Activity與Service通訊的方式有三種:

jia635發表於2014-08-27

在部落格園看到的,看著挺不錯的,借來分享下

</pre><p></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-size:14px; line-height:25px; font-family:Helvetica,Tahoma,Arial,sans-serif"><span style="margin: 0px; padding: 0px;"><span style="margin:0px; padding:0px">繼承Binder類</span></span></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-size:14px; line-height:25px; font-family:Helvetica,Tahoma,Arial,sans-serif"><span style="margin:0px; padding:0px; font-size:14px">  這個方式只有當你的Acitivity和Service處於同一個Application和程式時,才可以用,比如你後臺有一個播放背景音樂的Service,這時就可以用這種方式來進行通訊。</span></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-size:14px; line-height:25px; font-family:Helvetica,Tahoma,Arial,sans-serif"><span style="margin:0px; padding:0px; font-size:14px">用例子來說明其使用方法:</span></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-size:14px; line-height:25px; font-family:Helvetica,Tahoma,Arial,sans-serif"><span style="margin:0px; padding:0px; font-size:14px">  1. 來看Service的寫法:</span></p><pre code_snippet_id="459570" snippet_file_name="blog_20140827_2_3516924" name="code" class="java">public class LocalService extends Service {  
    // 例項化自定義的Binder類  
    private final IBinder mBinder = new LocalBinder();  
    // 隨機數的生成器  
    private final Random mGenerator = new Random();  
  
    /** 
     * 自定義的Binder類,這個是一個內部類,所以可以知道其外圍類的物件,通過這個類,讓Activity知道其Service的物件 
     */  
    public class LocalBinder extends Binder {  
        LocalService getService() {  
            // 返回Activity所關聯的Service物件,這樣在Activity裡,就可呼叫Service裡的一些公用方法和公用屬性  
            return LocalService.this;  
        }  
    }  
  
    @Override  
    public IBinder onBind(Intent intent) {  
        return mBinder;  
    }  
  
    /** public方法,Activity可以進行呼叫 */  
    public int getRandomNumber() {  
      return mGenerator.nextInt(100);  
    }  
}  

在Service裡定義一個內部類,Binder的子類,通過這個類,把Service的物件傳給Activity,這樣Activity就可以呼叫Service裡的公用方法和公用屬性了,但這種方式,一定要在同一個程式和同一個Application裡。
   2. 再看相應Activity的程式碼:

public class BindingActivity extends Activity {  
    LocalService mService;  
    boolean mBound = false;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
    }  
  
    @Override  
    protected void onStart() {  
        super.onStart();  
        // 繫結Service,繫結後就會呼叫mConnetion裡的onServiceConnected方法  
        Intent intent = new Intent(this, LocalService.class);  
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  
    }  
  
    @Override  
    protected void onStop() {  
        super.onStop();  
        // 解綁Service,這樣可以節約記憶體  
        if (mBound) {  
            unbindService(mConnection);  
            mBound = false;  
        }  
    }  
  
    /** 使用者點選button,就讀取Service裡的隨機數 */  
    public void onButtonClick(View v) {  
        if (mBound) {  
            // 用Service的物件,去讀取隨機數  
            int num = mService.getRandomNumber();  
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();  
        }  
    }  
  
    /** 定交ServiceConnection,用於繫結Service的*/  
    private ServiceConnection mConnection = new ServiceConnection() {  
  
        @Override  
        public void onServiceConnected(ComponentName className,  
                IBinder service) {  
            // 已經繫結了LocalService,強轉IBinder物件,呼叫方法得到LocalService物件  
            LocalBinder binder = (LocalBinder) service;  
            mService = binder.getService();  
            mBound = true;  
        }  
  
        @Override  
        public void onServiceDisconnected(ComponentName arg0) {  
            mBound = false;  
        }  
    };  
}  

這裡就是通過IBinder來得到LocalService物件,再去呼叫其Public方法。

使用Messenger

   上面的方法只能在同一個程式裡才能用,如果要與另外一個程式的Service進行通訊,則可以用Messenger。

    其實實現IPC的方式,還有AIDL,但推薦使用Messenger,有兩點好處:

      1. 使用Messenger方式比使用AIDL的方式,實現起來要簡單很多

      2. 使用Messenger時,所有從Activity傳過來的訊息都會排在一個佇列裡,不會同時請求Service,所以是執行緒安全的。如果你的程式就是要多執行緒去訪問Service,就可以用AIDL,不然最好使用Messenger的方式。

  不過,其實Messenger底層用的就是AIDL實現的,看一下實現方式,先看Service的程式碼:

public class MessengerService extends Service {  
    /** 用於Handler裡的訊息型別 */  
    static final int MSG_SAY_HELLO = 1;  
  
    /** 
     * 在Service處理Activity傳過來訊息的Handler 
     */  
    class IncomingHandler extends Handler {  
        @Override  
        public void handleMessage(Message msg) {  
            switch (msg.what) {  
                case MSG_SAY_HELLO:  
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();  
                    break;  
                default:  
                    super.handleMessage(msg);  
            }  
        }  
    }  
  
    /** 
     * 這個Messenger可以關聯到Service裡的Handler,Activity用這個物件傳送Message給Service,Service通過Handler進行處理。 
     */  
    final Messenger mMessenger = new Messenger(new IncomingHandler());  
  
    /** 
     * 當Activity繫結Service的時候,通過這個方法返回一個IBinder,Activity用這個IBinder建立出的Messenger,就可以與Service的Handler進行通訊了 
     */  
    @Override  
    public IBinder onBind(Intent intent) {  
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();  
        return mMessenger.getBinder();  
    }  
}  

Activity程式碼實現

public class ActivityMessenger extends Activity {  
    /** 向Service傳送Message的Messenger物件 */  
    Messenger mService = null;  
  
    /** 判斷有沒有繫結Service */  
    boolean mBound;  
  
    private ServiceConnection mConnection = new ServiceConnection() {  
        public void onServiceConnected(ComponentName className, IBinder service) {  
            // Activity已經繫結了Service  
            // 通過引數service來建立Messenger物件,這個物件可以向Service傳送Message,與Service進行通訊  
            mService = new Messenger(service);  
            mBound = true;  
        }  
  
        public void onServiceDisconnected(ComponentName className) {  
            mService = null;  
            mBound = false;  
        }  
    };  
  
    public void sayHello(View v) {  
        if (!mBound) return;  
        // 向Service傳送一個Message  
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);  
        try {  
            mService.send(msg);  
        } catch (RemoteException e) {  
            e.printStackTrace();  
        }  
    }  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
    }  
  
    @Override  
    protected void onStart() {  
        super.onStart();  
        // 繫結Service  
        bindService(new Intent(this, MessengerService.class), mConnection,  
            Context.BIND_AUTO_CREATE);  
    }  
  
    @Override  
    protected void onStop() {  
        super.onStop();  
        // 解綁  
        if (mBound) {  
            unbindService(mConnection);  
            mBound = false;  
        }  
    }  
}  

 注意:以上寫的程式碼只能實現從Activity向Service傳送訊息,如果想從Service向Activity傳送訊息,只要把程式碼反過來寫就可以了。

 

使用AIDL

  這個方法略,如果知道上面兩種方法,這個方法基本很少會用到。




相關文章