aidl实现进程间通信

在封装sdk的过程中,sdk是如何与app进行通信的呢?

总所周知,进程间通信,android的四大组件都是可以做到的,如果大家对其中原理有不明白的可以参照http://blog.csdn.net/toyuexinshangwan/article/details/8640709,这个博客说明得比较清楚。

 

下面我们主要学习的是,sdk利用aidl服务实现与app之间相互通信。
以下就举我做项目用到的一个demo作为例子,说说aidl服务的用法及使用中会遇到的问题。

 

demo实现的功能很简单,因为我做的是一个IM的sdk包,所以需要在IM的连接状态发生变化时,去通过app即时展示出来。

那么我们的aidl的服务可以这样设计。

创建一个IXmppConnectCallBack用来给予app实现sdk的连接状态监听。

创建一个IRemoteServiceInterface用来向sdk注册IXmppConnectCallBack的回调方法。

(可能大家对这两个接口关系不太明白,开始我也是;可以认为sdk是一个法院,IRemoteServiceInterface是我们的代表律师,IXmppConnectCallBack就是申诉人;就是申诉人委托律师去法院执行一些工作,个人愚见,哈哈)

// IRemoteServiceInterface.aidl
package com.guiyi.hsim;

// Declare any non-default types here with import statements

import com.guiyi.hsim.IXmppConnectCallBack;

interface IRemoteServiceInterface {
    /**
                 * Often you want to allow a service to call back to its clients.
                 * This shows how to do so, by registering a callback interface with
                 * the service.
                 */
                void registerCallback(IXmppConnectCallBack cb);

                /**
                 * Remove a previously registered callback interface.
                 */
                void unregisterCallback(IXmppConnectCallBack cb);
}
// IXmppConnectCallBack.aidl
package com.guiyi.hsim;

// Declare any non-default types here with import statements

interface IXmppConnectCallBack {
    /**
                 * Demonstrates some basic types that you can use as parameters
                 * and return values in AIDL.
                 */
                void connectStateChanged(int value);
}

 

注意点1:添加aidl的时候,如果需要引入别的类,需要手动Import,如上IRemoteServiceInterface 的

import com.guiyi.hsim.IXmppConnectCallBack;

 

定义两个接口之后,我们需要实现一个service类来运作。

package com.dannytree.mylibrary;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by kangsq on 2016/7/20.
 */
public class RemoteService extends Service {
    /**
     * This is a list of callbacks that have been registered with the
     * service.  Note that this is package scoped (instead of private) so
     * that it can be accessed more efficiently from inner classes.
     */
    private final static int CONNECITON_STATE_CHANGE = 101;

    static final RemoteCallbackList<IXmppConnectCallBack> mCallbacks
            = new RemoteCallbackList<IXmppConnectCallBack>();
    private int mValue = 0;
    //private static final int REPORT_MSG = 1;

    public int FullState = 0;

    private int tempint = 1;

    @Override
    public void onCreate() {
        //mHandler.sendEmptyMessage(REPORT_MSG);

        timer.schedule(task, 10000, 10000); // 10s后执行task,经过10s再次执行
    }


    Timer timer = new Timer();
    TimerTask task = new TimerTask() {

        @Override
        public void run() {
            connectionStateChange(tempint++);
        }
    };

    public void connectionStateChange(int state) {

        /*final int N = mCallbacks.beginBroadcast();
        Log.d("RemoteService","before handler mCallbacks count....----.=="+N);
*/

        FullState = state;

        Log.d("RemoteService", "gettting  FullState...." + state);
        Message msg = new Message();
        msg.arg1 = state;
        msg.what = CONNECITON_STATE_CHANGE;

        mHandler.sendMessageDelayed(msg, 1000);
    }

    @Override
    public void onDestroy() {
        // Tell the user we stopped.
        //Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();
        // Unregister all callbacks.
        mCallbacks.kill();
        Log.d("RemoteService","mCallbacks ..kill ..");
        // Remove the next pending message to increment the counter, stopping
        // the increment loop.
        //mHandler.removeMessages(REPORT_MSG);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d("RemoteService","IRemoteServiceInterface onbind....");
        return mServiceBinder;

        // Select the interface to return.  If your service only implements
        // a single interface, you can just return it here without checking
        // the Intent.
        /*if (IRemoteServiceInterface.class.getName().equals(intent.getAction())) {
            Log.d("RemoteService","IRemoteServiceInterface onbind....");
            return mServiceBinder;
        }

        Log.d("RemoteService","nothing onbind....");
        return null;*/
    }

    /**
     * The IRemoteInterface is defined through IDL
     */
    private final IRemoteServiceInterface.Stub mServiceBinder = new IRemoteServiceInterface.Stub() {
        public void registerCallback(IXmppConnectCallBack cb) {
            if (cb != null) {
                boolean aa = mCallbacks.register(cb);

                Log.d("RemoteService", "mCallbacks ..register successed.?" + aa);

                // int bb = mCallbacks.beginBroadcast();
                // Log.d("RemoteService", "mCallbacks ..count ?" + bb);
            }
        }

        public void unregisterCallback(IXmppConnectCallBack cb) {
            if (cb != null) mCallbacks.unregister(cb);
        }

    };



    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Toast.makeText(this, "Task removed: " + rootIntent, Toast.LENGTH_LONG).show();
    }

    /**
     * Our Handler used to execute operations on the main thread.  This is used
     * to schedule increments of our value.
     */
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CONNECITON_STATE_CHANGE:
                    Log.d("RemoteService","getting mHandler....");

                    int state_enum = (int) msg.arg1;

                    final int N = mCallbacks.beginBroadcast();
                    Log.d("RemoteService","mCallbacks count....----.=="+N);
                    for (int i = 0; i < N; i++) {
                        try {
                            Log.d("RemoteService","mCallbacks sending....----.=="+state_enum);
                            mCallbacks.getBroadcastItem(i).connectStateChanged(state_enum);

                        } catch (RemoteException e) {
                            // The RemoteCallbackList will take care of removing
                            // the dead object for us.
                            Log.d("RemoteService","getting mHandler. getBroadcastItem error...");
                        }
                    }
                    mCallbacks.finishBroadcast();
                    break;
            }
        }
    };
}

 

 

 

注意点2:onBind方法中必须返回一个IBinder ,否则app端bindservice的时候可能会失败。

注意点3:通过RemoteCallbackList来删除跨进程listener的接口。用于解决无法删除对应listener对象。因为是客户端传递给服务端的对象在服务端会生成一个不同的对象,但它们底层的Binder对象是同一个,利用这个特点,找出那个和解注册listener具有相同Binder对象的服务端listener并把它删除掉。另外,当客户端进程终止后,它能够自动移除客户端所注册的listener。 

static final RemoteCallbackList<IXmppConnectCallBack> mCallbacks
            = new RemoteCallbackList<IXmppConnectCallBack>();

注意点4:上述变量最初只有final,所以mCallbacks.beginBroadcast()一直返回0,导致app无法接收到sdk端的通知。原来是因为final在类的每次调用中,都会初始化一遍。基础不扎实啊

 

 

 

 

至此,sdk封装就完成了,app端已经可以正常收到回调

package com.dannytree.testusingaidl;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.dannytree.mylibrary.IRemoteServiceInterface;
import com.dannytree.mylibrary.IXmppConnectCallBack;
import com.dannytree.mylibrary.RemoteService;

public class MainActivity extends Activity implements View.OnClickListener{

    IRemoteServiceInterface m_remoteServiceInterface =null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.btn_bind).setOnClickListener(this);
    }



    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_bind:
                Intent intent = new Intent(this, RemoteService.class);
                //intent.setPackage("com.guiyi.hsim");
                //注意这里的Context.BIND_AUTO_CREATE,这意味这如果在绑定的过程中,
                //如果Service由于某种原因被Destroy了,Android还会自动重新启动被绑定的Service。
                // 你可以点击Kill Process 杀死Service看看结果
                bindService(intent,
                        mConnection, Context.BIND_AUTO_CREATE);
                //mIsBound = true;
                //mCallbackText.setText("Binding.");

                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (m_remoteServiceInterface != null) {
            try {
                m_remoteServiceInterface.unregisterCallback(Act_mCallback);
            } catch (RemoteException e) {
                // There is nothing special we need to do if the service
                // has crashed.
            }
        }
        unbindService(mConnection);
        //unbindService(mcallbackConnection);
    }

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            Log.d("abrahamkang", "========= inside====onServiceConnected");

            // This is called when the connection with the service has been
            // established, giving us the service object we can use to
            // interact with the service.  We are communicating with our
            // service through an IDL interface, so get a client-side
            // representation of that from the raw service object.
            m_remoteServiceInterface = IRemoteServiceInterface.Stub.asInterface(service);
            //mKillButton.setEnabled(true);
            //mCallbackText.setText("Attached.");

            // We want to monitor the service for as long as we are
            // connected to it.
            try {
                m_remoteServiceInterface.registerCallback(Act_mCallback);

                Log.d("abrahamkang", "=============registerCallback");
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even
                // do anything with it; we can count on soon being
                // disconnected (and then reconnected if it can be restarted)
                // so there is no need to do anything here.
                Log.d("abrahamkang", "=============registerCallback error"+e.toString());
            }

            // As part of the sample, tell the user what happened.
            /*Toast.makeText(BindActivity.this, R.string.remote_service_connected,
                    Toast.LENGTH_SHORT).show();*/
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            m_remoteServiceInterface = null;

            Log.d("abrahamkang", "=============onServiceDisconnected ");
//            mKillButton.setEnabled(false);
//            mCallbackText.setText("Disconnected.");

            // As part of the sample, tell the user what happened.
//            Toast.makeText(BindActivity.this, R.string.remote_service_disconnected,
//                    Toast.LENGTH_SHORT).show();
        }
    };


    /**
     * 远程回调接口实现
     */
    private IXmppConnectCallBack Act_mCallback = new IXmppConnectCallBack.Stub() {
        @Override
        public void connectStateChanged(int state) throws RemoteException {
            Toast.makeText(MainActivity.this, "Connection state is " + state, Toast.LENGTH_SHORT).show();
        }
    };
}

 

注意点5:在app中的AndroidManifest.xml中需要添加与sdk中service一致的包名才能bindservice成功。

<service
android:name="com.dannytree.mylibrary.RemoteService"
></service>




posted @ 2016-07-28 16:23  HealthTree  阅读(487)  评论(0编辑  收藏  举报