Activity呼叫Service裡的方法
Service是不能被例項化的,那麼我們如果想呼叫裡邊的方法,該怎樣進行呢?
首先看一個Serviece類
Activity的程式碼部分如下:由於這些方法都是按鈕的點選事件,所以傳入引數View(例如在XML檔案中android:click = "start")public class SingService extends Service{ @Override public IBinder onBind(Intent intent) { // TODO 自動生成的方法存根 return null; } @Override public void onCreate() { // TODO 自動生成的方法存根 super.onCreate(); System.out.print("服務啟動,開始唱歌了"); } @Override public void onDestroy() { // TODO 自動生成的方法存根 super.onDestroy(); System.out.print("服務結束,停止唱歌了"); } //自定義的方法 public void ChangeSong(String songName){ Toast.makeText(getApplicationContext(), "切換歌曲", 0).show(); } }
那麼我們怎樣才能呼叫Service裡的方法呢?可以採用代理人模式,不直接呼叫,而是通過與之有關係的代理人來實現。public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } /* * 開啟服務 * */ public void start(View view){ Intent intent = new Intent(this, SingService.class); //採用api建立服務,服務物件是被系統(Android 框架)new 出來的 startService(intent); } /* * 停止服務 * */ public void stop(View view){ Intent intent = new Intent(this, SingService.class); stopService(intent); } /* * 呼叫服務裡的方法,換首歌,由於Service是系統建立的,我們不能NEW物件呼叫方法 * */ public void change(View view){ //由於系統框架在建立服務的時候,會建立與之對應的上下文,下面的程式碼是錯誤的 // SingService service = new SingService(); // service.ChangeSong("月亮之上"); } }
我們啟動Service,除了StartService之外,還可以通過bindService的方法,得到代理人物件。
首先看Service類的寫法有什麼不一樣
Activity裡的寫法:public class SingService extends Service{ @Override <strong>//步驟二:服務在成功繫結的時候會調動onBind方法,返回一個IBinder物件</strong> <span style="font-size:12px;"> </span><span style="font-size:14px;"><span style="color:#ff0000;">public IBinder onBind(Intent intent) { // 當服務被成功繫結的時候,系統自動呼叫該方法 System.out.print("服務成功被繫結"); //返回自定義的代理人物件,這個很關鍵 return new MyBinder(); }</span> <span style="color:#ff0000;"> public class MyBinder extends Binder{ //簡介的利用代理人,呼叫了唱歌的方法 <strong>public void CallChangeSong(String name){ ChangeSong(name);</strong> } }</span> </span> @Override public void onCreate() { // TODO 自動生成的方法存根 super.onCreate(); System.out.print("服務啟動,開始唱歌了"); } @Override public void onDestroy() { // TODO 自動生成的方法存根 super.onDestroy(); System.out.print("服務結束,停止唱歌了"); } //自定義的方法 public void ChangeSong(String songName){ Toast.makeText(getApplicationContext(), "切換歌曲", 0).show(); } }
public class MainActivity extends Activity {
<strong>//步驟四:在Activity裡面得到服務IBinder物件的引用</strong>
private SingService.MyBinder myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void change(View view){
<strong>//步驟五:利用iBinder物件間接的呼叫了服務裡的方法</strong>
myBinder.CallChangeSong("月亮之上");
}
<strong>//步驟一:採用繫結服務的方式開啟服務</strong>
public void bind(View view){
Intent intent = new Intent(this, SingService.class);
bindService(intent, new MyConn(), BIND_AUTO_CREATE);
}
//建立一個內部類,代理人
private class MyConn implements ServiceConnection{
//在服務被成功繫結時候呼叫的方法
@Override
public void onServiceConnected(ComponentName name,
IBinder service) {
System.out.println("把代理人返回來了");
<strong>//第三步:服務返回的IBinder物件會被傳遞給myConn的回撥方法</strong>
myBinder = (MyBinder) service;
}
//在服務失去繫結時候呼叫的方法,正常情況下不會被呼叫,只有在程序異常終止時候才會呼叫。
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO 自動生成的方法存根
}
}
}
整個的流程如下:
但是在實際的開發中,我們不可能這麼直接去寫,把代理人寫在Service裡,那肯定是不行的,而且不能直接定義成public讓外部去訪問,我們通常是建立一個介面,通過暴露介面的方式來實現。
public interface Iservice {
public void callChangeSong(String name);
}
單獨寫一個介面,統一規範作用
在Service中,把MyBinder類去實現這個介面
private class MyBinder extends Binder implements Iservice{
@Override
public void callChangeSong(String name) {
// TODO 自動生成的方法存根
ChangeSong(name);
}
}
在Activity中做如下修改:
private Iservice myBinder;
myBinder = (Iservice) service;
如果我們沒有繫結服務,那麼Activity退出了,服務還在,但是如果綁定了,那麼Activity退出,服務跟著也馬上退出。
服務的混合開啟:
需求:既要想保證服務長期在後臺執行,又想去呼叫服務裡的方法,怎麼辦呢?
技巧:1、先開啟服務——這樣就可以保證服務長期執行(不繫結) 2、繫結服務——這樣就可以呼叫裡邊的方法了
服務只會被建立一次,也就是當我們如果先開啟了服務,會執行OnCreate方法,當再繫結服務的時候,onCreate方法不會再執行,直接執行onBind方法。
注意事項:
當我們繫結服務了之後,如果直接退出,會報出異常的錯誤,為什麼呢?因為我們綁定了服務,直接退出會顯示異常,怎樣解決呢?也就是在我們退出的時候,要把繫結的服務解除掉。
定義一個方法:
//解除繫結服務的方法
public void unBind(View view){
unbindService(conn);
}
這時候在Service中會呼叫onUnbind方法,如下:
public boolean onUnbind(Intent intent) {
// TODO 自動生成的方法存根
System.out.println("解除繫結");
return super.onUnbind(intent);
}
服務一旦被繫結,通過StopService方法是不能停止掉的,只能通過解綁之後,才能停止,服務先解綁,然後直接onDestory了,所以綁定了服務,記得要解綁。如果點選多次繫結服務,只會呼叫一次onBind方法,但是如果呼叫多次解綁方法,程式第一次會呼叫解綁,後邊就會報錯。
為了防止忘記解綁服務,我們通常在Activity的onDestory中呼叫解綁服務的方法,這樣就能保證應用程式在退出的時候,自動把程式解綁掉,但是如果程式設計師比較勤奮,之前已經解綁過了,那如果再解綁就會報錯,怎麼辦呢?通常情況下我們可以用try_catch方法包圍解綁,這樣就比較安全了。