Android多进程共享单例实现之——AIDL方式
来源:互联网 发布:excel网页数据抓取vba 编辑:程序博客网 时间:2024/06/10 19:58
Android多进程共享单例实现之——AIDL方式
概述
前一段时间说到单例在Android多进程中失效的问题(变成多例),最近花了一点时间用Android AIDL进程间通信的方式验证了一下可行性,结果表明,这种方式能实现单例在不同的进程中共享的功能。
实现思想
针对每一个单例,创建一个对应的Service,并在单独进程运行,在Service中创建唯一的实例,所有不同进程针对单例的操作均通过Service的AIDL接口调用,这样就保证了不同的进程操作的是同一个单例实例。
本测试应用使用的类和接口说明:
ProcessXActivity 运行在主进程的主Activity
ProcessYActivity 运行在:processY进程的ActivityProcessXService 运行在:processService进程的ServiceIProcessXService ProcessXService服务的AIDL接口SingletonTest 单例实现类
BaseActivity Activity基类,实现Service绑定
具体实现类
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.pj.sh"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".TestHomeActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> </activity> <activity android:name=".multiprocess.ProcessXActivity" android:label="@string/title_activity_process_x"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".multiprocess.ProcessYActivity" android:label="@string/title_activity_process_y" android:process=":processY" /> <service android:name=".multiprocess.ProcessXService" android:enabled="true" android:exported="true" android:process=":processService"></service> </application></manifest>
BaseActivity.java
package com.pj.sh.multiprocess;import android.app.Activity;import android.app.ActivityManager;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;/** * Created by sunhong on 2016/12/28. */public class BaseActivity extends Activity { private boolean flag; protected IProcessXService mService; protected ServiceConnection connection; protected int getProcessPid() { return android.os.Process.myPid(); } protected String getProcessName(Context context) { String name = ""; int pid = android.os.Process.myPid(); ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningAppProcessInfo process : activityManager.getRunningAppProcesses()) { if(process.pid == pid) { name = process.processName; } } return name; } @Override protected void onResume() { super.onResume(); bindService(); } @Override protected void onPause() { super.onPause(); unBind(); } private void bindService(){ Intent intent = new Intent(BaseActivity.this, ProcessXService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); } private void unBind(){ if(flag == true){ unbindService(conn); flag = false; } } private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub mService = IProcessXService.Stub.asInterface(service); flag = true; } };}
package com.pj.sh.multiprocess;import android.content.Intent;import android.os.Bundle;import android.app.Activity;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.TextView;import com.pj.sh.R;public class ProcessXActivity extends BaseActivity implements View.OnClickListener { private TextView mTXInstance; private Button mBtnGetInstance; private Button mBtnGo2ProcessY; private Button mBtnGetInstanceByThread; private Button mBtnGetCount; private Button mBtnSetCount; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_process_x); startService(new Intent(this, ProcessXService.class)); Log.d("process-test", "当前进程:" + getProcessPid() + "/" + getProcessName(this)); mTXInstance = (TextView) findViewById(R.id.id_tx_singleton); mBtnGetInstance = (Button) findViewById(R.id.id_btn_get_instance); mBtnGo2ProcessY = (Button) findViewById(R.id.id_btn_goto_processy); mBtnGetInstanceByThread = (Button) findViewById(R.id.id_btn_thread_get_instance); mBtnGetCount = (Button) findViewById(R.id.id_btn_get_count); mBtnSetCount = (Button) findViewById(R.id.id_btn_set_count); mBtnGetInstance.setOnClickListener(this); mBtnGo2ProcessY.setOnClickListener(this); mBtnGetInstanceByThread.setOnClickListener(this); mBtnGetCount.setOnClickListener(this); mBtnSetCount.setOnClickListener(this); } @Override public void onClick(View v) { switch(v.getId()) { case R.id.id_btn_get_instance: mTXInstance.setText("processX:" + SingletonTest.getInstance()); break; case R.id.id_btn_goto_processy: startActivity(new Intent(this, ProcessYActivity.class)); break; case R.id.id_btn_thread_get_instance: final String tmp = mTXInstance.getText().toString(); new Thread() { @Override public void run() { super.run(); final String tx = tmp + "\n" + "processX:" + Thread.currentThread().getId() + ":" + SingletonTest.getInstance(); runOnUiThread(new Runnable() { @Override public void run() { mTXInstance.setText(tx); } }); } }.start(); break; case R.id.id_btn_get_count: if(mService != null) { try { int count = mService.getCount(); mTXInstance.setText("count:" + count); Log.d("process-test", "获取count值:" + count); } catch (RemoteException e) { e.printStackTrace(); } } break; case R.id.id_btn_set_count: if(mService != null) { try { mService.setCount(); int count = mService.getCount(); mTXInstance.setText("count:" + count); Log.d("process-test", "设置count值:" + count); } catch (RemoteException e) { e.printStackTrace(); } } break; default: break; } }}
ProcessYActivity.java
package com.pj.sh.multiprocess;import android.content.Intent;import android.os.Bundle;import android.app.Activity;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.TextView;import com.pj.sh.R;public class ProcessYActivity extends BaseActivity implements View.OnClickListener{ private TextView mTXInstance; private Button mBtnGetInstance; private Button mBtnGo2ProcessX; private Button mBtnGetCount; private Button mBtnSetCount; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_process_y); Log.d("process-test", "当前进程:" + getProcessPid() + "/" + getProcessName(this)); mTXInstance = (TextView) findViewById(R.id.id_tx_singleton); mBtnGetInstance = (Button) findViewById(R.id.id_btn_get_instance); mBtnGo2ProcessX = (Button) findViewById(R.id.id_btn_goto_processx); mBtnGetCount = (Button) findViewById(R.id.id_btn_get_count); mBtnSetCount = (Button) findViewById(R.id.id_btn_set_count); mBtnGetInstance.setOnClickListener(this); mBtnGo2ProcessX.setOnClickListener(this); mBtnGetCount.setOnClickListener(this); mBtnSetCount.setOnClickListener(this); } @Override public void onClick(View v) { switch(v.getId()) { case R.id.id_btn_get_instance: mTXInstance.setText("processY:" + SingletonTest.getInstance()); break; case R.id.id_btn_goto_processx: startActivity(new Intent(this, ProcessXActivity.class)); break; case R.id.id_btn_get_count: if(mService != null) { try { int count = mService.getCount(); mTXInstance.setText("count:" + count); Log.d("process-test", "获取count值:" + count); } catch (RemoteException e) { e.printStackTrace(); } } break; case R.id.id_btn_set_count: if(mService != null) { try { mService.setCount(); int count = mService.getCount(); mTXInstance.setText("count:" + count); Log.d("process-test", "设置count值:" + count); } catch (RemoteException e) { e.printStackTrace(); } } break; default: break; } }}
ProcessXService.java
package com.pj.sh.multiprocess;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.os.RemoteException;public class ProcessXService extends Service { private ProcessXServiceBinder mServiceBinder = null; private SingletonTest mSingletonInstance = null; private ProcessXService mServiceInstance = null; public ProcessXService() { } private ServiceBinder singleBinder = new ServiceBinder(); @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return mServiceBinder; } @Override public void onDestroy() { super.onDestroy(); mServiceBinder = null; mSingletonInstance = null; mServiceInstance = null; } @Override public void onCreate() { super.onCreate(); mServiceBinder = new ProcessXServiceBinder(); mSingletonInstance = SingletonTest.getInstance(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { mServiceInstance = this; return super.onStartCommand(intent, flags, startId); } private int getCount() { return mSingletonInstance.getCount(); } private void setCount() { mSingletonInstance.setCount(); } public class ProcessXServiceBinder extends IProcessXService.Stub { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public int getCount() throws RemoteException { return mServiceInstance.getCount(); } @Override public void setCount() throws RemoteException { mServiceInstance.setCount(); } } public class ServiceBinder extends Binder { public ProcessXService getService() { return ProcessXService.this; } }}
IProcessXService.aidl
// IProcessXService.aidlpackage com.pj.sh.multiprocess;// Declare any non-default types here with import statementsinterface IProcessXService { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); int getCount(); void setCount();}
SingletonTest.java
package com.pj.sh.multiprocess;/** * Created by sunhong on 2016/12/28. * Singleton Test */public class SingletonTest { volatile private static SingletonTest mInstance; volatile private int count = 0; private SingletonTest() { } public static SingletonTest getInstance() { if (mInstance == null) { synchronized (SingletonTest.class) { if (mInstance == null) { mInstance = new SingletonTest(); } } } return mInstance; } public void setCount() { count++; } public int getCount() { return count; }}
运行结果
Log运行结果表明,一个进程对count值的修改对另一个进程可见,说明操作的是同一个实例。
12-28 17:35:20.574 13677-13677/com.pj.sh D/process-test: 当前进程:13677/com.pj.sh12-28 17:35:43.074 13677-13677/com.pj.sh D/process-test: 获取count值:012-28 17:35:44.984 13677-13677/com.pj.sh D/process-test: 设置count值:112-28 17:35:46.614 13677-13677/com.pj.sh D/process-test: 设置count值:212-28 17:35:47.254 13677-13677/com.pj.sh D/process-test: 设置count值:312-28 17:35:50.064 14484-14484/com.pj.sh:processY D/process-test: 当前进程:14484/com.pj.sh:processY12-28 17:35:55.059 14484-14484/com.pj.sh:processY D/process-test: 获取count值:312-28 17:35:56.794 14484-14484/com.pj.sh:processY D/process-test: 设置count值:412-28 17:35:57.069 14484-14484/com.pj.sh:processY D/process-test: 设置count值:512-28 17:35:57.254 14484-14484/com.pj.sh:processY D/process-test: 设置count值:612-28 17:35:59.289 13677-13677/com.pj.sh D/process-test: 当前进程:13677/com.pj.sh12-28 17:36:02.749 13677-13677/com.pj.sh D/process-test: 获取count值:612-28 17:36:03.939 13677-13677/com.pj.sh D/process-test: 设置count值:712-28 17:36:04.149 13677-13677/com.pj.sh D/process-test: 设置count值:8
优缺点
优点:实现直观,容易理解,做过AIDL远程调用的同学都不陌生
缺点:需要一个单独的Service包装单例实现的类
其它实现方式有没有? 欢迎大家一起讨论分享
0 0
- Android多进程共享单例实现之——AIDL方式
- android 多进程之 AIDL
- Android 多进程通讯之 AIDL
- Android 多进程通信之AIDL
- 9.Android中的IPC方式——Bundle、文件共享、Messenger、AIDL、Content-Provider
- android学习之使用AIDL实现进程间的通讯
- Android 进程通信之AIDL
- Android进程通信之AIDL
- Android 进程通信之AIDL
- Android之aidl进程通信
- Android内存共享、进程间高性能IO、手动实现 Binder IPC、Aidl例子
- Android进程间通讯——AIDL
- android进程间的通信方式AIDL
- Android中的IPC——AIDL方式
- Android 设计模式之单例实现方式
- MFC使用共享段实现单例进程
- android 使用AIDL实现进程间通信
- Android Aidl实现进程间通信
- 国际化
- 1061. 判断题(15)
- Android APK反编译就这么简单 详解(附图)
- react-native控件
- apache kafka_2.11-0.10.1.0实用命令
- Android多进程共享单例实现之——AIDL方式
- SQL基础语句汇总
- HDS简单介绍
- 消息红点BadgeView
- 如何解决JavaScript中UUID作为方法参数在方法中无法传递而数字却正常传递的问题
- 【算法】A+B problem 用位运算完成两数相加
- System.getProperty()参数手册
- 框架之Struts2的使用(传参、获取参数及验证输入)
- html中三种路径详谈