Android 的 IntentService 与 Service

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/o279642707/article/details/82222654

前言

之前一直用IntentService,Service,而且网上说IntentService比Service要好,好在那里?,工作中遇到关于IntentService的问题,才总结,亡羊补牢为时不晚。

背景:

做启动页广告,在app 启动时候开启一个IntentService 去下载广告Json,并缓存广告图片url,广告时间等信息,在下次开屏时候,如果有广告的缓存的url,就进行开屏广告展示。
在IntentService中有两个网络请求,现实情况是同样的代码在Intentservice 中不能缓存广告url到sp中,但是修改为Service就可以正常展示广告,并缓存到sp中。

网上摘抄:

 1. Service不是一个单独的进程 ,它和应用程序在同一个进程中。

 2. Service不是一个线程,所以我们应该避免在Service里面进行耗时的操作

 3.  每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程), 也就是说Handler对象初始化
      后,就默认与对它初始化的进程的消息队列绑定,因此可以利用Handler所包含的消息队列,制
      定一些操作的顺序。

[问题]

那么为什么我不直接用Thread而要用Service呢?

翻开一些类似IntentService的blog大致有5点疑问

猜想一,线程嵌套,内部会不会等待所有线程执行完后,调用stop线程,
线程A stop后,线程B 内部逻辑是否会执行

线程a{

线程B{…. }
线程C{…. }

stop线程A
}

代码:

package com.tseng.alldilaog.guess;

public class Threademo {


    static Runnable runnable = null;
    static Thread thread = null;

    public static void main(String[] args) {

        setRun();
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread threadb = new Thread(runnable, "THREAD_B");
                threadb.start();
                System.out.println(Thread.currentThread().getName() + "  执行时间:");
                thread.stop();
            }
        }, "Thread_A");
        thread.start();

    }

    private static void setRun() {
        runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    System.out.println(Thread.currentThread().getName() + " 猜想会打印");
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        };
    }

}

执行结果

Thread_A  执行时间:
THREAD_B 猜想会打印

Process finished with exit code 0

答案:
线程B 和线程A,是不同的线程,在未受到人为干预(线程同步)情况下,A,B 互相不受影响,关闭线程B的宿主A,宿主B线程仍然会执行完毕。

猜想二

IntentService 中的OnIntent( ) 方法内部是执行耗时操作的,是否可以执行【子线程】的操作,2️⃣ 执行子线程操作会进行阻塞线程吗?后面的stopService() 会先于线程执行吗?

package com.tseng.alldilaog.service;

import android.app.IntentService;
import android.content.Intent;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.widget.Toast;

import com.tseng.alldilaog.MyApp;

public class IntentServiceDemo extends IntentService {

    public static String Tag = IntentService.class.getSimpleName();


    public IntentServiceDemo() {
        super(Tag);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {

        Toast.makeText(MyApp.getmContext(),"弹窗",1000).show();
        System.out.println(Thread.currentThread().getName() + " 当前线程" + getMainLooper()  +" my looper" + Looper.myLooper());

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread threadb = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            System.out.println(Thread.currentThread().getName() + " 猜想会打印");
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }
                }, "THREAD_B");
                threadb.start();

                System.out.println(Thread.currentThread().getName() + "  执行时间:");
            }
        }, "Thread_A");
        thread.start();


    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println(Tag + "  OnDestroy");
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
}

MainActivity

    @Override
    protected void onResume() {
        super.onResume();
        Intent intent = new Intent(MainActivity.this, IntentServiceDemo.class);
        startService(intent);
        }

答案:

在IntentService的 protected void onHandleIntent(@Nullable Intent intent)的方法中进行线程嵌套 (猜想一代码),结论一致。
只是IntentService 的 ondestroy( )会优先执行。
【注意】:网上所说的可以在 onHandleIntent()方法中做耗时操作。为了保持生命周期的连贯性 ondestroy()在耗时任务完成后调用。建议在onHandleIntent
方法中做同步工作。

08-30 14:54:05.511 2709-2709/com.tseng.alldilaog I/System.out: Thread[main,5,main]   looper =Looper (main, tid 1) {a86f274}

08-30 14:54:05.549 2709-2781/com.tseng.alldilaog I/System.out: IntentService[IntentService] 当前线程Looper (main, tid 1) {a86f274}
08-30 14:54:05.570 2709-2783/com.tseng.alldilaog I/System.out: Thread_A  执行时间:
08-30 14:54:05.571 2709-2784/com.tseng.alldilaog I/System.out: THREAD_B 猜想会打印
08-30 14:54:10.574 2709-2709/com.tseng.alldilaog I/System.out: IntentService  OnDestroy

猜想三

子线程中的getMainLooper(),拿到的是子线程的Looper 还是主ui线程的Looper,二 ,getLooper的阻塞指的是二次StartService()时候,才会调用吗?

样例代码:

@Override
protected void onResume() {
    super.onResume();
    Intent intent = new Intent(MainActivity.this, IntentServiceDemo.class);
    startService(intent);
    System.out.println("第二次调用");
    Intent intent2 = new Intent(MainActivity.this, IntentServiceDemo.class);
    startService(intent2);
}

答案:

getMainLooper():当前线程Looper (main, tid 1) {a86f274}

Looper.myLooper() :Looper (IntentService[IntentService], tid 481) {fda1c0c}

关于IntentService()内部原理方面,二次startService() 会以Message 队列方式进行运行,调用两次,执行两次onHandleIntent()方法

输出:

08-30 15:11:40.262 8294-8294/com.tseng.alldilaog I/System.out: Thread[main,5,main]   looper =Looper (main, tid 1) {a86f274}   这句是在Activity的Oncreat()中调用的

08-30 15:11:40.285 8294-8294/com.tseng.alldilaog I/System.out: 第二次调用
08-30 15:11:40.353 8294-8393/com.tseng.alldilaog I/System.out: IntentService[IntentService] 当前线程Looper (main, tid 1) {a86f274} my looperLooper (IntentService[IntentService], tid 493) {105e0a4}
08-30 15:11:40.354 8294-8394/com.tseng.alldilaog I/System.out: Thread_A  执行时间:
08-30 15:11:40.356 8294-8395/com.tseng.alldilaog I/System.out: THREAD_B 猜想会打印

08-30 15:11:45.417 8294-8393/com.tseng.alldilaog I/System.out: IntentService[IntentService] 当前线程Looper (main, tid 1) {a86f274} my looperLooper (IntentService[IntentService], tid 493) {105e0a4}
08-30 15:11:45.424 8294-8742/com.tseng.alldilaog I/System.out: Thread_A  执行时间:
08-30 15:11:45.424 8294-8743/com.tseng.alldilaog I/System.out: THREAD_B 猜想会打印

08-30 15:11:50.427 8294-8294/com.tseng.alldilaog I/System.out: IntentService  OnDestroy

猜想四

Hander是主线程hander还是子线程hander,取决于Looper()所在的线程和Hander初始化的线程。
1.主线程有初始化Handler 不指定Looper(),那hander属于主线程Handler。如果主线程Hander,给的子线程Looper(),那么会是子线程的Handler(),
区分是主线程hander还是子线程Hander,在于是否可以直接操作ui线程的ui元素

答案:

以上猜想是正确的,Handler 具体是子线程的Handler还是主线程的Hander,取决于用的初始化的Looper 是在子线程中初始化,还是主线程中。

Hander hander =new Handler( Lopper) //默认使用的是主线程的Looper(),这也是为什么在子线程
中不能new Handler的原因,需要:

        Looper.prepare();
        ...
        ...
        ...
        Looper.loop();

子线程需要和Handler 进行手动绑定

猜想五

HandlerThread 原理是在子线程中,绑定Hander + Looper【消息队列】,默认子线程和Handler是不绑定的,为了方便系统提供的方法

这里写图片描述

这里可以是同一线程,多个message,也统一是不同线程的Message,放到消息队列中

延伸:

IntentServive 原理 ,HandlerThread 用法,Handler 是子线程Handler 还是主线程Handler,

引用:
http://www.cnblogs.com/ghj1976/archive/2011/05/06/2038469.html

猜你喜欢

转载自blog.csdn.net/o279642707/article/details/82222654
今日推荐