IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android的AsyncTask -> 正文阅读

[移动开发]Android的AsyncTask

AsyncTask的介绍

AsyncTask是Android中的异步消息处理机制Handler的封装,更容易从子线程切换到主线程。
先简单看一下Handler是如何进行子线程和主线程之间的切换。

异步消息处理机制Handler

首先来看一下代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    public static final int UPDATE_TEXT = 1;
    private TextView text;
    private Handler handler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case UPDATE_TEXT:
                    text.setText("Nice to meet you");
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        text = (TextView) findViewById(R.id.text);
        Button change_text = (Button) findViewById(R.id.change_text);
        change_text.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (R.id.change_text == view.getId()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Message msg = new Message();
                    msg.what = UPDATE_TEXT;
                    handler.sendMessage(msg);
                }
            }).start();
        }
    }
}

在主活动中,有一个Button,一个TextView,当按下Button的时候,TextView中的内容就会改变,但是在上面代码中,当我们按下Button时,就会开启一个线程去处理TextView的内容,但是由于在子线程中不能去操作UI,否则程序将会崩溃,那么,我们应该如何去改变这个TextView呢?
此时,我们就需要用到异步消息处理机制了。
首先,我们先new一个Handler对象,并且重写其中的handleMessage()方法,然后在handleMessage()方法中去操作UI。我们应该如何去通知Handler去处理UI呢?这里就需要一个Message对象去设置what字段,然后调用handler.sendMessage()去传递一个message,然后就会调用handler的handleMessage()方法。当我们去传递一个message时,message就会进入MessageQueue中,当MessageQueue中有Message时,Looper就会将其拿出来提交给Handler去处理。这就是Handler异步消息处理机制的原理。
在这里插入图片描述
上图就是handler异步消息处理机制的示意图。
我接下来索要介绍的AsyncTask就是handler的封装,他只是让异步消息处理机制变得更加的简单。

AsyncTask的使用

上面讲述了AsyncTask的原理,我们就来看一下AsyncTask是如何来使用的。
一个异步任务的执行一般包括以下几个步骤:

1.execute(Params… params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。

2.onPreExecute(),在execute(Params… params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。

3.doInBackground(Params… params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息。

4.onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。

5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。

简单来说,execute()方法,就是去启动AsyncTask,onPreExecute()方法就是去做一些子线程的准备工作,它是在主线程执行的,doInBackground()方法是在子线程中执行一些费时的操作,当在这个方法中调用publishProgress()方法时就会调用onProgressUpdate()方法,这个方法会向主线程中发送已处理的数据。onProgress()在doInBackground()执行完之后执行,它是返回一个值,是最后的处理结果。

public abstract class AsyncTask<Params, Progress, Result> 

这是AsyncTask的定义。其中,有三个数据。Params是我们在开始执行时传入的数据,Progress是onProgressUpdate()方法返回的数据类型,Result是我们在执行完之后返回的数据类型。

AsyncTask的实例

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;

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... strings) {
        InputStream inputStream = null;
        RandomAccessFile savedFile = null;
        File file = null;
        try {
            long downloadedLength = 0;
            String downloadUrl = strings[0];
            String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
            String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
            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()
                    .url(downloadUrl)
                    .addHeader("RANGE", "bytes=" + downloadedLength + "-")
                    .build();
            Response response = client.newCall(request).execute();
            if (response != null) {
                inputStream = response.body().byteStream();
                savedFile = new RandomAccessFile(file, "rw");
                savedFile.seek(downloadedLength);       //跳过已下载的字节
                byte[] b = new byte[1024];
                int total = 0;
                int len;
                while ((len = inputStream.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 (inputStream != null) {
                    inputStream.close();
                }
                if (savedFile != null) {
                    savedFile.close();
                }
                if (isCanceled && file != null) {
                    file.delete();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return TYPE_FAILED;
    }


    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.body().close();
            return contentLength;
        }
        return 0;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        int progress = values[0];
        if (progress > lastProgress) {
            listener.onProgress(progress);
            lastProgress = progress;
        }
    }

    @Override
    protected void onPostExecute(Integer integer) {
        switch (integer) {
            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 onCanceled () {
        isCanceled = true;
    }
    
}

以上是AsyncTask的一个下载实例,在这个实例中,就能很好的展示每一个方法的作用。
首先是这个DownloadTask的构造方法,传入的是一个DownloadListener,它是一个接口,在服务中用匿名内部类去实现了这个接口,它是控制下载的进度。在下载中,它不需要去做一些准备工作,所以我们就不需要去重写onPrexeute()方法,所以就直接开始执行doInBackground()方法,在这里,我们传入的是一个字符串类型,传入的数据是我们下载的Url,在doInBackground中去执行下载的具体实现。当我们去调用publishProgress()方法时,就会自动调用onProgressUpdate()方法,这里调用这个方法,是更新我们的前台服务,当我们下载完成之后,就会调用onPostExecute()返回我们最后的状态,到底是下载成功还是其他。
以上就是AsyncTask的简单介绍,如有不对,请指正!

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-19 08:05:55  更:2021-09-19 08:06:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 20:01:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码