1. 程式人生 > >Android中Service與Activity的通訊---回撥介面方式

Android中Service與Activity的通訊---回撥介面方式

最近在技術交流群中有人問到:要實現service與activity的高強度通訊用什麼方法?

群友回答的是用handler,但面試官好像不太滿意,後來本人查找了下資料,得到個人的結論:service與activity之前的通訊方式有很多,回撥介面方式、觀察者模式、廣播、還有handler等,方法有很多,但要高強度地通訊,個人覺得還是用回撥介面的方式比較妥當(雖然本人開始也是用的傳入的handler。。。哈哈,用handler的話,如果涉及到service要向多個activity傳送資料就變得麻煩了)。所以在這裡記錄下回撥介面的方式進行通訊:

service部分:

註冊

<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="false"
    android:launchMode="singleTop" >
    <intent-filter>
         <action android:name="MyService.START_SERVICE" />

         <category android:name="android.intent.category.DEFAULT" />
     </intent-filter>
</service>


public class MyService extends Service {
    private Callback callback = null;
      Thread readthread;
    Boolean RUN_THREAD = false;
    @Override
    public IBinder onBind(Intent intent) {
Utils.log(1,"MyService", "onBind");
return mybinder;//注意這裡返回值不能為null  否則在activity中繫結時不會觸發onServiceConnected()
    }     private MyBinder mybinder = new MyBinder(); public class MyBinder extends Binder{     public MyService getService(){          return MyService.this;        }     }     public void setCallback(Callback callback){//注意這裡以單個回撥為例  如果是向多個activity傳送資料 可以定義一個回撥集合 在此處進行集合的新增     this.callback = callback; }     @Override     public void onCreate() {         Utils.log(1,"MyService", "onCreate");         super.onCreate();     }     @Override     public int onStartCommand(Intent intent, int flags, int startId) {      Utils.log(1, "MyService", "onStartCommand"); if(!RUN_THREAD) {             RUN_THREAD = true;             readthread = new Thread(MyRunnable);//啟動一個執行緒             readthread.start();         }         Intent LaunchIntent = intent; //new Intent();         LaunchIntent.addCategory(Intent.CATEGORY_LAUNCHER);         //設定啟動上下文         LaunchIntent.setClass(MyService.this, MainActivity.class);         LaunchIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);         Notification.Builder builder = new Notification.Builder(this);         PendingIntent contentIntent = PendingIntent.getActivity(this, 0, LaunchIntent, 0);         builder.setContentIntent(contentIntent);         builder.setSmallIcon(appInfo.icon);         builder.setContentTitle(appInfo.loadLabel(pm).toString());         builder.setContentText("竭誠為您服務");         Notification notification = builder.build();         startForeground(R.drawable.imgflow_3, notification); // 在通知欄顯示一個常駐通知 提高service的優先順序(貌似可以到2級優先順序)         return START_STICKY;//異常結束自啟動     } private Runnable MyRunnable = new Runnable() {         public void run() {            while (RUN_THREAD) { try {              Thread.sleep(1000);              if(callback != null){                  callback.doback(null);//傳送資料到activity 資料可以為jason資料等 自己定義              }              } catch (Exception e) {                  e.printStackTrace();              }                 }              RUN_THREAD = false;             } catch (Exception e) {                 e.printStackTrace();            }         }     };     @Override     public void onDestroy() {     Utils.log(1, "MyService", "onDestroy()");         super.onDestroy();     }     /**      * 定義回撥介面      */     public interface Callback{     public void doback(JSONObject data);     } }

activity部分:
public class MainActivity extends Activity implements OnClickListener,Callback{//實現下在service中定義的回撥介面
	Button button1,button2,button3;
	String TAG="MainActivity";
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		button1 = (Button) findViewById(R.id.button1);
		button1.setOnClickListener(this);
		button2 = (Button) findViewById(R.id.button2);
		button2.setOnClickListener(this);
		button3 = (Button) findViewById(R.id.button3);
		button3.setOnClickListener(this);
        
	}
	/* 繫結service監聽*/  
    ServiceConnection sconnection = new ServiceConnection() {  
        /*當繫結時執行*/  
        public void onServiceConnected(ComponentName name, IBinder service) {  //service的onbind()中返回值不為null才會觸發
        	 Utils.log(1, TAG, "onServiceConnected");
        	 MyService mMyService = ((MyService.MyBinder)service).getService();//得到該service例項
        	 mMyService.setCallback(MainActivity.this);//把回撥物件傳送給service
        }  
        /*當異常結束service時執行,但呼叫unbindService()時不會觸發改方法 測試的話可以在bind時使用Context.BIND_NOT_FOREGROUND  呼叫stopservice()可觸發*/  
        public void onServiceDisconnected(ComponentName name) {  
            Utils.log(1, TAG, "onServiceDisconnected");
        }  
    };  
	@Override
	protected void onResume() {
		super.onResume();
	}
	@Override
	protected void onDestroy() {
		Utils.log(1, TAG, "onDestroy()");
        unbindService(sconnection);//解綁下service否則  退出會報錯
		super.onDestroy();
	}
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button1:
			Toast.makeText(this, "繫結service", 0).show();
			Intent bindIntent = new Intent(MainActivity.this, MyService.class); 
			bindService(bindIntent, sconnection, Context.BIND_AUTO_CREATE); 
			break;
		case R.id.button2:
			Toast.makeText(this, "開啟service...", 0).show();//本例中是app啟動時自動啟動service
			Intent i  = new Intent();  
	        i.setClass(MainActivity.this, MyService.class);  
	        startService(i);  
			break;
		case R.id.button3:
			Toast.makeText(this, "停止service...", 0).show();
			Intent i  = new Intent();  
	        i.setClass(MainActivity.this, MyService.class);  
	        stopService(i);
			break;
		default:
			break;
		}
		
	}
	public Handler handler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
			Toast.makeText(MainActivity.this, "refreshing...", 0).show();
			super.handleMessage(msg);
		}
	};
	@Override
	public void doback(JSONObject data) { //實現的回撥方法  收到service迴應後在裡面做想要做的工作
		handler.sendEmptyMessage(0);
	}
}
這個樣子就能實現了,當然傳入回撥處也可以傳入handler物件。。。。