[Android Studio] AIDL

AIDL 用于进程间通信,广泛应用于安卓开发中.

从Android 5.0开始,Google推荐使用Android Studio 进而取代原来的Eclipse.

下面以一简单例子介绍AIDL的使用(非概念) ,基于 Android Studio (1.0.1).

PS: AIDL 基础概念可以参考: http://blog.csdn.net/stonecao/article/details/6425019

 

1. 主要模块

(1) AIDLClient: AIDL 客户端,提供一个Button 和 TextView.

UI(TextView)更新有两个方式:a. 点击Button,从服务端获取信息主动更新; b. 服务端定时请求客户端更新。

从而实现客户端和服务端之间的通信.

(2) AIDLService: AIDL 服务端,启动一个线程计数(模拟获取数据). 主要功能:

a. 提供客户端调用方法 b.主动请求更新

 

2. AIDL文件

Client & Service 端需要相同的.aidl 文件, 并且包名实现.

在Android Studio 中创建AIDL 文件非常方便,File -> New ->AIDL, 之后在java 的同目录下会创建"aidl" 文件夹.

以下两个文件在客户端和服务端都要有一份(IMyService 在服务端实现,IAdapter 在客户端实现 )

// IMyService.aidl
package com.xx.myaidlservice;

// Declare any non-default types here with import statements
import com.xx.aidlapp.iadapter;

interface IMyService {
    void setAdapter(in IAdapter adapter);
    String getMsg();
}

 

// IAdapter.aidl
package com.xx.aidlapp;

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

interface IAdapter {
    void resetTextView(String text);
}

 

3. 服务端实现: 

(1)注意黄色部分,即mBinder为实现IMyService.Stub  (其中Stub 是IMyService的内部类),

在客户端绑定服务后返回mBinder给客户端,因此客户端可以通过mBinder调用服务端的方法

(2) 蓝色背景部分,为服务端调用客户端方法. 其中mAdapter 是由客户端传过的值实例化. 从而调用客户端方法resetTextView。

 

package com.xx.myaidlservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.xx.aidlapp.IAdapter;


public class AIDLService extends Service {
    private final String LOG_TAG = "AIDLService";
    public IMyService mImyService;
    private int cnt;
    private AutoCountThread thread;
    private boolean stopThread;
    private IAdapter mAdapter;

    public AIDLService() {
    }

    @Override
    public void onCreate() {
        Log.d(LOG_TAG, "OnCreate " );
        super.onCreate();
        cnt = 0;
        stopThread = false;
        thread = new AutoCountThread();
        thread.start();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(LOG_TAG, "onStartCommand " );
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.d(LOG_TAG, "onDestroy " );
        stopThread = true;
        super.onDestroy();
    }

    private final IMyService.Stub mBinder = new IMyService.Stub(){
        @Override
        public void setAdapter(IAdapter adapter) throws RemoteException {
            Log.d(LOG_TAG, "setAdapter adapter " + adapter );
            mAdapter = adapter;
        }

        @Override
        public String getMsg() throws RemoteException {
            String serviceStr;
            serviceStr = "Msg(Service) " + cnt;
            Log.d(LOG_TAG, "serviceStr = " + serviceStr + " cnt = " + cnt);
            return serviceStr;
        }
    };


    @Override
    public IBinder onBind(Intent intent) {
        Log.d(LOG_TAG, "onBind");
        if(mBinder == null){
            Log.d(LOG_TAG, "bind service fail -- mBinder == null");
        }
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(LOG_TAG, " onUnbind -- intent" + intent);
        return super.onUnbind(intent);
    }

    public class AutoCountThread extends Thread{

        @Override
        public void run() {
            //super.run();
            while(stopThread != true) {
                try {
                    cnt++;
                    Thread.sleep(5000);
                    Log.d(LOG_TAG, "stopThread " + stopThread + " cnt = " + cnt);
                    resetText();
                    if(cnt == 50){
                        stopThread = true;
                    }
                } catch (InterruptedException e) {
                    Log.d(LOG_TAG, "AutoCountThread InterruptedException e " + e);
                }
            }
        }

        @Override
        public synchronized void start() {
            super.start();
            Log.d(LOG_TAG, "AutoCountThread -- start");
        }
    }

    public void resetText(){
        Log.d(LOG_TAG, "resetText --mAdapter =  " + mAdapter );
        if( mAdapter!= null){
            String serviceStr;
            serviceStr = "Auto Update Msg(Service) " + cnt;
            try {
                Log.d(LOG_TAG, "serviceStr =  " + serviceStr );
                mAdapter.resetTextView(serviceStr);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}

 

4. 客户端实现:

(1) 黄色部分即为调用服务端方法

(2) 蓝色部分即为客服端实现的AIDL接口相关

注意: 在服务端请求更新UI, 客服端需要在主线程中更新UI, 否则setText不生效, 该处使用了Hanlder处理.

package com.xx.aidlapp;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.xx.myaidlservice.IMyService;


public class AIDLMainActivity extends Activity {
    private final String LOG_TAG = "AIDLMainActivity";
    private Button aidlTestBtn;
    private TextView messageText;
    private IMyService mService;

    private MyServiceConnection conn;

    private static final int MSG_UPDATE_TEXT = 1;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_UPDATE_TEXT:
                    //Log.d(LOG_TAG, "  handleMessage msg.obj = " + msg.obj);
                    updateTextView((String)msg.obj);
            }
        }
    };


    private final IAdapter mAdapter = new IAdapter.Stub(){

        @Override
        public void resetTextView(String text) throws RemoteException {
            //Log.d(LOG_TAG, "resetTextView text = "  + text);
            Message msg = mHandler.obtainMessage(MSG_UPDATE_TEXT, text);
            mHandler.sendMessage(msg);
            //messageText.setText(text);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //Log.d(LOG_TAG, "   onCreate + mAdapter = " + mAdapter);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_aidl_main);

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        aidlTestBtn = (Button) findViewById(R.id.aidlButton1);
        messageText = (TextView) findViewById(R.id.msgText);
        //Log.d(LOG_TAG, "onCreate -- messageText " + messageText);

        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.xx.myaidlservice", "com.xx.myaidlservice.AIDLService"));
        conn = new MyServiceConnection();
        bindService(intent, conn, Context.BIND_AUTO_CREATE);

        aidlTestBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String msg = "Init";
                try {
                    if (mService != null ) {
                        msg = mService.getMsg();
                    }else{
                        Toast.makeText(AIDLMainActivity.this, "Service has been kill, can not get message from AIDLService", Toast.LENGTH_SHORT);
                    }
                } catch (RemoteException e) {
                    Log.d(LOG_TAG, "   mService.getMsg fail");
                }
                messageText.setText(msg);
            }
        });

    }

    @Override
    protected void onDestroy() {
        Log.d(LOG_TAG, "onDestroy");
        if(mService != null){
            Log.d(LOG_TAG, "onDestroy --> unbindService");
            unbindService(conn);
        }
        super.onDestroy();
    }

    protected class MyServiceConnection implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(LOG_TAG, "onServiceConnected-- ComponentName = " + name);
            mService = IMyService.Stub.asInterface(service);
            setAdapter();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(LOG_TAG, "onServiceDisconnected -- ComponentName = " + name);
            mService = null;
        }
    }


    private void setAdapter(){
        Log.d(LOG_TAG, "mService = " + mService + " mAdapter = " + mAdapter);
        if(mService != null){
            try {
                mService.setAdapter(mAdapter);
            } catch (RemoteException e) {
                Log.d(LOG_TAG, "   mService.setAdapter fail");
            }
        }

    }
    public void updateTextView(String text){
        Log.d(LOG_TAG, "updateTextView "  + text);
        //Log.d(LOG_TAG, "updateTextView -- messageText " + messageText);
        messageText.setText(text);
    }

}

 

5. 总结

1. 客户端和服务端需要相同的AIDL文件,包括包名需要一样。可以在写好一份拷贝过去。

2.定义了AIDL接口文件后,需要实现该接口, 另一方通过 xx.Stub.asInterface 获取代理对象.

3. UI更新需要在主线程中.

4. AIDLService 在启动一段时间后,会被强制kill掉,不知是不是内存泄露了...

未完待续。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值