Android -- Service綁定解綁和aidl


Service是安卓四大組件之一,先前講到了Service的生命周期,以及非綁定類型的生命周期的例子,這次來分享一下綁定形式的。

應用組件(客戶端)可以調用bindService()綁定到一個service。Android系統之后調用service的onBind()方法,它返回一個用來與service交互的IBinder。

綁定是異步的,bindService()會立即返回,它不會返回IBinder給客戶端。要接收IBinder,客戶端必須創建一個ServiceConnection的實例並傳給bindService()。ServiceConnection包含一個回調方法,系統調用這個方法來傳遞要返回的IBinder。

  • 實現ServiceConnection

實現必須重寫兩個回調方法:

onServiceConnected()

系統調用這個來傳送在service的onBind()中返回的IBinder。

OnServiceDisconnected()

Android系統在同service的連接意外丟失時調用這個.比如當service崩潰了或被強殺了.當客戶端解除綁定時,這個方法不會被調用。

  • 調用bindService(),傳給它ServiceConnection的實現。

  • 當系統調用你的onServiceConnected()方法時,你就可以使用接口定義的方法們開始調用service了。

  • 要與service斷開連接,調用unbindService()。

  • 程序                                                                                          

    public class MainActivity extends Activity {
    
        private Button btn_start;
        private Button btn_stop;
        private Button btn_change;
        private Button btn_bind;
        private Button btn_unbind;
        
        private MyConn myConn;
        
        private IService myBinder;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            btn_start = (Button) findViewById(R.id.btn_start);
            btn_stop = (Button) findViewById(R.id.btn_stop);
            btn_change = (Button) findViewById(R.id.btn_change);
            btn_bind = (Button) findViewById(R.id.btn_bind);
            btn_unbind = (Button) findViewById(R.id.btn_unbind);
            buttonListener bl = new buttonListener();
            btn_change.setOnClickListener(bl);
            btn_start.setOnClickListener(bl);
            btn_stop.setOnClickListener(bl);
            btn_bind.setOnClickListener(bl);
            btn_unbind.setOnClickListener(bl);
    
            
    
        }
    
        class buttonListener implements OnClickListener
        {
    
            @Override
            public void onClick(View v) {
                switch (v.getId()) {
                case R.id.btn_start:
                    Intent intent_start = new Intent(getApplicationContext(),BindService.class);
                    startService(intent_start);
                    break;
                case R.id.btn_stop:
                    Intent intent_stop = new Intent(getApplicationContext(),BindService.class);
                    stopService(intent_stop);
                    break;
                case R.id.btn_change:
                    if(myBinder != null)
                        myBinder.doChange("啦啦啦");
                    break;
                case R.id.btn_bind:
                    if(myConn == null)
                    {
                        myConn = new MyConn();
                        Intent intent_bind = new Intent(getApplicationContext(),BindService.class);
                        bindService(intent_bind, myConn, BIND_AUTO_CREATE);
                    }
                    break;
                case R.id.btn_unbind:
                    Intent intent_unbind = new Intent(getApplicationContext(),BindService.class);
                    if(myConn != null && myBinder != null)
                    {
                        unbindService(myConn);
                        myConn = null;
                        myBinder = null;
                    }
                    break;
    
                default:
                    break;
                }
    
            }
    
        }
        
        private class MyConn implements ServiceConnection
        {
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                System.out.println("代理人返回回來了,onServiceConnected");
                myBinder = (IService) service;
                
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                System.out.println("接觸綁定了,onServiceDisconnected");
                
            }
            
        }
        
        
    }

    Service類:

    public class BindService extends Service {
    
        @Override
        public IBinder onBind(Intent intent) {
            System.out.println("Service綁定成功,onBind");
            //返回自定義的代理對象
            return new MyBinder();//這里的返回是返回到MainActivity里面的綁定myConn
        }
        
        
        
        @Override
        public boolean onUnbind(Intent intent) {
            System.out.println("Service解綁成功,onUnbind");
            return super.onUnbind(intent);
        }
    
    
    
        public class MyBinder extends Binder implements IService
        {
            //間接的利用代理人調用了changeServiceThing的方法
            public void doChange(String what)
            {
                changeServiceThing(what);
            }
        }
    
        @Override
        public void onCreate() {
            System.out.println("Service開啟,onCreate");
            super.onCreate();
        }
    
        @Override
        public void onDestroy() {
            System.out.println("Service關閉,onDestroy");
            super.onDestroy();
        }
        
        public void changeServiceThing(String what)
        {
            Toast.makeText(getApplicationContext(), what+"變換了,changeServiceThing", Toast.LENGTH_LONG).show();
        }
    
        
        
    }

    IService:

    public interface IService {
        public void doChange(String what);
    }

    結果                                                                                           

    點擊“開啟服務”之后,再“綁定服務”,這樣執行之后直接點“關閉服務”是沒用的,要先“解除服務”,再“關閉服務”。如果直接“綁定服務”,那么點擊“關閉服務”沒有用,需要點擊“解綁服務”。

    aidl                                                                                           

    進程間通信->調用者和Service如果不在一個進程內,就需要使用android中的遠程Service調用機制。

    android使用AIDL定義進程間的通信接口。AIDL的語法與java接口類似,需要注意以下幾點:

    • AIDL文件必須以.aidl作為后綴名。
    • AIDL接口中用到的數據類型, 除了基本類型, String, List, Map, CharSequence之外, 其他類型都需要導包, 即使兩種在同一個包內. List和Map中的元素類型必須是AIDL支持的類型。
    • 接口名需要和文件名相同。
    • 方法的參數或返回值是自定義類型時, 該自定義的類型必須實現了Parcelable接口。
    • 所有非java基本類型參數都需要加上in, out, inout標記, 以表明參數是輸入參數, 輸出參數, 還是輸入輸出參數。
    • 接口和方法前不能使用訪問修飾符和static, final等修飾。

    進程間通信需要創建aidl文件,IService.aidl:

    public interface IService {
        public void doChange(String what);
    }

    接口中有一個static的抽象內部類Stub,Stub類繼承了Binder類並實現了IRemoteService接口。

    public class MainActivity extends Activity {
    
        private Intent intent;
        private IService iService;
        private ServiceConnection myConn;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
        }
    
        public void bind(View view) {
            intent = new Intent();
            intent.setAction("com.yydcdut.alipay");
            myConn = new MyConn();
            boolean flag = bindService(intent, myConn, BIND_AUTO_CREATE);
            System.out.println("flag------>" + flag);
        }
    
        private class MyConn implements ServiceConnection {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iService = IService.Stub.asInterface(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        }
    
        public void method(View view) {
            try {
                iService.callMethodInService();
            } catch (RemoteException e) {
                // TODO 自動生成的 catch 塊
                e.printStackTrace();
            }
        }
    
    }

    在實現這個的時候我建立了兩個程序,這樣可以做到進程間通信。附帶了源碼。

    我是天王蓋地虎的分割線                                                               

    源代碼:http://pan.baidu.com/s/1dD1Qx01

    service學習2.zip

    aidl學習.zip

    aidl學習配套2.zip

     

     

    轉載請注明出處:http://www.cnblogs.com/yydcdut

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM