由于项目需要,我们有时候需要在service中处理耗时操作,然后将结果发送给activity以更新状态。通常情况下,我们只需要在一个service与一个activity之间通信,通常这种情况下,我们使用最多的是通过回调接口。具体做法是在service中定义一个接口,在activity中实现该接口,并通过bindservice来传入。实现方式很简单,在此不再赘述。
当需要将service中的结果一次发送给多个activity时,我们又该如何实现呢?经过多个项目的积累,总结了三种实现的方式。分别是回调接口、广播接收者和观察者模式。
1.回调接口的方式,与单个service与单个activity通信类似,只是将service中的接口变为接口的集合,每个需要通信的activity都实现接口,然后在获取结果后,循环调用集合中的实现类,来与多个activity进行通信,代码如下:
Service类:
package com.example.servicecallback; import java.util.ArrayList; import java.util.List; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log; public class ContentService extends Service { //回调接口的集合 private List<Callback> list; @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return new LocalBinder(); } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); list = new ArrayList<Callback>(); } public final class LocalBinder extends Binder { public ContentService getService() { return ContentService.this; } } /** * 回调接口 * @author Ivan Xu * */ public interface Callback { public void getPerson(Person person); } /** * 往回调接口集合中添加一个实现类 * @param callback */ public void addCallback(Callback callback) { list.add(callback); } public void asyncSendPerson(final String name) { // 休息5秒,模拟异步任务 new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } handler.sendMessage(handler.obtainMessage(0, name)); } }).start(); } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub String name = (String) msg.obj; Log.i("ContentService", "---name-->" + name); Person person = new Person(); person.setName(name); Log.i("ContentService", "---list.size()-->" + list.size()); Log.i("ContentService", "---person-->" + person.toString()); //遍历集合,通知所有的实现类,即activity for (int i = 0; i < list.size(); i++) { list.get(i).getPerson(person); } } }; }
第一个activity:
package com.example.servicecallback; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; import com.example.servicecallback.ContentService.Callback; import com.example.servicecallback.ContentService.LocalBinder; public class MainActivity extends Activity implements Callback { private MyServiceConn conn; private ContentService service; private TextView mContent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); conn=new MyServiceConn(); bindService(new Intent(this, ContentService.class), conn, BIND_AUTO_CREATE); mContent = (TextView) findViewById(R.id.content); this.findViewById(R.id.button1).setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub startActivity(new Intent(MainActivity.this, OtherActivity.class)); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } public class MyServiceConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder binder) { service = ((LocalBinder) binder).getService(); //将当前activity添加到接口集合中 service.addCallback(MainActivity.this); } @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub service = null; } } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unbindService(conn); } /** * 获取回调的内容,更新UI */ @Override public void getPerson(Person person) { // TODO Auto-generated method stub mContent.setText(person.toString()); } }
第二个activity:
package com.example.servicecallback; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.example.servicecallback.ContentService.Callback; import com.example.servicecallback.ContentService.LocalBinder; import com.example.servicecallback.MainActivity.MyServiceConn; public class OtherActivity extends Activity implements Callback { private ContentService service; private TextView mContent; private Button mSubmit; private EditText mEditText; private ServiceConnection conn; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.other); mEditText = (EditText) findViewById(R.id.edittext); mSubmit = (Button) findViewById(R.id.button1); mContent = (TextView) findViewById(R.id.content); mSubmit.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub String name = mEditText.getText().toString(); service.asyncSendPerson(name); } }); conn=new MyServiceConn(); bindService(new Intent(OtherActivity.this, ContentService.class), conn, BIND_AUTO_CREATE); } public final class MyServiceConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder binder) { // TODO Auto-generated method stub service = ((LocalBinder) binder).getService(); //将当前activity添加到接口集合中 service.addCallback(OtherActivity.this); } @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub service = null; } } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unbindService(conn); } /** * 获取回调的内容,更新UI */ @Override public void getPerson(Person person) { // TODO Auto-generated method stub mContent.setText(person.toString()); } }
2.通过广播接收者,在service中执行完耗时操作后,将结果以广播的形式发送,在所有的activity中注册广播,接收到结果后更新UI,这种方式比较简单,也是笔者比较推荐的方式。因为耗时的操作结果不需要以handler的方式发送到主线程,可以直接在子线程中发送广播,接收者始终运行在主线程中。代码如下:
Service类:
package com.example.servicecallback; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; public class ContentService extends Service { @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return new LocalBinder(); } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); } public final class LocalBinder extends Binder { public ContentService getService() { return ContentService.this; } } public void asyncSendPerson(final String name) { // 休息5秒,模拟异步任务 new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } //可以在子线程中直接发送广播 sendContentBroadcast(name); } }).start(); } /** * 发送广播 * @param name */ protected void sendContentBroadcast(String name) { // TODO Auto-generated method stub Intent intent=new Intent(); intent.setAction("com.example.servicecallback.content"); intent.putExtra("name", name); sendBroadcast(intent); } }
第一个activity:
package com.example.servicecallback; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; public class MainActivity extends Activity { private MyServiceConn conn; private TextView mContent; private ContentReceiver mReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); conn = new MyServiceConn(); bindService(new Intent(this, ContentService.class), conn, BIND_AUTO_CREATE); mContent = (TextView) findViewById(R.id.content); this.findViewById(R.id.button1).setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub startActivity(new Intent(MainActivity.this, OtherActivity.class)); } }); doRegisterReceiver(); } /** * 注册广播接收者 */ private void doRegisterReceiver() { mReceiver=new ContentReceiver(); IntentFilter filter = new IntentFilter( "com.example.servicecallback.content"); registerReceiver(mReceiver, filter); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } public class MyServiceConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder binder) { // service = ((LocalBinder) binder).getService(); } @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub // service = null; } } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unbindService(conn); if (mReceiver!=null) { unregisterReceiver(mReceiver); } } public class ContentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String name = intent.getStringExtra("name"); Person person = new Person(); person.setName(name); mContent.setText(person.toString()); } } }
另一个activity:
package com.example.servicecallback; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.example.servicecallback.ContentService.LocalBinder; public class OtherActivity extends Activity { private ContentService service; private TextView mContent; private Button mSubmit; private EditText mEditText; private ServiceConnection conn; private ContentReceiver mReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.other); mEditText = (EditText) findViewById(R.id.edittext); mSubmit = (Button) findViewById(R.id.button1); mContent = (TextView) findViewById(R.id.content); mSubmit.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String name = mEditText.getText().toString(); service.asyncSendPerson(name); } }); conn=new MyServiceConn(); bindService(new Intent(OtherActivity.this, ContentService.class), conn, BIND_AUTO_CREATE); doRegisterReceiver(); } private void doRegisterReceiver() { mReceiver=new ContentReceiver(); IntentFilter filter = new IntentFilter( "com.example.servicecallback.content"); registerReceiver(mReceiver, filter); } public final class MyServiceConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder binder) { service = ((LocalBinder) binder).getService(); } @Override public void onServiceDisconnected(ComponentName name) { service = null; } } @Override protected void onDestroy() { super.onDestroy(); unbindService(conn); if (mReceiver!=null) { unregisterReceiver(mReceiver); } } public class ContentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String name = intent.getStringExtra("name"); Person person = new Person(); person.setName(name); mContent.setText(person.toString()); } } }
3.使用观察者模式,service为被观察者,所以的activity为观察者,当service中的内容发生改变时,通知所有的activity来更新,代码如下:
Service类:
package com.example.servicecallback; import java.util.Observable; import java.util.Observer; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Message; public class ContentService extends Service { //被观察者 private MyObservable mObservable; @Override public IBinder onBind(Intent arg0) { return new LocalBinder(); } @Override public void onCreate() { super.onCreate(); mObservable = new MyObservable(); } public final class LocalBinder extends Binder { public ContentService getService() { return ContentService.this; } } public void asyncSendPerson(final String name) { // 休息5秒,模拟异步任务 new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } handler.sendMessage(handler.obtainMessage(0, name)); } }).start(); } /** * 添加观察者 * @param observer */ public void addObserver(Observer observer) { mObservable.addObserver(observer); } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { String name = (String) msg.obj; Person person = new Person(); person.setName(name); //通知更新 mObservable.notifyChanged(person); } }; public class MyObservable extends Observable { public void notifyChanged(Object object) { this.setChanged(); this.notifyObservers(object); } } }
第一个activity:
package com.example.servicecallback; import java.util.Observable; import java.util.Observer; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; import com.example.servicecallback.ContentService.LocalBinder; public class MainActivity extends Activity implements Observer { private MyServiceConn conn; private TextView mContent; private ContentService mService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); conn = new MyServiceConn(); bindService(new Intent(this, ContentService.class), conn, BIND_AUTO_CREATE); mContent = (TextView) findViewById(R.id.content); this.findViewById(R.id.button1).setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this, OtherActivity.class)); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } public class MyServiceConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder binder) { mService = ((LocalBinder) binder).getService(); //将当前activity添加为观察者 mService.addObserver(MainActivity.this); } @Override public void onServiceDisconnected(ComponentName name) { mService = null; } } @Override protected void onDestroy() { super.onDestroy(); unbindService(conn); } //更新UI @Override public void update(Observable observable, Object data) { Person person = (Person) data; mContent.setText(person.toString()); } }
第二个activity:
package com.example.servicecallback; import java.util.Observable; import java.util.Observer; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.example.servicecallback.ContentService.LocalBinder; public class OtherActivity extends Activity implements Observer { private ContentService service; private TextView mContent; private Button mSubmit; private EditText mEditText; private ServiceConnection conn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.other); mEditText = (EditText) findViewById(R.id.edittext); mSubmit = (Button) findViewById(R.id.button1); mContent = (TextView) findViewById(R.id.content); mSubmit.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String name = mEditText.getText().toString(); service.asyncSendPerson(name); } }); conn = new MyServiceConn(); bindService(new Intent(OtherActivity.this, ContentService.class), conn, BIND_AUTO_CREATE); } public final class MyServiceConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder binder) { service = ((LocalBinder) binder).getService(); //将当前activity添加为观察者 service.addObserver(OtherActivity.this); } @Override public void onServiceDisconnected(ComponentName name) { service = null; } } @Override protected void onDestroy() { super.onDestroy(); unbindService(conn); } //更新UI @Override public void update(Observable observable, Object data) { // TODO Auto-generated method stub Person person=(Person) data; mContent.setText(person.toString()); } }
附上其他相关代码,三种方式都一样:
Person类:
package com.example.servicecallback; public class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person [name=" + name + "]"; } }
MainActiivty的布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <Button android:id="@+id/button1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="next" /> <TextView android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello_world" /> </LinearLayout>
OtherActivity的布局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:id="@+id/edittext" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/button1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="submit" /> <TextView android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="content" /> </LinearLayout>
由于笔者的水平有限,如有错漏,请各位留言指正,感激不尽!
以上虽有借鉴别人的思想,但是源代码均为原创。请尊重笔者的劳动成果。如果转载,请注明出处,谢谢!
全文完