由于項(xiàng)目需要,我們有時(shí)候需要在service中處理耗時(shí)操作终娃,然后將結(jié)果發(fā)送給activity以更新狀態(tài)服傍。通常情況下,我們只需要在一個(gè)service與一個(gè)activity之間通信节猿,通常這種情況下票从,我們使用最多的是通過(guò)回調(diào)接口。具體做法是在service中定義一個(gè)接口滨嘱,在activity中實(shí)現(xiàn)該接口峰鄙,并通過(guò)bindservice來(lái)傳入。實(shí)現(xiàn)方式很簡(jiǎn)單太雨,在此不再贅述吟榴。
當(dāng)需要將service中的結(jié)果一次發(fā)送給多個(gè)activity時(shí),我們又該如何實(shí)現(xiàn)呢囊扳?經(jīng)過(guò)多個(gè)項(xiàng)目的積累吩翻,總結(jié)了三種實(shí)現(xiàn)的方式兜看。分別是回調(diào)接口、廣播接收者和觀察者模式狭瞎。
1. 回調(diào)接口的方式
與單個(gè)service與單個(gè)activity通信類似细移,只是將service中的接口變?yōu)榻涌诘募希總€(gè)需要通信的activity都實(shí)現(xiàn)接口熊锭,然后在獲取結(jié)果后弧轧,循環(huán)調(diào)用集合中的實(shí)現(xiàn)類,來(lái)與多個(gè)activity進(jìn)行通信碗殷,代碼如下:
1.1 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 {
//回調(diào)接口的集合
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;
}
}
/**
* 回調(diào)接口
* @author Ivan Xu
*
*/
public interface Callback {
public void getPerson(Person person);
}
/**
* 往回調(diào)接口集合中添加一個(gè)實(shí)現(xiàn)類
* @param callback
*/
public void addCallback(Callback callback) {
list.add(callback);
}
public void asyncSendPerson(final String name) {
// 休息5秒精绎,模擬異步任務(wù)
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());
//遍歷集合,通知所有的實(shí)現(xiàn)類亿扁,即activity
for (int i = 0; i < list.size(); i++) {
list.get(i).getPerson(person);
}
}
};
}
1.2 第一個(gè)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();
//將當(dāng)前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);
}
/**
* 獲取回調(diào)的內(nèi)容捺典,更新UI
*/
@Override
public void getPerson(Person person) {
// TODO Auto-generated method stub
mContent.setText(person.toString());
}
}
1.3 第二個(gè)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();
//將當(dāng)前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);
}
/**
* 獲取回調(diào)的內(nèi)容,更新UI
*/
@Override
public void getPerson(Person person) {
// TODO Auto-generated method stub
mContent.setText(person.toString());
}
}
2 通過(guò)廣播(==推薦==)
在service中執(zhí)行完耗時(shí)操作后从祝,將結(jié)果以廣播的形式發(fā)送襟己,在所有的activity中注冊(cè)廣播,接收到結(jié)果后更新UI牍陌,這種方式比較簡(jiǎn)單擎浴,也是筆者比較推薦的方式。因?yàn)楹臅r(shí)的操作結(jié)果不需要以handler的方式發(fā)送到主線程毒涧,可以直接在子線程中發(fā)送廣播贮预,接收者始終運(yùn)行在主線程中。代碼如下:
2.1 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秒契讲,模擬異步任務(wù)
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//可以在子線程中直接發(fā)送廣播
sendContentBroadcast(name);
}
}).start();
}
/**
* 發(fā)送廣播
* @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);
}
}
2.2 第一個(gè)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();
}
/**
* 注冊(cè)廣播接收者
*/
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());
}
}
}
2.3 第二個(gè)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為觀察者,當(dāng)service中的內(nèi)容發(fā)生改變時(shí)捡偏,通知所有的activity來(lái)更新唤冈,代碼如下:
3.1 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秒,模擬異步任務(wù)
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);
}
}
}
3.2 第一個(gè)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();
//將當(dāng)前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());
}
}
3.2 第二個(gè)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();
//將當(dāng)前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());
}
}
附上其他相關(guān)代碼银伟,三種方式都一樣:
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>