Android多进程重启app

跨进程:Client进程只不过是持有了Server端的代理;代理对象协助驱动完成了跨进程通信。

对于一些需求,比如切换语言重启应用,如果项目中很多地方有通过Application.getResource().getString(int stringRes)

在部分手机可能存在语言没有切换的问题,比较简单的能解决这个问题的方式是,杀死当前进程,重新启动app。

具体实现:

1、子进程服务

/**
 * 跨进程重启,避免用Application获取的文案,切换语言后文案未更新问题
 */
public class RestartService extends Service {
    public static final int MSG_CONNECTED = 1;
    public static final int MSG_KILL_APP = 2;
    public static final int MSG_RESTART_APP = 3;
    private String mPackageName;//要重启的app的包名
    @Override
    public IBinder onBind(Intent intent) {
        if (intent != null) {
            mPackageName = intent.getStringExtra(AppRestartControl.PACKAGE_BUNDLE_KEY);
        }
        Messenger restartMessenger = new Messenger(new ServerMsgHandler(this, mPackageName));
        return restartMessenger.getBinder();
    }

    private static class ServerMsgHandler extends Handler {
        private Context mContext;
        private String mPackageName;
        public ServerMsgHandler(Context context, String packageName) {
            mContext = context;
            mPackageName = packageName;
        }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_CONNECTED://收到app进程发来的消息,binder连接成功
                    try {
                        msg.replyTo.send(Message.obtain(null, MSG_KILL_APP));//通知app进程自杀
                    } catch (RemoteException e1) {
                        e1.printStackTrace();
                    }
                    break;
                case MSG_RESTART_APP://收到app进程自杀前发出的重启消息
                    ThreadPoolFactory.instance().fixExecutor(new Runnable() {//避免子进程anr
                        @Override
                        public void run() {
                            try {
                                Logger.d("restart", "============准备重启");
                                Thread.sleep(1000);//延迟1秒,等app进程死透了再重启
                                Logger.d("restart", "============重启");
                                DeviceUtils.startApp(mContext, mPackageName);
                                Logger.d("restart", "============重启结束");
                                Thread.sleep(1000);//延迟1秒
                                Process.killProcess(Process.myPid());//重启进程自杀
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    });
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
}

2、app进程中调用的api

/**
 * app跨进程重启包装类
 */
public class AppRestartControl {
    public static final String PACKAGE_BUNDLE_KEY = "package_bundle_key";
    private Messenger mServerMsger = null;//用于包装从重启进程返回的binder的Messenger
    private Context mContext;

    public AppRestartControl(Context context) {
        mContext = context;
    }

    public void doBindService(String packageName) {
        ThreadPoolFactory.instance().fixExecutor(new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent(mContext, RestartService.class);
                intent.putExtra(PACKAGE_BUNDLE_KEY, packageName);
                mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
            }
        });
    }

    public void unBindService(Context context) {
        context.unbindService(mConnection);
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            mServerMsger = new Messenger(service);//包装重进进程的Binder,通过该Messenger可以使当前进程与重启进程交互,使当前进程发送消息给重启进程
            try {
                Message msg = Message.obtain(null, RestartService.MSG_CONNECTED);
                msg.replyTo = getClientMessenger();//消息的replyTo指向当前进程中创建的Messenger,方便接收重启进程发过来的消息
                mServerMsger.send(msg);//消息发送给重启进程
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName className) {
            mServerMsger = null;
        }
    };

    /** 创建接收重启进程消息的Messenger */
    private Messenger getClientMessenger() {
        ClientMsgHandler handler = new ClientMsgHandler(mServerMsger);
        Messenger clientMsger = new Messenger(handler);
        handler.setClientMsger(clientMsger);
        return clientMsger;
    }

    private static class ClientMsgHandler extends Handler {
        private Messenger serverMsger;//用于包装从重启进程返回的binder的Messenger
        private Messenger clientMsger;

        public ClientMsgHandler(Messenger serverMsger) {
            this.serverMsger = serverMsger;
        }

        public void setClientMsger(Messenger clientMsger) {
            this.clientMsger = clientMsger;
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case RestartService.MSG_KILL_APP:
                    Message restartMsg = Message.obtain(null, RestartService.MSG_RESTART_APP);
                    restartMsg.replyTo = clientMsger;
                    try {
                        if (serverMsger != null) {
                            serverMsger.send(restartMsg);
                        }
                        Process.killProcess(Process.myPid());
                        System.exit(0);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
}

3、在Manifest中注册重启服务,并标明子进程

<service android:name="xxx.restart.RestartService"
         android:process=":restart"/>

4、调用方式

/**重启app*/
public static void rebootApp(final Context context) {
    AppRestartControl restart = new AppRestartControl(context);
    restart.doBindService(context.getPackageName());
}

public static void startApp(Context context,String packageName) throws Exception {
    PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, 0);
    Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
    resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    resolveIntent.setPackage(pi.packageName);
    List<ResolveInfo> apps = context.getPackageManager().queryIntentActivities(resolveIntent, 0);
    ResolveInfo ri = apps.iterator().next();
    if (ri != null) {
        String className = ri.activityInfo.name;
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        ComponentName cn = new ComponentName(packageName, className);
        intent.setComponent(cn);
        context.startActivity(intent);
    }
}

猜你喜欢

转载自blog.csdn.net/u010577768/article/details/80487916
今日推荐