天天看點

Service與Activity之間的通訊(二)

開啟服務是不能使Service和Activity之間通訊的,是以隻能通過綁定服務完成。

有三種方式來建立綁定服務,接下來一個一個的介紹:

一、擴充 Binder 類

此方法隻有在用戶端和服務位于同一應用和程序内這一最常見的情況下方才有效。

1、在服務中,建立一個可滿足下列任一要求的 Binder 執行個體:

1)包含用戶端可調用的公共方法

2)傳回目前 Service 執行個體,其中包含用戶端可調用的公共方法

3)或傳回由服務承載的其他類的執行個體,其中包含用戶端可調用的公共方法

2、從 onBind() 回調方法傳回此 Binder 執行個體。

3、在用戶端中,從 onServiceConnected() 回調方法接收 Binder,并使用提供的方法調用綁定服務。

接下來通過代碼來說話吧

public class MyService extends Service {

    private final MyIBinder myIBinder = new MyIBinder();

    //其他綁定了該Service的元件可以通過IBinder對象與該Service進行通訊,該方法隻執行一次
    @Override
    public IBinder onBind(Intent intent) {
        return myIBinder;//傳回IBinder對象,傳給onServiceConnected
    }
    //繼承Binder而不是繼承IBinder的原因:Binder是IBinder的子類,若果要繼承IBinder會需要實作很多的方法,比較複雜也沒什麼用
    public class MyIBinder extends Binder {
         MyService getServiceInstance() {
            return MyService.this;
        }
    }

    //這個就是服務要做的東東了,必須是公共的,可被外界調用的
    public InputStream getImageFromNet(String path){

        InputStream inputStream = null;
        try {
            URL url = new URL(path);
            try {
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout();

                if(connection.getResponseCode() == ){
                    inputStream = connection.getInputStream();
                    return inputStream;
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return  null;
    }
}
           
public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private MyService myService;
    private MyService.MyIBinder myIBinder;
    private boolean isBond;
    private ServiceConnection serviceConnection= new ServiceConnection() {
        //服務連接配接成功調用的方法
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            myIBinder = (MyService.MyIBinder) iBinder;
            //通過IBinder的到服務(IBinder很關鍵的)
            myService = myIBinder.getServiceInstance();
            isBond = true;
            //可以在這裡調用服務裡的那個公共方法,耗時的不要在主現場直接寫哈
        }
        //服務連接配接失敗調用的方法
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            isBond = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.image);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MyService.class);
        //綁定服務,注意第三個參數哈,寫錯了可能看不到想要的結果
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

    }
    //我是在界面可見時綁定了服務,當點選按鈕時才開始執行裡面的通路網絡的操作
    public void startService(View view) {
        Intent intent = new Intent(this,MyService.class);
        startService(intent);

        if (isBond) {
            //開啟子線程做耗時操作,不要忘了調用start方法,否則白寫了
            new Thread(new Runnable() {
                @Override
                public void run() {
                    InputStream inputStream = myService.getImageFromNet("http://dl.iteye.com/upload/attachment/533746/cdfa048a-d545-31c5-b250-2ec546863eb3.jpg");
                    final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    //不能在非UI線程中更新UI,這個裡面的runnable是運作在主線程的
                    imageView.post(new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImageBitmap(bitmap);
                        }
                    });
                }
            }).start();
        }
    }

    public void stopService(View view) {
        if(isBond){
            unbindService(serviceConnection);
            isBond = false;
        }
    }
           

二、使用 Messenger

如需讓服務與遠端程序通信,則可使用 Messenger 為您的服務提供接口。利用此方法,您無需使用 AIDL 便可執行程序間通信 (IPC)。

與 AIDL 比較 當您需要執行 IPC 時,為您的接口使用 Messenger 要比使用 AIDL 實作它更加簡單,因為Messenger 會将所有服務調用排入隊列,而純粹的 AIDL 接口會同時向服務發送多個請求,服務随後必須應對多線程處理。

對于大多數應用,服務不需要執行多線程處理,是以使用 Messenger 可讓服務一次處理一個調用。如果您的服務必須執行多線程處理,則應使用AIDL 來定義接口。

  • 1、服務實作一個 Handler,由其接收來自用戶端的每個調用的回調
  • 2、 Handler 用于建立 Messenger 對象(對 Handler 的引用)
  • 3、Messenger 建立一個 IBinder,服務通過 onBind() 使其傳回用戶端
  • 4、用戶端使用 IBinder 将 Messenger(引用服務的 Handler)執行個體化,然後使用後者将 Message 對象發送給服務
  • 5、服務在其 Handler 中(具體地講,是在 handleMessage() 方法中)接收每個 Message

接下來上代碼來說明吧

public class MessengerServiceDemo extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //通過messenger得到IBinder對象并傳回
        return messenger.getBinder();
    }
    //為了建立Messenger建立,
    class MyHandle extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);         
                Log.e("------>","fgfgfgfgs");
        }
    }
    //建立Messenger對象
    Messenger messenger = new Messenger(new MyHandle());
}
           
public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private boolean isBond;
    private Messenger messenger;

    private ServiceConnection messengerconn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            messenger = new Messenger(iBinder);
            isBond = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            messenger = null;
            isBond = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.image);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MessengerServiceDemo.class);
        bindService(intent, messengerconn, Context.BIND_AUTO_CREATE)
    }

    public void startService(View view) {
        if (isBond) {

            Message message = Message.obtain();
            message.what = ;

            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }
    }

    public void stopService(View view) {
        if(isBond){
            unbindService(messengerconn);
            isBond = false;
        }
    }
           

三、AIDL

這個沒有用過,不太會,就不多說了,以免誤導大家……

點這裡看AIDL文檔

AIDL實作