Android 中的线程

1,347 阅读4分钟
原文链接: blog.csdn.net

1.Android中的线程概括

这里写图片描述

  1. 线程与进程
    线程:线程是CPU调度的最小单元,同时线程也是一种有限的系统资源,即线程不可能无限制的产生,并且线程的创建和销毁有开销
    进程:一般指一个执行单元,在pc和移动设备上指的是一个程序或者一个应用。
  2. 主线程和子线程
    主线程:指的是进程所拥有的线程,在java中默认情况下一个进程只有一个线程,这个线程就是主线程
    子线程:工作线程,除了主线程以外的都是子线程
    Android的线程模型和java线程模型一样,也分为主线程和子线程,其中主线程叫做UI线程,主线程主要作用是运行四大组件以及处理和用户的交互,子线程的作用是处理耗时任务,比如说网络请求数据或者IO操作。
    从Android3.0开始系统要求网络访问必须在子线程中进行,否则将抛出异常NetworkOnMainThreadException,这样做避免了主线程因耗时操作所阻塞从而出现ANR

2.Android中的线程——AsyncTask

AsyncTask是一个轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI,AsyncTask封装了Thread和Handler,AsyncTask并不适合做特别耗时的任务。

下面给出一个用AsyncTask下载图片并显示进度的例子
MainActivity.Java

package com.zhoujian.thread;

import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import butterknife.ButterKnife;
import butterknife.InjectView;

public class MainActivity extends Activity
{
    @InjectView(R.id.download)
    Button mDownload;
    @InjectView(R.id.img)
    ImageView mImg;
    private MyDownLoadAsynctask mAsynctask;
    private ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.inject(this);
        clickEvent();
        progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("提示信息");
        progressDialog.setMessage("正在下载,请稍后...");
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setCanceledOnTouchOutside(false);
    }
    private void clickEvent()
    {
        mDownload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mAsynctask = new MyDownLoadAsynctask();
                mAsynctask.execute("http://img04.muzhiwan.com/2015/06/16/upload_557fd293326f5.jpg");
            }
        });
    }

    class MyDownLoadAsynctask extends AsyncTask
    {

        /**
         * 在主线程中执行,异步任务执行之前会调用,一般用于做一些准备工作
         */
        @Override
        protected void onPreExecute()
        {
            Toast.makeText(MainActivity.this, "异步任务开始执行下载", Toast.LENGTH_SHORT).show();
            progressDialog.show();
        }
        /**
         * 在线程池中执行,用于执行异步任务
         * @param strings
         * @return
         */
        @Override
        protected Bitmap doInBackground(String... strings) {
            HttpURLConnection connection = null;
            try {
                URL url = new URL(strings[0]);
                connection = (HttpURLConnection) url.openConnection();
                connection.setDoInput(true);
                connection.setConnectTimeout(5000);
                int code = connection.getResponseCode();
                if (code == 200) {
                    InputStream is = connection.getInputStream();
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    int length = -1;
                    int progress = 0;
                    int count = connection.getContentLength();
                    byte[] bytes = new byte[1024];
                    while ((length = is.read(bytes)) != -1) {
                        progress += length;
                        if (count == 0) {
                            publishProgress(-1);
                        } else {
                            //进度值改变通知,会调用onProgressUpdate()方法
                            publishProgress((int) ((float) progress / count * 100));
                        }
                        if (isCancelled()) {
                            return null;
                        }
                        Thread.sleep(50);
                        bos.write(bytes, 0, length);
                    }
                    return BitmapFactory.decodeByteArray(bos.toByteArray(), 0, bos.size());
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
            return null;
        }

        /**
         * 异步任务执行之后,会调用该方法,此方法会返回后台任务的返回值,即doInBackground的返回值
         * @param bitmap
         */
        @Override
        protected void onPostExecute(Bitmap bitmap)
        {
            Toast.makeText(MainActivity.this, "图片下载完成", Toast.LENGTH_SHORT).show();
            mImg.setImageBitmap(bitmap);
            progressDialog.dismiss();
        }
        /**
         * 在主线程中执行,当后台任务的执行进度发生改变时会调用这个方法
         * @param values
         */
        @Override
        protected void onProgressUpdate(Integer... values)
        {
            int progress = values[0];
            if (progress != -1) {
                progressDialog.setProgress(progress);
            }
        }
    }
}

activity_main.xml




    

    

AsyncTask使用时的注意事项:

(1)AsyncTask必须在主线程中创建,在子线程中创建会报错
报错截图如下:
这里写图片描述

看到这个错误,相信大家看着应该很熟悉,这个错误正是Handler在子线程创建的时候报的错。因为AsyncTask内部封装了Handler和Thread
(2)execute方法也必须在主线程中调用
(3)一个AsyncTask对象只能调用一次execute方法,否则会报错
报错截图如下:
这里写图片描述
(4)(0 到Android1.6)AsyncTask是串行执行任务的
[1.6到3.0)AsyncTask是并行执行任务的
[3.0到以后]AsyncTask是串行执行任务的,但是也可以通过executeOnExecutor方法来并行执行任务

3.Android中的线程——HandlerThread

HandlerThread继承了Thread,是一种可以使用Handler的thread
HandlerThread内部创建了消息队列,外界需要通过Handler的消息方式来通知HandlerThread执行一个具体的任务,可能还是好理解,直接上demo

SecondActivity.java

package com.zhoujian.thread;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.text.Html;
import android.widget.TextView;

/**
 * Created by zhoujian on 2016/12/15.
 */

public class SecondActivity extends Activity
{

    private static final int MSG_UPDATE_INFO = 0;
    private static final int MSG_INFO = 1;
    private TextView textview;
    private HandlerThread mHandlerThread;
    private Handler handler;
    private boolean boleanFlag;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            switch (msg.what) {
                case MSG_INFO:
                    String result = "随机数:%d";
                    result = String.format(result, (int) (Math.random() * 10));
                    textview.setText(Html.fromHtml(result));
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        //创建后台线程
        myThread();
        textview = (TextView) findViewById(R.id.textview);
    }

    @Override
    protected void onResume()
    {
        super.onResume();
        boleanFlag = true;
        handler.sendEmptyMessage(MSG_UPDATE_INFO);
    }

    @Override
    protected void onPause()
    {
        super.onPause();
        boleanFlag = false;
        handler.removeMessages(MSG_UPDATE_INFO);

    }

    private void myThread()
    {
        mHandlerThread = new HandlerThread("MyHandlerThread");
        mHandlerThread.start();
        handler = new Handler(mHandlerThread.getLooper())
        {
            @Override
            public void handleMessage(Message msg)
            {
                try
                {
                    //模拟耗时操作
                    Thread.sleep(2000);
                    mHandler.sendEmptyMessage(MSG_INFO);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }

                if (boleanFlag)
                {
                    handler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);
                }
            }
        };
    }
    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        //释放资源
        mHandlerThread.quit();
    }
}

activity_second.xml




    


运行结果截图:

这里写图片描述

4.Android中的线程——IntentService

IntentService是一种特殊的Service,它继承了Service并且是一个抽象类。IntentService可用于执行后台耗时任务,当任务执行完后会自动停止,同时由于IntentService是服务,所以它的优先级比单纯的线程要高,不容易被系统杀死。

这里写图片描述

5. Android中的线程——Thread

两种创建线程的方式:
这里写图片描述