1、保证 service 不被杀掉
StartCommond 的几个常量参数简介:
a、START_STICKY
在运行 onStartCommand 后 service 进程被 kill 后将保留在开始状态,但是不保留传入的intent。
之后 service 就会再次尝试重新创建,因为保留在开始状态,在创建 service 后将保证调用 onstartCommand,如果没有传递任何开始命令给 service,那将获取到 null 的 intent。
b、START_NOT_STICKY
在运行 onStartCommand 后 service 进程被 kill 后,并且没有新的 intent 传递给它。
Service 将移出开始状态,并且直到新的方法(startService)调用才重新创建。
因为如果没有传递任何未决定的 intent 那么 service 是不会启动,也就是期间 onstartCommand 不会接收到任何 null 的 intent。
c、START_REDELIVER_INTENT
在运行 onStartCommand 后 service 进程被 kill 后,系统将会再次启动 service,并传入最后一个 intent 给 onstartCommand。
直到调用 stopSelf(int) 才停止传递 intent。如果在被 kill 后还有未处理好的 intent,那被 kill 后服务还是会自动启动。因此 onstartCommand 不会接收到任何 null 的 intent。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
flags = START_STICKY;
return super.onStartCommand(intent, flags, startId);
}
2、如何结束线程
a、stop 强制停止
Android 的线程类本身提供了一些公共方法去结束线程,但不安全不建议使用
final void stop();
b、线程里的 run 函数执行完后线程会自行销毁
c、手动停止
在 run 里设置标志先停止运行,再调用 Thread.interrupt()
注:在 run 没有停止时调用 Thread.interrupt() 是没有效果的
示例:
a、加入一个成员变量, 在程序的循环里轮流去检查这个变量,变量变化时,就会退出这个线程
public class StopThread extends Thread {
private boolean _run = true;
public void stopThread(boolean run) {
this._run = !run;
}
@Override
public void run() {
while(_run) {
// 相应处理
}
}
}
b、方法 a 虽然可以取消线程,但是在有阻塞线程语句的时候会存在问题
比如设计到 Socket 的阻塞语句,虽然 java 提供异步 io 但是异步 io 是在程序里不断去查询有没有消息,耗电量较大
Java interrupt()方法且该方法是安全的,该方法可以将阻塞的线程唤醒过来,但不能将非阻塞的线程中断
while(!this.isInterrupted()) {
// 相应处理
}
public static void main(String[] args) {
StopThread thread=new StopThread();
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
System.out.println(interrupt);
}
c、Android 在自己的 Api 中加入了 Process 类,可以直接结束进程,也就是当前线程所在的 JVM
final static void killProcess(int pid)
其中 pid 可以通过 Process.mypid() 获取,但这样终结的是整个程序
如果该线程处在不可中断状态下,就是没有调用上述 api,那么 java 只是设置一下该线程的 interrupt 状态,其他事情都不会发生,如果该线程之后会调用行数阻塞 API,那到时候线程会马会上跳出,并抛出 InterruptedException,接下来的事情就跟第一种状况一致了。如果不会调用阻塞 API,那么这个线程就会一直执行下去。
readCacheThread = new Thread(){
public void run() {
try {
Method getPackageSizeInfo = pm.getClass().getMethod(
"getPackageSizeInfo", String.class,
IPackageStatsObserver.class);
for (AppInfoItem item : installedApp) {
sleep(1); // interrupt后会抛异常,这样就可以提前结束线程
getPackageSizeInfo.invoke(pm, item.packageName, pkgsizeobserver);
}
for (AppInfoItem item : systemApp) {
sleep(1);
getPackageSizeInfo.invoke(pm, item.packageName, pkgsizeobserver);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
return;
}
};
};
readCacheThread.start();
在需要中断线程的地方调用:
if(readCacheThread != null && readCacheThread.isAlive()){
readCacheThread.interrupt();
}
refer:
https://blog.csdn.net/mad1989/article/details/22492519
https://blog.csdn.net/lyf_007217/article/details/8542133