最近和同事讨论微信杀死进程结束后,还能收到好友发来的微信这功能。以前一直用着,没有去研究这技术。最近项目提前完成,有了点空闲时间,就研究这技术。然后写了个demo,试着运行,发现OK了。在这给朋友分享下,可能有不够好的地方,欢迎大神们指出。
首先,正常下,当我们退出程序或手动杀死后,我们的程序就停止运行了。或者不退出在后台运行时,使用360加速球清理时,也会杀死我们的进程。个人理解360加速时,把不被添加信任的进程用一个for循环,在循环里一个个的kill。于是有了一种思路,在我们应用中开启两个进程,当一个进程被杀死时,另外一个进程启动被杀死的进程,相互守护。沿着这思路,开始撸代码。
1.创建两个Service:LocationService和RemoteServices
LocationService代表主进程,RemoteServices代表守护进程。这里要实现RemoteServices是另外的进程需要在Androidmanifest中配置:
<service android:name=".RemoteServices" android:enabled="true" android:exported="true" android:process=".RemoteServices" />
接下来是要对这两个service相互绑定,相互监听对方的状态。两个进程中的通讯我们可以使用aidl,这里不对aidl细讲,不了解的朋友可以去查下。
创建一个ProcessIdle.aidl文件
// ProcessIdle.aidl package inner; interface ProcessIdle { String getProcessName(); }
这里只定义一个方法getProcessName(),用于获取进程名。接下来编写LocationService和RemoteServices两个类。
RemoteServices
public class RemoteServices extends Service { MyBinder myBinder; MyConn myConn; @Nullable @Override public IBinder onBind(Intent intent) { return myBinder; } @Override public int onStartCommand(Intent intent, int flags, int startId) { showWindow("RemoteServices======"); Toast.makeText(this, "RemoteServices=======onStartCommand", Toast.LENGTH_SHORT).show(); boolean isLocationServiceRunning = Util.isServiceRunning(this, "com.example.zonglijia.killapp.LocationService"); if (!isLocationServiceRunning) { RemoteServices.this.startService(new Intent(RemoteServices.this, LocationService.class)); } RemoteServices.this.bindService(new Intent(RemoteServices.this, LocationService.class), myConn, Context.BIND_IMPORTANT); return START_STICKY; } @Override public void onCreate() { Toast.makeText(this, "RemoteServices=======onCreate", Toast.LENGTH_SHORT).show(); Log.i("RemoteServices", "onCreate"); super.onCreate(); if (myBinder == null) myBinder = new MyBinder(); if (myConn == null) { myConn = new MyConn(); } // showWindow("RemoteServices======"); } class MyBinder extends ProcessIdle.Stub { @Override public String getProcessName() throws RemoteException { return "RemoteServices"; } } class MyConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { Toast.makeText(RemoteServices.this, "已连接本地服务", Toast.LENGTH_LONG).show(); } @Override public void onServiceDisconnected(ComponentName name) { Toast.makeText(RemoteServices.this, "断开连接本地服务", Toast.LENGTH_LONG).show(); RemoteServices.this.startService(new Intent(RemoteServices.this, LocationService.class)); RemoteServices.this.bindService(new Intent(RemoteServices.this, LocationService.class), myConn, Context.BIND_IMPORTANT); } } WindowManager mWM; TextView view; private void showWindow(String text) { mWM = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.format = PixelFormat.TRANSLUCENT; params.type = WindowManager.LayoutParams.TYPE_TOAST; params.setTitle("Toast"); params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; // view = LayoutInflater.from(this).inflate(R.layout.window_show, null); // TextView textView = (TextView) view.findViewById(R.id.text); view = new TextView(this); view.setText(text); view.setTextColor(Color.RED); mWM.addView(view, params); } @Override public void onDestroy() { Toast.makeText(this, "RemoteServices=======onDestroy", Toast.LENGTH_SHORT).show(); Log.i("RemoteServices", "onDestroy"); RemoteServices.this.startService(new Intent(RemoteServices.this, LocationService.class)); RemoteServices.this.bindService(new Intent(RemoteServices.this, LocationService.class), myConn, Context.BIND_IMPORTANT); super.onDestroy(); } }
LocationService
public class LocationService extends Service { MyBinder myBinder; MyConn2 myConn2; @Nullable @Override public IBinder onBind(Intent intent) { return myBinder; } @Override public int onStartCommand(Intent intent, int flags, int startId) { showWindow("LocationServices======"); Toast.makeText(this, "LocationService=======onStartCommand", Toast.LENGTH_SHORT).show(); boolean isRemoteServiceRunning = Util.isServiceRunning(this, "com.example.zonglijia.killapp.RemoteServices"); if (!isRemoteServiceRunning) { LocationService.this.startService(new Intent(LocationService.this, RemoteServices.class)); } LocationService.this.bindService(new Intent(LocationService.this, RemoteServices.class), myConn2, Context.BIND_IMPORTANT); return START_STICKY; } @Override public void onCreate() { Toast.makeText(this, "LocationService=======onCreate", Toast.LENGTH_SHORT).show(); Log.i("LocationService", "onCreate"); super.onCreate(); if (myBinder == null) myBinder = new MyBinder(); if (myConn2 == null) { myConn2 = new MyConn2(); } // showWindow("LocationServices======"); } class MyBinder extends ProcessIdle.Stub { @Override public String getProcessName() throws RemoteException { return "LocationProcess"; } } class MyConn2 implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { Toast.makeText(LocationService.this, "已连接远程服务", Toast.LENGTH_LONG).show(); } @Override public void onServiceDisconnected(ComponentName name) { Toast.makeText(LocationService.this, "断开连接远程服务", Toast.LENGTH_LONG).show(); LocationService.this.startService(new Intent(LocationService.this, RemoteServices.class)); LocationService.this.bindService(new Intent(LocationService.this, RemoteServices.class), myConn2, Context.BIND_IMPORTANT); } } WindowManager mWM; TextView view; private void showWindow(String text) { mWM = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.format = PixelFormat.TRANSLUCENT; params.type = WindowManager.LayoutParams.TYPE_TOAST; params.setTitle("Toast"); params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; // view = LayoutInflater.from(this).inflate(R.layout.window_show, null); // TextView textView = (TextView) view.findViewById(R.id.text); view = new TextView(this); view.setText(text); view.setTextColor(Color.RED); mWM.addView(view, params); } @Override public void onDestroy() { Log.i("LocationService", "onDestroy"); Toast.makeText(this, "LocationService=======onDestroy", Toast.LENGTH_SHORT).show(); LocationService.this.startService(new Intent(LocationService.this, RemoteServices.class)); LocationService.this.bindService(new Intent(LocationService.this, RemoteServices.class), myConn2, Context.BIND_IMPORTANT); super.onDestroy(); } }
这两个类的代码内容几乎相同,其中的逻辑是先判断另一进程是否在运行,如果否就先启动,然后再进行绑定。当监听到另一进程断开时,就再次启动并绑定。就是下面的代码块
class MyConn2 implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { Toast.makeText(LocationService.this, "已连接远程服务", Toast.LENGTH_LONG).show(); } @Override public void onServiceDisconnected(ComponentName name) { Toast.makeText(LocationService.this, "断开连接远程服务", Toast.LENGTH_LONG).show(); LocationService.this.startService(new Intent(LocationService.this, RemoteServices.class)); LocationService.this.bindService(new Intent(LocationService.this, RemoteServices.class), myConn2, Context.BIND_IMPORTANT); } }
好了,大致的思路就是这样,细节的处理代码就没再贴,需要的朋友可以在下面留言,可以发邮箱给你们。
运行测试后,在5.0以下的机型都测试成功,5.0以上机型除了在手动杀死进程时,测试失败,其它方式杀死都测试成功。对于在5.0以上的机型兼容,会再下一篇分享