Android中Service與Activity的通訊---回撥介面方式
阿新 • • 發佈:2019-01-29
最近在技術交流群中有人問到:要實現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物件。。。。