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();
}