该方法不能保证在所有机型上有效,而且除非在必要时,否则不建议写这样的流氓软件。特别是谷歌在android7.0以后对管理加强,想要保活Service其实已经变得不太可能了,谷歌这样做无疑是为了减少流氓软件的数量,这样做也是可取的。
一、开机广播监听
Android系统启动完成后会自动发出启动完成广播(android.intent.action.BOOT_COMPLETED),
所有注册了接收启动完成广播的接收器(BroadcastReceiver)都会收到此广播.
①编写一个继承BroadcastReceiver的类,接受系统启动完成广播.
package com.example.systemtest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* 系统启动完成广播接收器
* #
* @author Lone_Wolf
*/
public class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
//example:启动程序
Intent start = new Intent(context, MainActivity.class);
start.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//
context.startActivity(start);
}
}
}
②在AndroidManifest.xml文件里注册广播接收器.
③添加相应权限.
二、android:process属性说明
在Android应用的声明文件Manifest.xml中有时候会对相关的服务标签设置一个android:process=”:remote”,这个属性有什么作用呢?下面笔者就将自己整理的知识和大家分享。
在Android的帮助文档中我们可以了解到,一般情况下一个服务没有自己独立的进程,它一般是作为一个线程运行于它所在的应用的进程中。但是也有例外,Android声明文件中的android:process属性却可以为任意组件包括应用指定进程,换句话说,通过在声明文件中设置android:process属性,我们可以让组件(例如Activity, Service等)和应用(Application)创建并运行于我们指定的进程中。下面是相关资料和笔者翻译。
如果我们需要让一个服务在一个远端进程中运行(而不是标准的它所在的apk的进程中运行),我们可以在声明文件中这个服务的标签中通过android:process属性为其指定一个进程。
注意:这里选择”remote”这个名字是随意主观的,你能用其他名字来让这个服务在另外的进程中运行。冒号’:’这个前缀将把这个名字附加到你的包所运行的标准进程名字的后面作为新的进程名称。例如:一个应用的包名为com.aoyousatuo.example, 则本例中服务将运行的新进程的名称为com.aoyousatuo.example:remote.(注意,如果声明文件中的组件或者应用没有指定这个属性则默认应用和其组件将相应运行在以其包名命名的进程中).android:process 服务所在进程的名字。通常,一个应用的所有组件都运行在系统为这个应用所创建的默认进程中。这个默认进程是用这个应用的包名来命名的。
标签的process属性可以设置成和所有组件都不同的默认值。但是这些组件可以通过设置自己的process值来覆写这个默认值,这样可以让你的应用跨多进程运行。
如果被设置的进程名是以一个冒号开头的,则这个新的进程对于这个应用来说是私有的,当它被需要或者这个服务需要在新进程中运行的时候,这个新进程将会被创建。如果这个进程的名字是以小写字符开头的,则这个服务将运行在一个以这个名字命名的全局的进程中,当然前提是它有相应的权限。这将允许在不同应用中的各种组件可以共享一个进程,从而减少资源的占用。
例如一个应用运行在进程com.aoyousatuo.example中,android:process属性设置为com.rabbit.run,则新的进程名字为com.rabbit.run.
三、使用AIDL和.stub
stub类是为了方便client,service交互而生成出来的代码。
AIDL(Android Interface Definition Language Android接口定义语言)实现进程间通信,尤其是在涉及多进程并发情况下的进程间通信
aidl会在gen中自动生成一个同名的IaidlData.java接口文件,该接口文件包含一个抽象类stub,其继承了android.os.Binder、
实现IaidlData接口故,我们实际需要实现的是Stub抽象类。注意这个Stub抽象类要在生成aidl文件之后,编译一下项目才会产生。
具体参考:AndroidStudio实现AIDL
四、完整代码
1、AndroidManifest.xml
2、开机广播
public class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
//example:启动程序
Intent start = new Intent(context, MainActivity.class);
start.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//
context.startActivity(start);
}
}
}
3、AIDL文件
interface IServiceAidlInterface {
String getServiceName();
}
4、本地服务
public class LocalService extends Service {
MyBinder binder;
MyConn conn;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
binder = new MyBinder();
conn = new MyConn();
}
class MyBinder extends IServiceAidlInterface.Stub {
@Override
public String getServiceName() throws RemoteException {
return LocalService.class.getSimpleName();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
show();
Toast.makeText(LocalService.this, " 本地服务活了", Toast.LENGTH_SHORT).show();
this.startService(new Intent(LocalService.this,RomoteService.class));
this.bindService(new Intent(LocalService.this,RomoteService.class),conn, Context.BIND_IMPORTANT);
return START_STICKY;
}
class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("box", "绑定上了远程服务");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("box", "远程服务被干掉了");
Toast.makeText(LocalService.this, "远程服务挂了", Toast.LENGTH_SHORT).show();
//开启远程服务
LocalService.this.startService(new Intent(LocalService.this,RomoteService.class));
//绑定远程服务
LocalService.this.bindService(new Intent(LocalService.this,RomoteService.class),conn,Context.BIND_IMPORTANT);
}
}
@Override
public void onDestroy() {
super.onDestroy();
//开启远程服务
LocalService.this.startService(new Intent(LocalService.this,RomoteService.class));
//绑定远程服务
LocalService.this.bindService(new Intent(LocalService.this,RomoteService.class),conn,Context.BIND_IMPORTANT);
}
private void show() {
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Toast.makeText(LocalService.this, "本地服务正常", Toast.LENGTH_SHORT).show();
super.handleMessage(msg);
}
};
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
timer.schedule(task, 10000, 10000);
}
}
5、远程服务
public class RomoteService extends Service {
MyConn conn;
MyBinder binder;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
conn = new MyConn();
binder = new MyBinder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
show();
Toast.makeText(this, " 远程服务活了", Toast.LENGTH_SHORT).show();
this.bindService(new Intent(this, LocalService.class), conn, Context.BIND_IMPORTANT);
return START_STICKY;
}
class MyBinder extends IServiceAidlInterface.Stub {
@Override
public String getServiceName() throws RemoteException {
return RomoteService.class.getSimpleName();
}
}
class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("box", "绑定本地服务成功");
// Toast.makeText(RomoteService.this, "绑定本地服务成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("box", "本地服务被干掉了");
Toast.makeText(RomoteService.this, "本地服务挂了", Toast.LENGTH_SHORT).show();
//开启本地服务
RomoteService.this.startService(new Intent(RomoteService.this, LocalService.class));
//绑定本地服务
RomoteService.this.bindService(new Intent(RomoteService.this, LocalService.class), conn, Context.BIND_IMPORTANT);
}
}
@Override
public void onDestroy() {
super.onDestroy();
//开启本地服务
RomoteService.this.startService(new Intent(RomoteService.this, LocalService.class));
//绑定本地服务
RomoteService.this.bindService(new Intent(RomoteService.this, LocalService.class), conn, Context.BIND_IMPORTANT);
}
private void show() {
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Toast.makeText(RomoteService.this, "远程服务正常", Toast.LENGTH_SHORT).show();
super.handleMessage(msg);
}
};
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
timer.schedule(task, 10000, 10000);
}
}
6、MainActivity.java
public class MainActivity extends ActivityBase {
private ActivityMainBinding mBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = ActivityMainBinding.inflate(LayoutInflater.from(this));
setMainView(mBinding.getRoot());
startService(new Intent(this, LocalService.class));
}
}
参考:
Android Service保活方法总结(不被杀死)双进程守护
双进程守护
AndroidStudio实现AIDL
Android中 .stub类的使用