android activity和service的互動介紹
android開發中,作為4大元件的service在開發中經常會使用到。很多時候,我們的activity和service之間需要進行相應的互動,activity需要呼叫service裡面的方法實現某些功能,service需要呼叫activity的方法,實現介面更新等的互動。
實現2者之間相互互動的主要方式是:service中有個類部類繼承Binder,然後提供一個公有方法,返回當前service的例項。 activity通過bindService來開啟一個service,service通過onBind方法,返回一個IBinder例項(我們建立的那個類部類例項),activity中通過onServiceConnected方法,獲取IBinder例項,然後再通過IBinder例項來獲取service例項,這樣,我們得到了service的例項,那麼我們的activity就可以隨心所欲的使用它裡面的各種方法來操作它了。
上面activity可以操作service了,我們還需要service能操作activity。
我覺得可以有3中方式:
1.直接把activity傳給service,service通過activity例項隨便操作activity
2.使用介面回撥方式,activity實現相應的介面,service通過介面進行回撥,比較靈活
3.使用廣播
使用廣播是比較常見的方式,我們就不具體講解了,下面我們介紹前面2中方法,具體看程式碼,用service更新seekbar。
我們的activity程式碼:
package com.hck.bindservice; 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.widget.SeekBar; import android.widget.Toast; import com.hck.bindservice.MyService.MyBuild; public class MainActivity extends Activity { private MyService myService; //我們自己的service private SeekBar pBar; //模擬service更新進度條 private ConnectionService connectionService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); pBar = (SeekBar) findViewById(R.id.seekbar); connectionService=new ConnectionService(); } public void startService(View view) { //繫結service bindService(new Intent(this,MyService.class), connectionService, 1); } /** * * @author Administrator *實現service介面,用於service繫結時候,回撥 */ class ConnectionService implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { myService=((MyBuild)service).getMyService(); //獲取Myservice物件 /** * 直接把當前物件傳給service,這樣service就可以隨心所欲的呼叫本activity的各種可用方法 */ myService.setMainActivity(MainActivity.this); //把當前物件傳遞給myservice /** * 使用一個介面來實現回撥,這樣比上面方法更加靈活,推薦 */ // myService.setOnProgressBarListener(new UpdateProgressListener() { // // @Override // public void updateBar(int size) { // updateBar(size); // } // }); } @Override public void onServiceDisconnected(ComponentName name) { } } /** * * @param size * 更新seekbar */ public void updateBar(int size) { pBar.setProgress(size); } /** * * @param view * 開始更新seekbar */ public void startBar(View view) { if (myService==null) { Toast.makeText(this, "請先開始service", Toast.LENGTH_LONG).show(); } else { myService.startUpdateProgress(); } } /** * * @param view * 停止更新seekbar */ public void stopBar(View view) { if (myService==null) { Toast.makeText(this, "更新沒有開始", Toast.LENGTH_LONG).show(); } else { myService.stopUpdateProgress(); } } /** * * @param view * 停止service */ public void stopService(View view) { myService=null; unbindService(connectionService); } @Override protected void onDestroy() { super.onDestroy(); try { unbindService(connectionService); } catch (Exception e) { } } }
重要程式碼是onServiceConnected回撥方法裡面
myService=((MyBuild)service).getMyService(); //獲取Myservice物件
獲取service物件後,我們想怎麼操作它都行了,比如上面的,把activity例項直接通過它的方法傳遞過去,便於
service呼叫activity的各種方法。或者,設定傳遞一個回撥介面物件過去,使用者回撥
service程式碼:
package com.hck.bindservice; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.util.Log; public class MyService extends Service{ private int size=0; private UpdateProgress updateProgress; private final long TIME=2000; private boolean isUpdate=true; private MainActivity activity; private UpdateProgressListener listener; @Override public IBinder onBind(Intent intent) { return new MyBuild(); } @Override public void onCreate() { super.onCreate(); updateProgress=new UpdateProgress(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } /** * * @author Administrator * 執行緒用來改變seekbar進度的大小 * */ class UpdateProgress implements Runnable { @Override public void run() { if (isUpdate) { size+=10; if (size>100) { size=0; } handler.sendEmptyMessage(0); } } } /** * 呼叫更新相應方法,更新進度條 */ Handler handler=new Handler() { public void handleMessage(android.os.Message msg) { /** * 直接呼叫activity物件裡面的方法 */ if (activity!=null) { activity.updateBar(size); } /** * 使用介面回撥 */ // if (listener!=null) { // listener.updateBar(size); // } handler.postDelayed(updateProgress, TIME); }; }; /** * 停止更新 */ public void stopUpdateProgress() { isUpdate=false; } /** * 開啟更新 */ public void startUpdateProgress() { if (!isUpdate) { handler.post(updateProgress); } isUpdate=true; } public void onDestroy() { isUpdate=false; }; /** * * @param activity * 初始化MainActivity物件 */ public void setMainActivity(MainActivity activity) { this.activity=activity; } /** * * @param listener * 初始化UpdateProgressListener物件 */ public void setOnProgressBarListener(UpdateProgressListener listener) { this.listener=listener; } /** * * @author Administrator * 使用類部類,返回當前service的例項,用於activity,呼叫service的各種方法 * */ class MyBuild extends Binder { public MyService getMyService() { return MyService.this; } } }
service裡面最重要的就是,最下面我們的MyBuild類部類了,通過它的getMyService方法,獲取service的例項
該類的例項實在onBind時候,我們返回給activity的。
介面:
package com.hck.bindservice;
public interface UpdateProgressListener {
public void updateBar(int size);
}
一個簡單介面,用於service回撥activity
上面是使用 bindService來啟動service的,那麼如果我們使用startService啟動service時候,上面的辦法就不行了。
因為onBind不會執行,我們獲取不到IBinder例項。這個時候,我們可以使用設計模式的觀察者模式來處理。
其它不清楚,還有什麼比較好的辦法沒有,我是沒有想到,有知道的朋友,請告知,謝謝
請把 private boolean isUpdate=true; 改為 private boolean isUpdate=false;