安卓线程池和任务

来源:互联网 发布:申请淘宝商家披露信息 编辑:程序博客网 时间:2024/06/05 04:16

安卓线程池和任务:

线程和任务的区别:

线程若开辟,我们需要在内存中开辟相应的资源进行执行,而任务只是一个方法;

ThreadPoolExecutor线程池操作

即一个线程的集合;

当添加到线程池时,我们判断核心线程数量是够到达设置的上限,未到达则加入核心线程,达到则加入缓冲线程队列中(缓冲队列线程也有数量上限);当到达最大缓冲线程上限,会去看最大线程数量(其值需减去核心线程可放数量);当再超过,则会调用处理超出最大数量线程的handler任务策略;(在最大线程池中有一个最长存活时间)

若不指定上限,则会无限添加(现在一般都不指定上限);

线程池定义:



线程池的操作:

executor.execute(runnable):将线程加入到线程池

executor.remove(runnable):将线程移出线程池

AsyncTask异步加载网络任务

1、使用原因:

1)是其中使用了线程池技术,而且其中的方法很容易实现调用

2)可以调用相关的方法,在开启子线程前和后,进行界面的更新

3)一旦任务多了,不用每次都new新的线程,可以直接使用

2、执行的顺序:

onPreExecute()【执行前开启】--- >doInBackground() --- > onProgressUpdate() --- > onPostExecute()

3、执行过程:

当一个异步任务开启后,执行过程如下:

1)、onPreExecute():

这个方法是执行在主线程中的。这步操作是用于准备好任务的,作为任务加载的准备工作。建议在这个方法中弹出一个提示框。

2)、doInBackground():

这个方法是执行在子线程中的。在onPreExecute()执行完后,会立即开启这个方法,在方法中可以执行耗时的操作。需要将请求的参数传递进来,发送给服务器,并将获取到的数据返回,数据会传给最后一步中;这些值都将被放到主线程中,也可以不断的传递给下一步的onProgressUpdate()中进行更新。可以通过不断调用publishProgress(),将数据(或进度)不断传递给onProgressUpdate()方法,进行不断更新界面。

3)、onProgressUpdate():

这个方法是执行在主线程中的。publishProgress()在doInBackground()中被调用后,才开启的这个方法,它在何时被开启是不确定的,执行这个方法的过程中,doInBackground()是仍在执行的,即子线程还在运行着。

4)、onPostExecute():

这个方法是执行在主线程中的。当后台的子线程执行完毕后才调用此方法。doInBackground()返回的结果会作为参数被传递过来。可以在这个方法中进行更新界面的操作。

5)、execute():

最后创建AsyncTask自定义的类,开启异步任务。

 

3、实现原理:

1)、线程池的创建:

在创建了AsyncTask的时候,会默认创建一个线程池ThreadPoolExecutor,并默认创建出5个线程放入到线程池中,最多可防128个线程;且这个线程池是公共的唯一一份。

2)、任务的执行:

在execute中,会执行run方法,当执行完run方法后,会调用scheduleNext()不断的从双端队列中轮询,获取下一个任务并继续放到一个子线程中执行,直到异步任务执行完毕。

3)、消息的处理:

在执行完onPreExecute()方法之后,执行了doInBackground()方法,然后就不断的发送请求获取数据;在这个AsyncTask中维护了一个InternalHandler的类,这个类是继承Handler的,获取的数据是通过handler进行处理和发送的。在其handleMessage方法中,将消息传递给onProgressUpdate()进行进度的更新,也就可以将结果发送到主线程中,进行界面的更新了。

 

4)、需要注意东西:

1)      这个AsyncTask类必须由子类调用

2)      虽然是放在子线程中执行的操作,但是不建议做特别耗时的操作,如果操作过于耗时,建议使用线程池ThreadPoolExecutor和FutureTask

3)       AsyncTask可能存在新开大量线程消耗系统资源和导致应用FC的风险,因此,我们需要根据自己的需求自定义不同的线程池

4)       它封装了HandlerThread和handler来实现异步多线程的操作的

4、示例代码:

private class DownloadFilesTask extendsAsyncTask<URL, Integer, Long> {

   protected Long doInBackground(URL... urls) {

        int count = urls.length;

       long totalSize = 0;

       for (int i = 0; i < count; i++) {

           totalSize += Downloader.downloadFile(urls[i]);

           publishProgress((int) ((i / (float) count) * 100));

           // Escape early if cancel() is called

           if (isCancelled()) break;

       }

       return totalSize;

   }

 

   protected void onProgressUpdate(Integer... progress) {

       setProgressPercent(progress[0]);

   }

 

   protected void onPostExecute(Long result) {

       showDialog("Downloaded " + result + " bytes");

   }

}

new DownloadFilesTask().execute(url1,url2, url3);

 注意:

一般情况下内部类或者匿名AsyncTask回持有Activity或者View的引用,这容易造成内存泄漏,所以建议在使用AsyncTask的时候尽量使用静态内部类。

如果同时调用多个AsyncTask,任务会加入到队列中,等待前一个执行完才执行下一个。
这里是各个版本它的改动:

Android API 15-18:

  • 线程池核心线程数:5
  • 线程池最大线程数:128
  • 线程池缓存队列大小:10
  • 线程池维护线程空闲时间:1

Android API 19-23:

  • 线程池核心线程数:CPU_COUNT + 1
  • 线程池最大线程数:CPU_COUNT * 2 + 1
  • 线程池缓存队列大小:128
  • 线程池维护线程空闲时间:1

Android API 24-25:

  • 线程池核心线程数:Math.max(2, Math.min(CPU_COUNT - 1, 4))
  • 线程池最大线程数:CPU_COUNT * 2 + 1
  • 线程池缓存队列大小:128
  • 线程池维护线程空闲时间:30
  • 核心线程如果超出空闲时间也会被回收


timerTask循环执行线程:

通过timer对象实现;


用handler实现:


注意,别用子线程.sleep实现,这样写不优雅;一般线程延迟都使用handler;

Hander和looper

参考:http://blog.csdn.net/heng615975867/article/details/9194219

Looper是用来封装消息循环和消息队列的一个类,是 MessageQueue的管理者,用于在android线程中进行消息处理。通过调用Looper.myLooper()可以获得当前线程的Looper对象创建一个Looper 对象时,会同时创建一个MessageQueue对象。

handler其实可以看做是一个工具类,它的作用就是提供一系列函数,方便我们完成消息的创建封装和插入到消息队列,用来向消息队列中插入消息的。

关键点:

1.       Looper类用来为一个线程开启一个消息循环一个线程只能有一个Looper,同时对应一个MessageQueue。默认情况下android中新诞生的线程是没有开启消息循环的。(主线程系统会自动为其创建Looper对象,开启消息循环。Looper对象通过MessageQueue来存放消息和事件。因此在非主线程中直接用new Handler会报错!因为非主线程中没有Looper对象。需要先调用Looper.prepare()启用LooperLooper开始工作,从消息队列里取消息,处理消息。 

2.       Handler可看做是Looper的一个接口, 通常是通过Handler对象来与Looper进行交互的,他用来向指定的Looper发送消息及定义处理方法默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。 mainHandler = new Handler() 等价于newHandlerLooper.myLooper(). Looper.myLooper():获取当前进程的looper对象,类似的Looper.getMainLooper()用于获取主线程的Looper对象。 

3.       Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

例子:

官方子线程handler处理例子:

1.  class LooperThread extends Thread  

2.  {  

3.      public Handler mHandler;  

4.      public void run()   

5.      {

6.          Looper.prepare();  

7.          mHandler = new Handler()   

8.          {  

9.               public void handleMessage(Message msg)   

10.             {  

11.                // process incoming messages here  

12.             }  

13.         };  

14.     Looper.loop();  

15. }  

如果线程中使用Looper.prepare()Looper.loop()创建了消息队列就可以让消息处理在该线程中完成

主线程和子线程处理对比:

package com.example.cyf.myapplication;

 

import android.app.Activity;

import android.os.Handler;

import android.os.Looper;

import android.os.Message;

importandroid.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.widget.Toast;

 

public class MainActivity extendsActivity {

 

   private Handler handler1;

 

   private Handler handler2;

 

   @Override

   protected void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_main);

 

       initHandler1();

       initHandler2();

   }

 

   /**

     * 初始化handler(主线程)

    */

   private void initHandler1() {

       handler1= new Handler(){

            @Override

            public void handleMessage(Messagemsg) {

                if (msg.arg1==1) {

                  Toast.makeText(MainActivity.this,"hanlder1",Toast.LENGTH_SHORT).show();

                }

               super.handleMessage(msg);

            }

       };

 

       new Thread(new Runnable() {

            @Override

            public void run() {

                Message message =handler1.obtainMessage();

                message.arg1 = 1;

                handler1.sendMessage(message);

            }

       }).start();

   }

 

   /**

     * 初始化handler(子线程)

    */

   private void initHandler2() {

       new Thread(new Runnable() {

            @Override

            public void run() {

                Looper.prepare();

                handler2 = new Handler(){

                    @Override

                    public voidhandleMessage(Message msg) {

                        if (msg.arg1==1) {

                            Toast.makeText(MainActivity.this,"hanlder2",Toast.LENGTH_SHORT).show();

                        }

                       super.handleMessage(msg);

                    }

                };

                Message message =handler2.obtainMessage();

               message.arg1 = 1;

                handler2.sendMessage(message);

                Looper.loop();

            }

       }).start();

   }

}

 

0 0
原创粉丝点击