• Android线程


    1、引言

    在Android中,几乎完全采用了Java的线程机制,由于Android的特性,主线程只处理和界面相关的事情,子线程处理耗时操作。Android中扮演线程角色的有Thread、AsyncTask、IntentService和HandlerThread。对于AsyncTask来说,底层用到了线程池,对于IntentService和HandlerThread,底层用到了线程。

    2、AsyncTask

    AsyncTask是一个抽象的泛型类,它提供了Params、Progress和Result这三个泛型参数。

    public abstract class AsyncTask<Params, Progress, Result> 
    

    其中Params表示参数类型,Progress表示后台任务的执行进度的类型,Result表示后台任务返回结果的类型。并且提供了五个核心的方法。

    @MainThread
    protected void onPreExecute() {
    }
    

    此方法有个@MainThread注解,表示在主线程执行,在异步任务执行之前,此方法会被调用,一般可以做一些准备工作。

    @WorkerThread
    protected abstract Result doInBackground(Params... params);
    

    此方法有个@WorkerThread注解,表示在工作(子)线程执行,用于执行异步任务,params参数表示异步任务的输入参数,可调用publishProgress方法来更新任务进度,publishProgress会调用onProgressUpdate方法。并且此方法需要返回计算结果给onPostExecute方法。

    @MainThread
    protected void onPostExecute(Result result) {
    }
    

    在主线程中执行,在异步任务执行后,此方法会被调用,result是后台任务的返回值。

    @MainThread
    protected void onProgressUpdate(Progress... values) {
    }
    

    在主线程中执行,后台任务的执行进度发生变化时,此方法会被调用。

    @MainThread
    protected void onCancelled(Result result) {
        onCancelled();
    }    
    

    在主线程中执行,当异步任务被取消是,此方法会被调用,而onPostExecute则不会被调用。

    class MyTask extends AsyncTask<String, Integer, String> {
    
        @Override
        protected void onPreExecute() {
            Log.i(TAG, "onPreExecute() called");
            textView.setText("loading...");
        }
    
        @Override
        protected String doInBackground(String... strings) {
            Log.i(TAG, "doInBackground(Params... params) called");
            try {
                OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();
                Request request = new Request.Builder()
                        .url(strings[0])
                        .get()
                        .build();
                Call call = client.newCall(request);
                Response response = call.execute();
                if (response.code() == 200) {
                    InputStream is = response.body().byteStream();
                    long total = response.body().contentLength();
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    byte[] buf = new byte[1024];
                    int count = 0;
                    int length = 0;
                    while ((length = is.read(buf)) != -1) {
                        baos.write(buf, 0, length);
                        count += length;
                        //调用publishProgress公布进度,最后onProgressUpdate方法将被执行
                        publishProgress((int) (count * 1.0f / total * 100));
                        //为了演示进度,休眠500毫秒
                        Thread.sleep(500);
                    }
                    return new String(baos.toByteArray(), "utf8");
                }
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
            return null;
        }
    
        //onProgressUpdate方法用于更新进度信息
        @Override
        protected void onProgressUpdate(Integer... progresses) {
            Log.i(TAG, "onProgressUpdate(Progress... progresses) called");
            progressBar.setProgress(progresses[0]);
            textView.setText("loading..." + progresses[0] + "%");
        }
    
        //onPostExecute方法用于在执行完后台任务后更新UI,显示结果
        @Override
        protected void onPostExecute(String result) {
            Log.i(TAG, "onPostExecute(Result result) called");
            textView.setText(result);
    
            execute.setEnabled(true);
            cancel.setEnabled(false);
        }
    
        //onCancelled方法用于在取消执行中的任务时更改UI
        @Override
        protected void onCancelled() {
            Log.i(TAG, "onCancelled() called");
            textView.setText("cancelled");
            progressBar.setProgress(0);
    
            execute.setEnabled(true);
            cancel.setEnabled(false);
    
        }
    }
    

    上面代码中,实现一个具体的AsyncTask类,主要模拟get请求,并且更新progress。
    AsyncTask使用限制

    • 类必须在主线程中加载
    • 对象必须在主线程中创建
    • execute方法必须在UI线程调用
    • 不要在程序中直接调用onPreExecute、onPostExecute、doInBackground、onProgressUpdate方法
    • 一个AsyncTask对象只能执行一次,多次执行会报运行时异常。

    3、HandlerThread

    HandlerThread本质上是一个线程类,它继承了Thread,并且可以创建一个带有looper的线程,进行looper循环;looper对象可以用于创建Handler类来进行来进行调度,必须调用start()方法,Thread会先调用run方法来创建Looper对象。源码如下:

    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    

    创建HandlerThread很简单,它有两个构造函数,第一个构造函数只需要传递线程名称即可,第二构造函数除了线程名称,还需要设置优先级的功能

    HandlerThread thread = new HandlerThread("downImage");
    thread.start();
    
    HandlerThread thread = new HandlerThread("downImage", Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();
    

    需要注意的是,HandlerThread的run是一个无限循环,因此明确不需要它时,需要调用quit和quitSafely方法来终止线程的执行。

    4、IntentService

    IntentService继承了Service,并且它是一个抽象类,因此必须创建它的子类才能使用IntentService。它用于执行后台耗时的任务,执行完会自动停止。它拥有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务。
    IntentService其实还是由HandlerThread和Handler实现的。

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.
    
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
    
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    

    onCreate中创建了一个HandlerThread ,在通过HandlerThread创建了一个Handler。startService后,最终会调用onStart方法。

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
    

    从上面可以看出,mServiceHandler 发送的消息最终都会在HandlerThread 执行,会将Intent的对象传递给onHandleIntent抽象方法(需要子类实现)处理。onHandleIntent处理完之后会调用stopSelf(int startId)方法尝试停止服务,而不是stopSelf()来立即停止服务。下面创建一个示例看看它是怎样实现的。

    public class DownLoadService extends IntentService {
    
        public DownLoadService(String name) {
            super(name);
        }
    
        @Override
        protected void onHandleIntent(@androidx.annotation.Nullable @Nullable Intent intent) {
            String url = intent.getStringExtra("url");
            Bitmap bitmap = dowload(url);
            // 保存逻辑处理
        }
    }
    

    启动跟Service一样

    Intent intent = new Intent(this, DownLoadService.class);
    startService(intent);
    
  • 相关阅读:
    【数论】错排问题
    【数论】求逆元的几种方式
    【数论】卢卡斯定理模板 洛谷P3807
    【单调队列优化dp】 分组
    【期望dp】绵羊跳弹簧
    软件工程总结
    结对项目-地铁出行路线规划程序(续)
    个人作业--week3
    个人作业-week2
    个人作业-week1
  • 原文地址:https://www.cnblogs.com/fomin/p/9989540.html
Copyright © 2020-2023  润新知