Android应用内跨进程通信AIDL实例与源码

来源:互联网 发布:vga矩阵切换器标准进出 编辑:程序博客网 时间:2024/06/17 13:16
1. 跨进程通信
在android应用中不同进程是不能共享内存的,所以在不同进程间传递对象就需要用到跨进程通信。

2. 应用内多进程
一般一个应用一个进程就足够了,但如果像一些大型的应用经常会看到不止一个进程,比如微信、QQ之类的。一个进程的内存是定死的,如果有耗内存的动作就容易OOM,这时候就可以考虑多进程,提高内存的限制,还有就是不同进程间可以相互监听达到互相守护的功能,提高应用后台保持运行几率。

比如本人所在公司开发的软件是关于VoIP通信类,一个进程是那些通讯录、消息、历史记录、用户等等相关的Activity,而另一个进程是PJSIP通信相关的Service。这个service就相当于远程服务,独立运行,而Activity经常需要跟这个Service交互比如打VoIP电话,这就需要用到跨进程通信。

3. Android跨进程通信接口
Android跨进程通信可以采用AIDL来公开服务的接口,采用远程过程调用和代理模式来实现跨进程通信。AIDL英文全称Android Interface Definition Language 即 Android接口描述语言,ADT会根据AIDL在gen下生成相应的JAVA接口文件。

4. 实例解析
这个实例本来是我给来公司面试的人员出的一道面试题,后来闲着没事就自己写了个demo,题目大体如下:展示天气的demo,Activity负责展示,Service负责获取天气,Acitivty和Service在不同的进程,之间必须通过AIDL来传递对象。过程是Activity点击获取天气的BUTTON后Service开始获取天气,并封装成一个对象以回调的形式回传给Activity,Activity展示该天气信息。

(1) Android工程结构
以前用Eclipse,现在改用Android Studio,感觉效率提高了不少。结构如下图包括MainActivity 展示天气,WeatherBean 天气对象,WeatherService 获取天气的服务。 AIDL 包括 IWeatherInterface 天气服务的接口,IWeatherServiceCallback 天气服务回调的接口, WeatherBean 天气对象接口。




(2) AIDL文件

IWeatherInterface.aidl
这个AIDL主要是Activity绑定Service后注册和解注册回调接口以及通知Service开始获取天气的接口方法。源码如下:
// IWeatherInterface.aidlpackage com.easiio.test.weather;import com.easiio.test.weather.IWeatherServiceCallback;interface IWeatherInterface {    void registerCallback(int hash, IWeatherServiceCallback callback);    void unregisterCallback(int hash);    void startGetWeather(String citypinyin);}

IWeatherServiceCallback.aidl
这个是Service将天气回传给Activity的接口文件,源码如下:
// IWeatherServiceCallback.aidlpackage com.easiio.test.weather;import com.easiio.test.weather.WeatherBean;interface IWeatherServiceCallback {    void showWeather(in WeatherBean weather);}

WeatherBean.aidl
AIDL支持传递实现了android.os.Parcelable接口的复杂类型,这里的天气对象就是implements Parcelable 的复杂类型对象
// IWeatherServiceCallback.aidlpackage com.easiio.test.weather;parcelable WeatherBean;

(3) 主程序

MainActivity.java
package com.easiio.test.weather;import android.app.ProgressDialog;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.RemoteException;import android.support.design.widget.Snackbar;import android.support.v4.util.LogWriter;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.text.TextUtils;import android.util.Log;import android.view.View;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends AppCompatActivity {    private static final String TAG = "[EASIIO]MainActivity";    private static final int MSG_WHAT_GET_SUCCESS = 0;    private TextView mShowWeatherView;    private EditText mCityPinyinET;    private ProgressDialog mProgressDialog;    private IWeatherInterface mIWeatherInterface;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.i(TAG, "onCreate...");        setContentView(R.layout.activity_main);        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);        setSupportActionBar(toolbar);        mShowWeatherView = (TextView) this.findViewById(R.id.weather_text_view);        mCityPinyinET = (EditText) this.findViewById(R.id.city_pinyin_edittext);        mProgressDialog = new ProgressDialog(this);        mProgressDialog.setMessage("Loading...");        this.findViewById(R.id.button_get_weather).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                String pinyin = mCityPinyinET.getEditableText().toString();                if (TextUtils.isEmpty(pinyin)){                    Toast.makeText(MainActivity.this, "Not empty", Toast.LENGTH_SHORT).show();                    return;                }                mProgressDialog.show();                try {                    if (mIWeatherInterface != null){                        mIWeatherInterface.startGetWeather(pinyin);                    }                } catch (RemoteException ex){                    Log.e(TAG, "Start get weather failed, ex : " + ex.getLocalizedMessage());                }            }        });        if(!bindService(new Intent(this, WeatherService.class), mServiceConnection, Context.BIND_AUTO_CREATE)){            Toast.makeText(this, "Bind service failed.", Toast.LENGTH_SHORT);            finish();            return;        }    }    @Override    protected void onDestroy() {        super.onDestroy();        if (mServiceConnection != null){            this.unbindService(mServiceConnection);        }    }    private ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            try {                mIWeatherInterface = IWeatherInterface.Stub.asInterface(iBinder);                mIWeatherInterface.registerCallback(mIWeatherServiceCallback.hashCode(), mIWeatherServiceCallback);            } catch (Exception ex){                Log.e(TAG, "onServiceConnected failed : " + ex.getLocalizedMessage());            }        }        @Override        public void onServiceDisconnected(ComponentName componentName) {            try {                mIWeatherInterface.unregisterCallback(mIWeatherServiceCallback.hashCode());            } catch (Exception ex){                Log.e(TAG, "onServiceConnected failed : " + ex.getLocalizedMessage());            }        }    };    private IWeatherServiceCallback mIWeatherServiceCallback = new IWeatherServiceCallback.Stub () {        @Override        public void showWeather(WeatherBean weather) throws RemoteException {            Log.i(TAG, "shoWeather : " + weather.toString());            Message msg = mHandler.obtainMessage();            msg.what = MSG_WHAT_GET_SUCCESS;            msg.obj = weather;            mHandler.sendMessage(msg);        }    };    private Handler mHandler = new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if (msg.what == MSG_WHAT_GET_SUCCESS){                mProgressDialog.dismiss();                if (msg.obj == null){                    mShowWeatherView.setText("Weather is null.");                    return;                }                WeatherBean weather = (WeatherBean) msg.obj;                if (weather == null){                    mShowWeatherView.setText("Weather is null.");                    return;                }                mShowWeatherView.setText(weather.toString());            }        }    };}<span style="color:#4169e1;font-weight: bold;"></span>



WeatherService.java
package com.easiio.test.weather;import android.app.Service;import android.content.Intent;import android.os.DeadObjectException;import android.os.IBinder;import android.os.RemoteException;import android.support.annotation.Nullable;import android.text.TextUtils;import android.util.Log;import org.json.JSONException;import org.json.JSONObject;import java.io.BufferedReader;import java.io.ByteArrayOutputStream;import java.io.InputStream;import java.io.InputStreamReader;import java.net.URL;import java.net.URLConnection;import java.util.HashMap;import java.util.Iterator;import java.util.Set;/** * Created by gavin on 10/30/15. */public class WeatherService extends Service{    private static final String TAG = "[EASIIO]WeatherService";    private HashMap<Integer, IWeatherServiceCallback> m_callback = new HashMap<Integer, IWeatherServiceCallback>();    @Override    public void onCreate() {        super.onCreate();        Log.i(TAG, "onCreate");    }    @Override    public IBinder onBind(Intent intent) {        return new WeatherBinder();    }    private class WeatherBinder extends IWeatherInterface.Stub{        @Override        public void registerCallback(int hash, IWeatherServiceCallback callback) throws RemoteException {            if (m_callback != null && !m_callback.containsKey(hash)){                m_callback.put(hash, callback);                Log.w(TAG, "Add callback hash = " + hash);            }        }        @Override        public void unregisterCallback(int hash) throws RemoteException {            if (m_callback != null) {                Iterator<Integer> it = m_callback.keySet().iterator();                while (it.hasNext()) {                    Integer i_hash = it.next();                    if (i_hash.equals(hash)) {                        it.remove();                        break;                    }                }                Log.i(TAG, "Removed callback: " + hash + " callbacks: " + m_callback.size());            }        }        @Override        public void startGetWeather(final String citypinyin) throws RemoteException {            Log.w(TAG, "startGetWeather");            Thread thread = new Thread(new Runnable() {                @Override                public void run() {                    WeatherBean weather = null;                    String urlStr = "http://apistore.baidu.com/microservice/weather?citypinyin=" + citypinyin;                    try{                        URL url = new URL(urlStr);                        URLConnection connection = url.openConnection();                        connection.connect();                        InputStream inputStream = connection.getInputStream();                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));                        StringBuffer sb = new StringBuffer();                        String str = "";                        while ((str = reader.readLine()) != null)                        {                            sb.append(str).append("\n");                        }                        str = sb.toString();                        Log.w(TAG, "Get weather result = " + str);                        weather = parseJsonForWeather(str);                    } catch (Exception ex){                        Log.e(TAG, "Open url failed, ex : " + ex.getLocalizedMessage());                    }                    if (weather == null){                        weather = new WeatherBean();                        weather.errMsg = "Weather is Null.";                    }                    callbackShowWeather(weather);                }            });            thread.start();        }    }    private void callbackShowWeather(WeatherBean weather){        Set<Integer> clientsHash = null;        if (m_callback != null) {            clientsHash = m_callback.keySet();        }        if (clientsHash == null) {            return;        }        for (Integer hash : clientsHash) {            IWeatherServiceCallback callback = m_callback.get(hash);            if (callback != null){                try {                    callback.showWeather(weather);                } catch (DeadObjectException e_do) {                    Log.w(TAG, "Callback removed. DeadObjectException: hash " + hash);                    m_callback.remove(hash);                } catch (RemoteException re) {                    Log.w(TAG, "RemoteException:", re);                }            }        }    }    private WeatherBean parseJsonForWeather(String str){        if (TextUtils.isEmpty(str)){            return null;        }        try{            WeatherBean weather = new WeatherBean();            JSONObject json = new JSONObject(str);            weather.errNum = json.getInt("errNum");            weather.errMsg = json.getString("errMsg");            if (weather.errNum == 0){                JSONObject dataJson = json.getJSONObject("retData");                weather.city = dataJson.getString("city");                weather.weather = dataJson.getString("weather");                weather.temp = dataJson.getString("temp");                weather.l_tmp = dataJson.getString("l_tmp");                weather.h_tmp = dataJson.getString("h_tmp");                weather.wd = dataJson.getString("WD");                weather.ws = dataJson.getString("WS");            }            return weather;        } catch (JSONException ex){            Log.e(TAG, "parseJson failed : " + ex.getLocalizedMessage());            return null;        }    }}

WeatherBean.java
package com.easiio.test.weather;import android.os.Parcel;import android.os.Parcelable;/** * Created by gavin on 10/30/15. */public class WeatherBean implements Parcelable {    public String city;    public String weather;    public String temp;    public String l_tmp;    public String h_tmp;    public String wd;    public String ws;    public int errNum;    public String errMsg;    public WeatherBean(){    }    @Override    public String toString(){        StringBuilder builder = new StringBuilder();        builder.append("Result:").append(errMsg).append("\n")                .append("City = ").append(city).append("\n")                .append("Weather = ").append(weather).append("\n")                .append("Temp = ").append(temp).append("\n")                .append("Low Temp = ").append(l_tmp).append("\n")                .append("High Temp = ").append(h_tmp).append("\n")                .append("WD = ").append(wd).append("\n")                .append("WS = ").append(ws).append("\n");        return builder.toString();    }    private Object mLock = new Object();    private WeatherBean(Parcel in){        readFromParcel( in );    }    public void readFromParcel( Parcel in ){        synchronized (mLock) {            errNum = in.readInt();            errMsg = in.readString();            city = in.readString();            weather = in.readString();            temp = in.readString();            l_tmp = in.readString();            h_tmp = in.readString();            wd = in.readString();            ws = in.readString();        }    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        synchronized (mLock) {            dest.writeInt(errNum);            dest.writeString(errMsg);            dest.writeString(city);            dest.writeString(weather);            dest.writeString(temp);            dest.writeString(l_tmp);            dest.writeString(h_tmp);            dest.writeString(wd);            dest.writeString(ws);        }    }    public static final Creator<WeatherBean> CREATOR = new Creator<WeatherBean>() {        public WeatherBean createFromParcel( Parcel in ){            return new WeatherBean(in);        }        public WeatherBean[] newArray( int size){            return new WeatherBean[size];        }    };}

运行后界面大致如下:

 

基本上是这样子的了,欢迎交流,工程源码可到github下载

https://github.com/zjc3909/TestWeather.git

0 0
原创粉丝点击