編輯:關於Android編程
**寫作原因:跨進程通信的實現和理解是Android進階中重要的一環。下面博主分享IPC一些相關知識、操作及自己在學習IPC過程中的一些理解。
這一章是為下面的Messenger和AIDL的使用做准備,主要講解Android Service的綁定和Activity與本地Service之間通信相關知識。**
簡介
我們都知道啟動Service有兩種方式:startService()和bindService()。相比第一種方式,bindService()能夠更加靈活地實現與啟動端Activity的數據通信,第一種啟動方式啟動Activity與Service之間並沒有直接關聯,難以直接實現通信(當然了,使用BroadCast或者事件總線也是可以實現的)。而使用綁定的方式啟動Service則可以實現Service之間的通信。
下面就講述一下綁定Service實現本地通信的流程。

實例
結合圖片我們來模擬開啟一個後台執行更新功能為例來講解本地Service的綁定。
先分析一下該需求的場景:首先我們需要點擊Start按鈕開啟後台更新數據,後台將數據返回給Activity並在ProgressBar展示進度;當我們點擊Pause時後台暫停更新;點擊Stop按鈕時關閉後台。本例中也用到Service通過BroadCast向Activity傳遞數據。由於只是實例,對於線程操作一塊有一些bug,希望大家能夠幫忙指正。
Activity的布局如下:

Service 實現:
先看看Service的實現:
思路是這樣的:先繼承Binder類創建MyBinder類,把MyBinder看做Service與Activity通信的代理人,所以在MyBinder內部中寫好方法間接調用Service中的方法以供Activity去調用(如本例中callPauseUpgrade())。關於IBinder對象的獲取除了直接重寫後面還有兩種方式,這裡先不闡述了。在Service中我們開啟一個Thread,在這個Thread中模擬持續更新進度條直到isStop為False或者progress大於等於100時,然後將進度廣播出去,讓Activity接收到廣播進行進度條更新。Service中供Activity調用的方法實現暫停和停止Thread的功能,具體過程參照代碼。
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實現
下面是在客戶端實現與Service的通信代碼。主要思路是:先注冊廣播實現Service數據的返回;單擊Start按鈕時實現與Service的綁定,創建ServiceConnection對象實現ServiceConnection接口,分別回調綁定成功和失敗兩種情況下的邏輯。當成功時獲取MyBinder對象,並將設置的isBound值設為true;當失敗時將isBound設置為false。單擊Pause調用MyBinder對象的callPauseUpgrade()方法間接調用Service中的pauseUpgrade()方法。單擊Stop調用callStopUpgrade()方法並且解除綁定。注意解除綁定事件只能執行一次,否則程序會崩潰。
具體實現並不難,主要是認真理解上面的流程圖即可。
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;
}
};
}
總結:
這篇文章是為下面的Messenger和AIDL跨進程通信做准備的,實際上個人感覺真正開發時可以使用EventBus或者RxJava取代這種同進程各個組件通信的問題,有興趣的讀者可以自行嘗試。
超實用的Android手勢鎖制作實例教程
今天偶遇以github上gesturelock關於手勢鎖的一個例子(有興趣的去搜索下看看),於是下載下來研究,無奈基本沒有注釋,代碼上存在一些問題(當設置gravity=
Android實現Banner界面廣告圖片循環輪播(包括實現手動滑動循環)
前言:經常會看到有一些app的banner界面可以實現循環播放多個廣告圖片和手動滑動循環。本以為單純的ViewPager就可以實現這些功能。但是蛋疼的事情來了
App的打磨之路(上)
前言:俗話說磨刀不誤砍柴工,一個優秀的產品從一個不錯的點子直到用戶的手中,是需要一個團隊不遺余力協同合作不斷打磨出來的;同樣,一個好的App除正常的代碼編寫外,還需要經過
移植u-boot2012.04.1 -》2440 (二)norflash 識別
在上一篇文章中,我們實現了新建單板,時鐘 sdram 等一系列初始化工作,串口已經能正確輸出打印信息,但是有錯誤信息。現在,我們就來解決問題。搜索“Flash