1. 程式人生 > >Android Service 之繫結服務和AIDL

Android Service 之繫結服務和AIDL

今天在這裡給大家介紹Android 四大元件中service中的繫結模式onBind(),Activity和Service 之間可以繫結然後做到資料的互動,比如我做一個登入然後在服務中去進行判斷,在這裡演示一個簡單點的Demo就是一個普通的登入:

佈局如下,二個EditText和一個登入的Button:

<EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/main_qqname_edit"
        android:hint="請輸入使用者名稱/QQ/電話號碼"/>
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/main_qqpwd_edit"
        android:hint="請輸入密碼"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="login"
        android:text="登入"/>
在MainActivity中拿到幾個控制元件然後獲取值,再進行與服務之間的繫結
 private EditText main_qqname_edit;
    private EditText main_qqpwd_edit;
    private Intent intent;
    private QQLoginInterface qqLoginInterface;
    private QQLoginInterfaceOut qqLoginInterfaceOut;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //使用者名稱的控制元件
        main_qqname_edit = (EditText) findViewById(R.id.main_qqname_edit);
        //密碼的控制元件
        main_qqpwd_edit = (EditText) findViewById(R.id.main_qqpwd_edit);
        //繫結服務需要的Intent
        intent = new Intent(this,QQLoginServices.class);
    }
        //服務需要的ServiceConnection
        ServiceConnection connection=new ServiceConnection() {
        //繫結服務成功會呼叫的方法
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            qqLoginInterface = (QQLoginInterface) iBinder;

           // qqLoginInterfaceOut = QQLoginInterfaceOut.Stub.asInterface(iBinder);
        }
        //繫結服務失敗會呼叫的方法
        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };
        //進行互動時繫結服務
    @Override
    protected void onResume() {
        super.onResume();
        //繫結服務
        bindService(intent,connection, Service.BIND_AUTO_CREATE);
    }


具體的詳解在註釋中寫清楚就不具體解釋了,服務的類中內容如下,註釋狀態中的程式碼不予本次內容有關:
public class QQLoginServices extends Service {
//    class MyIBinder extends QQLoginInterfaceOut.Stub{
//
//        @Override
//        public boolean login(String qqname, String qqpwd) throws RemoteException {
//            if("100".equals(qqname)&&"123".equals(qqpwd)){
//                return true;
//            }
//            return false;
//        }
//    }

//onBind()方法中需要一個IBinder的返回型別值,所以我們在這裡例項化一個IBinder的子類Binder然後繼承一個介面來重寫這個方法提高安全性
    class MyIBinder extends Binder implements QQLoginInterface{

        @Override
        public boolean login(String qqname, String qqpwd) {
            if("100".equals(qqname)&&"123".equals(qqpwd)){
                return true;
            }
            return false;
        }
    }

//繫結服務時需要的生命週期:繫結
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyIBinder();
    }
}
在點選按鈕的時候進行如下操作:
 //點選按鈕的方法
    public void login(View view){
        String qqname=main_qqname_edit.getText().toString();
        String pwd=main_qqpwd_edit.getText().toString();
        boolean flag=qqLoginInterface.login(qqname,pwd);
      //  boolean flag= false;
       // try {
        //    flag = qqLoginInterfaceOut.login(qqname,pwd);
       // } catch (RemoteException e) {
       //     e.printStackTrace();
       // }

        Toast.makeText(this,""+flag,Toast.LENGTH_LONG).show();


    }
這裡的qqLoginInterface是我們之前繫結服務成功時裡面的那個介面,然後拿到接口裡面的登入方法把值給傳回去,在清單檔案中配置一下Service:
<service android:name=".QQLoginServices"
            android:exported="true"
            ></service>
那麼這裡的Service中的繫結就這樣了,要注意我們的繫結中的互動會放回Binder中寫入方法的放回型別,如要需要改動可以自己更改型別。

好了,現在說一下AIDL ,Android介面語言,就是程序與程序之間的通訊,比如demo1和demo2都可以使用一個登入的方法,那麼就可以在demo2中去呼叫demo1的登入方法,就是提供一個介面你去呼叫。那麼這裡的佈局就如上 只是多做一個demo,然後什麼都不需要做很多的改變。

先建立一個AIDL,在Android studio中右擊可以new 一個AIDL 然後輸入一個名字,會產生一個AIDL的檔案,並且會產生一個相對應的java檔案。

在AIDL檔案中吧我們介面中的方法放進去也就是如下:

interface QQLoginInterfaceOut {
     boolean login(String qqname,String qqpwd);

}

在服務類中需要更改由我們的AIDL作為IBinder返回,程式碼如下:

 class MyIBinder extends QQLoginInterfaceOut.Stub{

        @Override
        public boolean login(String qqname, String qqpwd) throws RemoteException {
            if("100".equals(qqname)&&"123".equals(qqpwd)){
                return true;
            }
            return false;
        }
    }
直接繼承我們的AIDL類點出其中的Stub就可以,然後在MainActivity中不需要我們之前的那個介面來接收了,由我們的AIDL來接收,需要更改的程式碼如下:
//服務需要的ServiceConnection
        ServiceConnection connection=new ServiceConnection() {
        //繫結服務成功會呼叫的方法
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //qqLoginInterface = (QQLoginInterface) iBinder;

            qqLoginInterfaceOut = QQLoginInterfaceOut.Stub.asInterface(iBinder);
        }
        //繫結服務失敗會呼叫的方法
        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

在點選事件中直接用qqLoginInterfaceOut點出其中的方法就可以。第一個demo就是這樣,和上面介紹的在這裡看不出什麼變化,但是在第二個demo中我們可以直接訪問這裡的服務傳回來值在這裡做判斷了,

第二個demo中佈局什麼的和上面的demo一樣,只說一下需要改變的地方,首先把demo1中由AIDL產生的介面類同包名和類名Copy到與MainActivity的包同級目錄下,

MainActivity下的需要更改的程式碼如下:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        main_qqname_edit = (EditText) findViewById(R.id.main_qqname_edit);
        main_qqpwd_edit = (EditText) findViewById(R.id.main_qqpwd_edit);
        intent = new Intent();
        ComponentName componentName=new ComponentName("com.example.android_services_bind_aidl","com.example.android_services_bind_aidl.QQLoginServices");
        intent.setComponent(componentName);
    }
            ServiceConnection connection=new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //  qqLoginInterface = (QQLoginInterface) iBinder;

            qqLoginInterfaceOut = QQLoginInterfaceOut.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

重點是Intent跳轉通過ComponentName來進行跳轉到demo1,ComponentName第一個引數是包名,第二個是包名加類名。

然後就可以輕鬆訪問到demo1中的那個服務了。

今天的分享就到這了,可能有些地方說的不清楚,但是在demo1中程式碼中的註釋希望大家看下可能可以幫助到。