啓動的時候
Intent i= new Intent(MainActivity.this, MyService.class);
i.putExtra("data",editText.getText().toString());
startService(i);
在MyService裏面,因爲之前是startService,與之對應的是onStartCommand,所以在這裏面接受數據就好啦
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
data = intent.getStringExtra("data");
return super.onStartCommand(intent, flags, startId);
}
啓動一次服務,輸入文本,再次點擊啓動按鈕
10-16 22:07:03.825 10312-10312/com.jackie.courseservice V/jackie﹕ 開始服務
10-16 22:07:03.830 10312-10312/com.jackie.courseservice V/jackie﹕ Service created
10-16 22:07:03.830 10312-10312/com.jackie.courseservice V/jackie﹕ Command started
10-16 22:07:03.835 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...默認信息
10-16 22:07:05.835 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...
10-16 22:07:07.835 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...
10-16 22:07:09.835 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...
10-16 22:07:11.835 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...
10-16 22:07:13.835 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...
10-16 22:07:15.835 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...
10-16 22:07:17.840 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...
10-16 22:07:19.835 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...
10-16 22:07:20.630 10312-10312/com.jackie.courseservice V/jackie﹕ 開始服務
10-16 22:07:21.835 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...修改後再次啓動
10-16 22:07:23.840 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...修改後再次啓動
10-16 22:07:25.840 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...修改後再次啓動
10-16 22:07:27.840 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...修改後再次啓動
10-16 22:07:29.840 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...修改後再次啓動
10-16 22:07:31.840 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...修改後再次啓動
10-16 22:07:33.840 10312-10746/com.jackie.courseservice V/jackie﹕ 服務正在運行...修改後再次啓動
10-16 22:07:33.920 10312-10312/com.jackie.courseservice V/jackie﹕ 停止服務
10-16 22:07:33.925 10312-10312/com.jackie.courseservice V/jackie﹕ Service destroyed
除了使用Intent進行通信,也可以通過Service中的Binder來通信,這裏就需要將Activity和Service綁定(bind)在一起了
1、綁定服務
bindService(new Intent(MainActivity.this, MyService.class), this, BIND_AUTO_CREATE);
2、Service中設置一個成員變量data,來呈現兩邊數據的同步,並且,在Service創建後啓動一個線程,不停地打印這個data,觀察它的變化
public String data = "默認信息";
...
while (isRunning){
Log.v("jackie","服務正在運行..."+data);
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
3、關鍵:在Service裏面自己寫一個MyBinder,繼承Binder,裏面寫一個方法,用來設置成員變量data的值,並且,在onBind(Intent intent)
方法裏面返回這個自己定義的MyBinder
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
這個返回的自定義Binder就是Service和Activity溝通的橋樑
4、由於在爲MainActivity綁定Service的時候,是將MainActivity作爲一個ServiceConnection傳參,所以在這個必須重寫的方法裏,IBinder service
其實就是之前返回的MyBinder
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//這裏的binder用於接受onBinder返回的MyBinder
binder = (MyService.MyBinder) service;
}
5、通過這個binder,來在按鈕點擊事件裏改變Service中data的值
binder.setData(editText.getText().toString());
這樣就實現了在Activity裏面改變Service中的成員變量,關鍵就在於這個binder
10-16 21:57:25.795 27876-5582/com.jackie.courseservice V/jackie﹕ 服務正在運行...默認信息
10-16 21:57:27.795 27876-5582/com.jackie.courseservice V/jackie﹕ 服務正在運行...默認信息
10-16 21:57:29.800 27876-5582/com.jackie.courseservice V/jackie﹕ 服務正在運行...默認信息
10-16 21:57:31.795 27876-5582/com.jackie.courseservice V/jackie﹕ 服務正在運行...默認信息
10-16 21:57:31.960 27876-27876/com.jackie.courseservice W/IInputConnectionWrapper﹕ showStatusIcon on inactive InputConnection
10-16 21:57:33.800 27876-5582/com.jackie.courseservice V/jackie﹕ 服務正在運行...默認信息
10-16 21:57:35.540 27876-27876/com.jackie.courseservice V/jackie﹕ 同步數據
10-16 21:57:35.795 27876-5582/com.jackie.courseservice V/jackie﹕ 服務正在運行...我是綁定後修改的值
10-16 21:57:37.795 27876-5582/com.jackie.courseservice V/jackie﹕ 服務正在運行...我是綁定後修改的值
10-16 21:57:39.795 27876-5582/com.jackie.courseservice V/jackie﹕ 服務正在運行...我是綁定後修改的值
10-16 21:57:41.800 27876-5582/com.jackie.courseservice V/jackie﹕ 服務正在運行...我是綁定後修改的值
上面我們通過binder對Service裏面的數據進行了訪問操作,並且在LogCat裏面打印了這個數據,那麼如果不想看Log,直接把數據呈現在用戶可以交互到的Activity豈不是更加方便嗎,所以,這裏可以嘗試一下,如何偵聽被綁定的 Service 的內部狀態。
還是之前的打印線程,給一個count,每次加一
...
count++;
Log.v("jackie","服務正在運行..."+count);
...
在Activity裏面弄一個顯示區域顯示這個count
這個實現的關鍵就是:回調機制 Callback,Service裏面那個自己定義的MyBinder裏面寫一個獲取當前Service的方法
public MyService getService() {
return MyService.this;
}
然後定義一個接口Callback,並且該Service要有一個Callback類型的成員變量
private Callback callback;
public static interface Callback {
public void onDataChange(String data);
}
然後線程打印的時候,循環裏面有一句
count++;
if (callback != null) {
callback.onDataChange("服務正在運行..." + count);
}
在Activity中通過獲取Callback並重寫onDataChange方法就可以監聽線程裏面count的值了
由於其他線程是不可以改變UI線程的內容的,所以我們需要Handler來通知主線程改變TextView的內容
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (MyService.MyBinder) service;
binder.getService().setCallback(new MyService.Callback() {
@Override
public void onDataChange(String data) {
Message msg = new Message();
Bundle b = new Bundle();
b.putString("data", data);
msg.setData(b);
handler.sendMessage(msg);
}
});
// Log.v("jackie", "Service Connected");
}
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
tvShow.setText(msg.getData().getString("data"));
}
};
po主要說一句,Callback太特麼好用了!Activity可以爲自己給綁定的Service的Callback重寫自己需要的功能,然後MyService啓動之後它的Callback執行的就是重寫過的功能了。