zoukankan      html  css  js  c++  java
  • 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()方法即可。

  • 相关阅读:
    深入Android 【一】 —— 序及开篇
    Android中ContentProvider和ContentResolver使用入门
    深入Android 【六】 —— 界面构造
    The service cannot be activated because it does not support ASP.NET compatibility. ASP.NET compatibility is enabled for this application. Turn off ASP.NET compatibility mode in the web.config or add the AspNetCompatibilityRequirements attribute to the ser
    Dynamic Business代码片段总结
    对文件的BuildAction以content,resource两种方式的读取
    paraview 3.12.0 windows下编译成功 小记
    百度网盘PanDownload使用Aria2满速下载
    netdata的安装与使用
    用PS给证件照排版教程
  • 原文地址:https://www.cnblogs.com/zhangxiaoxu/p/9400087.html
Copyright © 2011-2022 走看看