寫(xiě)作原因:跨進(jìn)程通信的實(shí)現(xiàn)和理解是Android進(jìn)階中重要的一環(huán)。下面博主分享IPC一些相關(guān)知識(shí)、操作及自己在學(xué)習(xí)IPC過(guò)程中的一些理解回怜。
這一章是為下面的Messenger和AIDL的使用做準(zhǔn)備仓洼,主要講解Android Service的綁定和Activity與本地Service之間通信相關(guān)知識(shí)。有興趣的可以關(guān)注博主的博客或者之后的文章扇单。
簡(jiǎn)介
我們都知道啟動(dòng)Service有兩種方式:startService()和bindService()。相比第一種方式奠旺,bindService()能夠更加靈活地實(shí)現(xiàn)與啟動(dòng)端Activity的數(shù)據(jù)通信蜘澜,第一種啟動(dòng)方式啟動(dòng)Activity與Service之間并沒(méi)有直接關(guān)聯(lián),難以直接實(shí)現(xiàn)通信(當(dāng)然了响疚,使用BroadCast或者事件總線(xiàn)也是可以實(shí)現(xiàn)的)鄙信。而使用綁定的方式啟動(dòng)Service則可以實(shí)現(xiàn)Service之間的通信。下面就講述一下綁定Service實(shí)現(xiàn)本地通信的流程忿晕。
以Activity調(diào)用Service中的方法為例装诡,具體流程參考博主繪制的流程圖:
實(shí)例
結(jié)合圖片我們來(lái)模擬開(kāi)啟一個(gè)后臺(tái)執(zhí)行更新功能為例來(lái)講解本地Service的綁定。
先分析一下該需求的場(chǎng)景:首先我們需要點(diǎn)擊Start按鈕開(kāi)啟后臺(tái)更新數(shù)據(jù)杏糙,后臺(tái)將數(shù)據(jù)返回給Activity并在ProgressBar展示進(jìn)度慎王;當(dāng)我們點(diǎn)擊Pause時(shí)后臺(tái)暫停更新;點(diǎn)擊Stop按鈕時(shí)關(guān)閉后臺(tái)宏侍。本例中也用到Service通過(guò)BroadCast向Activity傳遞數(shù)據(jù)赖淤。由于只是實(shí)例,對(duì)于線(xiàn)程操作一塊有一些bug谅河,希望大家能夠幫忙指正咱旱。
Activity的布局如下:
Service實(shí)現(xiàn)
先看看Service的實(shí)現(xiàn):
思路是這樣的:先繼承Binder類(lèi)創(chuàng)建MyBinder類(lèi)确丢,把MyBinder看做Service與Activity通信的代理人,所以在MyBinder內(nèi)部中寫(xiě)好方法間接調(diào)用Service中的方法以供Activity去調(diào)用(如本例中callPauseUpgrade())吐限。關(guān)于IBinder對(duì)象的獲取除了直接重寫(xiě)后面還有兩種方式鲜侥,這里先不闡述了。在Service中我們開(kāi)啟一個(gè)Thread诸典,在這個(gè)Thread中模擬持續(xù)更新進(jìn)度條直到isStop為False或者progress大于等于100時(shí)描函,然后將進(jìn)度廣播出去,讓Activity接收到廣播進(jìn)行進(jìn)度條更新狐粱。Service中供Activity調(diào)用的方法實(shí)現(xiàn)暫停和停止Thread的功能舀寓,具體過(guò)程參照代碼。
public class UpgradeService extends Service {
private Thread thread;
private Intent intent;
private int progress;
private Boolean isStop;
public class MyBinder extends Binder{
public void callPauseUpgrade(){
pauseUpgrade();
}
public void callStopUpgrade() {
stopUpgrade();
}
}
private void stopUpgrade() {
progress = 0;
isStop = false;
intent.putExtra("progress",progress);
sendBroadcast(intent);
}
@Override
public void onCreate() {
super.onCreate();
progress = 0;
isStop = true;
intent = new Intent();
thread = new Thread(new Runnable() {
@Override
public void run() {
while(isStop){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
progress = progress +5;
intent.putExtra("progress",progress);
intent.setAction("UPGRADE_ACTION");
sendBroadcast(intent);
if(progress>=100) break;
}
}
});
thread.start();
}
private void pauseUpgrade() {
//TODO:Pause the upgrade
Toast.makeText(getApplicationContext(),"暫停",Toast.LENGTH_SHORT).show();
isStop = false;
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
}
Activity實(shí)現(xiàn)
下面是在客戶(hù)端實(shí)現(xiàn)與Service的通信代碼肌蜻。主要思路是:先注冊(cè)廣播實(shí)現(xiàn)Service數(shù)據(jù)的返回互墓;單擊Start按鈕時(shí)實(shí)現(xiàn)與Service的綁定,創(chuàng)建ServiceConnection對(duì)象實(shí)現(xiàn)ServiceConnection接口蒋搜,分別回調(diào)綁定成功和失敗兩種情況下的邏輯篡撵。當(dāng)成功時(shí)獲取MyBinder對(duì)象,并將設(shè)置的isBound值設(shè)為true豆挽;當(dāng)失敗時(shí)將isBound設(shè)置為false育谬。單擊Pause調(diào)用MyBinder對(duì)象的callPauseUpgrade()方法間接調(diào)用Service中的pauseUpgrade()方法。單擊Stop調(diào)用callStopUpgrade()方法并且解除綁定祷杈。注意解除綁定事件只能執(zhí)行一次斑司,否則程序會(huì)崩潰。具體實(shí)現(xiàn)并不難但汞,主要是認(rèn)真理解上面的流程圖即可。
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button mBtStart;
private Button mBtStop;
private Button mBtPause;
private ProgressBar mPbProgress;
private UpgradeService.MyBinder myBinder;
private boolean isBound;
private UpgradeReceiver upgradeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("UPGRADE_ACTION");
upgradeReceiver = new UpgradeReceiver();
registerReceiver(upgradeReceiver,intentFilter);
initView();
initEvent();
}
public class UpgradeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
mPbProgress.setProgress(intent.getIntExtra("progress",0));
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(upgradeReceiver);
}
private void initEvent() {
mBtPause.setOnClickListener(this);
mBtStart.setOnClickListener(this);
mBtStop.setOnClickListener(this);
}
private void initView() {
mBtPause = (Button) findViewById(R.id.bt_pause);
mBtStart = (Button) findViewById(R.id.bt_start);
mBtStop = (Button) findViewById(R.id.bt_stop);
mPbProgress = (ProgressBar) findViewById(R.id.pb_progress);
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.bt_pause:
if(isBound&&myBinder!=null){
myBinder.callPauseUpgrade();
}
break;
case R.id.bt_start:
bindService(new Intent(MainActivity.this,UpgradeService.class),conn,BIND_AUTO_CREATE);
break;
case R.id.bt_stop:
if(isBound) {
myBinder.callStopUpgrade();
unbindService(conn);
isBound = false;
}
break;
}
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if(service != null){
myBinder = (UpgradeService.MyBinder) service;
isBound = true;
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
}
總結(jié)
這篇文章是為下面的Messenger和AIDL跨進(jìn)程通信做準(zhǔn)備的互站,實(shí)際上個(gè)人感覺(jué)真正開(kāi)發(fā)時(shí)可以使用EventBus或者RxJava取代這種同進(jìn)程各個(gè)組件通信的問(wèn)題私蕾,有興趣的讀者可以自行嘗試。