专栏首页移动端开发Android学习--探究服务(一)

Android学习--探究服务(一)

什么是服务?


      服务(service)是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互而且还要求长期运行的任务。服务的运行不依赖任何的用户界面,即使应用被切换到后台或者用户重新启动了另一个程序,服务还是能够保持正常运行的。

      不过需要注意的是,服务并不是运行在一个独立的进程里面,而是依赖于创建服务时所在的程序的进程,当某个程序的进程被杀掉的时候,所有依赖于这个进程的服务就都会被停掉!

      当然也不能被服务的后台概念所迷惑,实际上所有的服务并不会自动开启线程,所有的代码都是默认运行在主线程当中的,也就是说我们需要在服务的内部手动的床架子线程,并在这里执行具体的任务,否则就有可能出现主线程被阻塞的情况。

Android多线程得先知道


      在探究服务这点上我们首先要明白的是安卓的多线程,我们这里学习的也只是安卓多线程最基本以及简单的东西,虽然自己的水平也只是学习入门的水平,但是按照我对多线程这该耐心的理解,要仔细研究的话多线程里面的东西是不会少的,比如说线程之间的通信,由线程安全牵扯出的线程的各种锁等等,看最简单的,Android线程的基本用法:

// 线程的第一种写法,直接继承自Thread自定义我们的MyThread类
class MyThread extends Thread{

    @Override
    public void run() {
        super.run();
        // 具体的逻辑处理

    }
}
/*
*
* 那我们改如何使用这个多线程呢?
* 其实也很简单,我们直接new 一个 MyThread类
* 然后调用它的start()方法,这样run方法里面的具体的操作就在子线程中执行了
* */

      我们还有更好的方式来写多线程,这种继承的方式耦合度有点低,更多的时候我们是选择实现Runnable()接口的方式来定义一个线程,要是我们使用了这个方法来实现多线程之后我们调用的方式也就要发生改变

      大概的思路还是: 我们初始化一个MyThread类,这个类实现一下 Runnable() 接口

      我们再初始化一个Thread对象,但是在初始化的时候需要我们把New出来的MyThread类对象传入,在之后直接调用start()方法

      那有没有更简单的方式来写呢?当然是有,也会说我们最常见的,要是你不想再去定义一个类,我们就使用下面匿名类的方式来写,代码如下:

// 使用匿名类的方式使用多线程
new Thread(new Runnable() {
       @Override
       public void run() {

             Log.d("ServiceMainActivity","我是在其他线程执行的任务")
       }
}).start();

不安全的线程


      Android的线程和我们iOS的线程是一样的也是不安全的,所以想要在子线程中更新UI是办不到的,这一点和我们iOS的一样,这时候就涉及到主线程和子线程之间的通信,该如何处理呢?

      下面是我们在异步线程里面做的操作,在完成我们发送消息,在主线程接收到消息只有处理任务:

   // 线程的第一种写法,直接继承自Thread自定义我们的MyThread类
    class MyThread extends Thread{

        @Override
        public void run() {
            super.run();

            // 具体的逻辑处理
            Message message = new Message();
            message.what = UPDATE_TEXT;
            handler.sendMessage(message);
        }
    }

      下面是我们在主线程做的操纵:

    public  static final int UPDATE_TEXT = 1;

    private  Handler handler = new Handler(){
        // 线程的第一种写法,直接继承自Thread自定义我们的MyThread类
        class MyThread extends Thread{

            @Override
            public void run() {
                super.run();

                // 具体的逻辑处理
                Message message = new Message();
                message.what = UPDATE_TEXT;
                handler.sendMessage(message);
            }
        }
    };

      这样我们在异步和主线程之间建立起了通讯,其实在主线程和异步线程之间建立通讯的方式还有其他的方式,我们在接着看异步消息处理机制。

异步消息处理机制


      在Android中的异步消息处理主要有四个部分组成: Message   Handler   MessageQueue    Looper 

      在上一节中,前面的Message和Handler在上一节中我们已经接触过了,而MessageQueue和Looper我们暂时还没有接触到,下面我们就对着四部分一点点的剖析一下。

      1、Message

          Message是在线程之间传递的消息,他可以在内部携带少量的信息,用于在不同的线程之间交换数据,前面的时候我们用到的只是简单的what字段,除此之外可以使用arg1和arg2字段类携带一些整形数据,使用obj字段可以携带一个object对象。

      2、Handler

           Handler 顾明思议也就是处理者的意思,它也主要是用于发送和处理消息的,发送消息一般都是使用Handler的sendMessage()方法,而发出的消息经过一系列的辗转处理后,最终会传递到Handler的handleMessage()方法。

      3、MessageQueue

           MessageQueue 是消息队列的意思,它主要用于存放所有通过Handler发送的消息,这部分消息会一直存放在消息队列里面,等待被处理,每个线程中只会有一个MessageQueue对象。

      4、Looper

           Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法,就会进入到一个无限循环当中,然后每当发现MessageQueue中存放在一条消息,就会将它取出,并传递到Handler的handlerMessage()方法中,每一个线程中也只会有一个Looper对象。

      我们了解了他们的基本概念之后我们也就可以看看下面的这张图了,Android异步消息处理流程图,通过这张流程图我们乐意更好的理解一下这个Android异步消息的处理流程,理解他们四个之间的关系,更好的裂解一下他们的概念:

 AsyncTask


      为了更加方便的我们在子线程中对UI进行操作,Android还提供了拧一个好用的工具,比如AsyncTask,借助它既是你对异步消息的处理机制完全不了解,也可以十分简单的从子线程切换到主线程,当然他背后的实现原理还是使用了异步消息的处理机制的,只是Android帮我们分装好了而已。

      AsyncTask首先是一个抽象类,所以我们想要使用它就必须创建一个子类去继承它,在继承的时候我们可以为AsyncTask类指定三个泛型参数:

      * params  可用于在后台任务中使用

      * Progress 后台执行任务的时候,界面要是要显示进度,可以使用这里指定的泛型作为进度单位

      * Result  如果需要对结果进行参会,则使用这里指定的泛型作为返回值类型

      除了上面的这三个参数,还有四个方法使我们在继承之后需要重写的:

      1、onPreExecute()                  后台任务开始执行之前调用,用于进行一些界面上的初始化操作

      2、doInBackground()              耗时操作

      3、onProgressUpdate()           UI的操作

      4、onPostExecute()                任务执行完毕并通过return语句进行返回时,这个方法很快被调用,返回的参数会违参数传递到此方法中,处理任务的收尾工作

      当然想要启动个DownLoadTask任务,也只需要我们执行 new DownLoadTask().execute()方法即可。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • iOS 从实际出发理解多线程

    前言 ----       多线程很多开发者多多少少相信也都有了解,以前有些东西理解的不是很透,慢慢的积累之后,这方面的东西也需要自己好好的总结一下。多线程从我...

    Mr.RisingSun
  • 告诉你 iOS9.0 之后的Bitcode到底是什么!!

     用Xcode 7 beta 3在真机(iOS 8.3)上运行一下工程,结果发现工程编译不过。看了下问题,报的是以下错误: ld: ‘/Users/**/Fr...

    Mr.RisingSun
  • 快速排序OC、Swift版源码

    前言: 你要问我学学算法在工作当中有什么用,说实话,当达不到那个地步的时候,可能我们不能直接的感觉到它的用处!你就抱着这样一个心态,当一些APP中涉及到算法...

    Mr.RisingSun
  • 菜鸟的进阶之路:了解使用多线程

    关于多进程和多线程,教科书上最经典的一句话是“进程是资源分配的最小单位,线程是CPU调度的最小单位”,一般来说进程是独立的而同一进程中的线程是共享的,但是开一个...

    乱敲代码
  • 多线程编程:多线程并发制单的开发记录【一】

    进程和线程: 下图是在来自知乎用户的解释,个人感觉狠到位 ?        进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资...

    赵小忠
  • 常见的并发场景

    最常见、比较复杂一个场景是Web容器的线程池。Web容器使用线程池同步或者异步处理HTTP请求,同时这也可以有效的复用HTTP连接,降低资源申请的开销。通常我们...

    技术从心
  • 先行发生原则(happens-before)介绍

    如果Java内存模型中所有的有序性都仅仅靠volatile和synchronized来完成,那么有一些操作将会变得很烦琐,但是我们在编写Java并发代码的时候并...

    栋先生
  • 菜鸟的进阶之路:了解使用多线程

    关于多进程和多线程,教科书上最经典的一句话是“进程是资源分配的最小单位,线程是CPU调度的最小单位”,一般来说进程是独立的而同一进程中的线程是共享的,但是开一个...

    码农小胖哥
  • 线程和线程池的几个状态值

    在java中线程池的实现的主类是通过ThreadPoolExcutor这个类来实现的, 线程池运行的状态,并不是用户显式设置的,而是伴随着线程池的运行,由内部...

    居士
  • dotnet 多线程禁止同时调用相同的方法 禁止方法重入调用 双检锁的设计

    大家在使用多线程的时候,是否有关注过线程安全的问题。如果咱的代码在使用多线程时,在相同的时间有多个线程同时执行相同的方法,此时也许就存在数据安全的问题,如多个线...

    林德熙

扫码关注云+社区

领取腾讯云代金券