Android开发之Handler机制及AsyncTask的使用

来源:互联网 发布:如何将压缩的js还原 编辑:程序博客网 时间:2024/06/16 12:35

开启线程的两种方式:
1,新建一个类继承Thread,然后重写父类的run()方法,最后调用它的start()方法。
2,使用继承的方式耦合性有点高,更多的时候会选择使用实现Runnable接口的方式来定义一个线程。

在子线程中更新UI
如果想要更新应用程序的UI元素,则必须在主线程中进行,否则会出现异常。
1,使用handler异步消息处理子线程更新UI的使用方法。

public class MainActivity extends AppCompatActivity {    public static final int UPDATE_TEXT = 1;    private Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case UPDATE_TEXT:                    //在这里可以进行UI操作                    break;                default:                    break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Button mUpdate = (Button)findViewById(R.id.btn_get);        mUpdate.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(new Runnable() {                    @Override                    public void run() {                        Message message = new Message();                        message.what = UPDATE_TEXT;                        handler.sendMessage(message);  //将message对象发送出去。                    }                }).start();            }        });    }}

解析异步消息处理机制:
Android中异步消息处理主要由4个部分组成:Message、Handler、MessageQueue、Looper。
1,Message
Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。

2,Handler
Handler主要是用于发送和处理消息的。发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列的处理后,最后会传递到Handler的handleMessage()方法中。

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

4,Looper
Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无线循环中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handlerde 的handleMessage()方法中。

整个流程:
首先需要在主线程当中创建一个Handler对象,并重写handleMessage()方法。然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将这条消息发送出去。之后这条消息会被添加到MessageQueue的队列中等待被处理,而Looper则会一直尝试从MessageQueue中取出待处理的消息,最后分发回Handler的handleMessage()方法中。

2,runOnUiThread()也可以在子线程更新UI,其实也是一个异步消息处理机制的接口封装。

3,使用AsyncTask
诀窍:在doInBackground()方法中执行具体的耗时任务,在onProgressUpdate()方法中进行UI操作,在onPostExecute()方法中执行一些任务的收尾工作。

package com.gyq.servicebestpractice;import android.os.AsyncTask;import android.os.Environment;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.RandomAccessFile;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response;/** * ${DESC} * author: gyq * create at 2016/12/27 16:21 */public class DownloadTask extends AsyncTask<String,Integer,Integer> {    public static final int TYPE_SUCCESS = 0;    public static final int TYPE_FAILED = 1;    public static final int TYPE_PAUSED = 2;    public static final int TYPE_CANCELED = 3;    private DownloadListener listener;    private boolean isCanceled = false;    private boolean isPaused = false;    private int lastProgress;    public DownloadTask(DownloadListener listener) {        this.listener = listener;    }    @Override    protected Integer doInBackground(String... params) {        InputStream is = null;        RandomAccessFile savedFile = null;        File file = null;        try {            long downloadedLength = 0;     //记录已下载的文件长度            String downloadUrl = params[0];            String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));            String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();            file = new File(directory + fileName);            if (file.exists()) {                downloadedLength = file.length();            }            long contentLength = getContentLength(downloadUrl);            if (contentLength == 0) {                return TYPE_FAILED;            }else if (contentLength == downloadedLength) {                //已下载字节和文件总字节相等,说明已经下载完成了                return TYPE_SUCCESS;            }            OkHttpClient client = new OkHttpClient();            Request request = new Request.Builder()                    //断点下载,指定从哪个字节开始下载                    .addHeader("RANGE","bytes = " + downloadedLength + "-")                    .url(downloadUrl)                    .build();            Response response = client.newCall(request).execute();            if (response != null) {                is = response.body().byteStream();                savedFile = new RandomAccessFile(file,"rw");                savedFile.seek(downloadedLength);                byte[] b = new byte[1024];                int total = 0;                int len;                while ((len = is.read(b)) != -1) {                    if (isCanceled) {                        return TYPE_CANCELED;                    }else if (isPaused) {                        return TYPE_PAUSED;                    }else {                        total += len;                        savedFile.write(b,0,len);                        //计算已下载的百分比                        int progress = (int)((total + downloadedLength) * 100 / contentLength);                        publishProgress(progress);                    }                }                response.body().close();                return TYPE_SUCCESS;            }        }catch (Exception e) {            e.printStackTrace();        }finally {            try {                if (is != null) {                    is.close();                }                if (savedFile != null) {                    savedFile.close();                }                if (isCanceled && file != null) {                    file.delete();                }            }catch (Exception e) {                e.printStackTrace();            }        }        return TYPE_FAILED;    }    @Override    protected void onProgressUpdate(Integer... values) {        int progress = values[0];        if (progress > lastProgress) {            listener.onProgress(progress);            lastProgress = progress;        }    }    @Override    protected void onPostExecute(Integer status) {        switch (status) {            case TYPE_SUCCESS :                listener.onSuccess();                break;            case TYPE_FAILED :                listener.onFailed();                break;            case TYPE_PAUSED :                listener.onPaused();                break;            case TYPE_CANCELED :                listener.onCanceled();                break;            default:                break;        }    }    public void pauseDownload() {        isPaused = true;    }    public void cancelDownload() {        isCanceled = true;    }    private long getContentLength(String downloadUrl) throws IOException {        OkHttpClient client = new OkHttpClient();        Request request = new Request.Builder()                .url(downloadUrl)                .build();        Response response = client.newCall(request).execute();        if (response != null && response.isSuccessful()) {            long contentLength = response.body().contentLength();            response.close();            return contentLength;        }        return 0;    }}

如果想启动这个任务,只需编写如下代码:

new DownloadTask().execute();
1 0
原创粉丝点击