Android的UI线程主要负责处理用户的按键事件、触屏事件等。因此其他阻塞UI线程的操作不应该在主线程中操作。为了避免UI线程失去响应的问题,Android程序采用将耗时操作放在新线程中完成的方式,但是新线程可能需要动态更新UI组件,比如获取网络资源操作放在新线程中完成。但由于新线程不允许直接更新山I组件,为了解决这个问题,Android提供了异步任务 (AsyncTask) 的方式实现异步线程的操作。

运行环境

  • Windows 10
  • Android Studio Arctic Fox (2020.3.1)
  • jdk1.7.0_67

本次实验我们使用该方法从网络上下载一张图片

AsyncTask

  • AsyncTask<Params,Progress,Result>是一个抽象类,通常被用于继承,继承时要指定如下三个泛型参数

Params启动任务执行时的输入参数的类型。

ImageDownTask task=new ImageDownTask(img);
                task.execute(url);

Progress后台任务完成的进度值的类型。

protected void onProgressUpdate(Void... values)

Result后台任务完成后返回结果的类型。

protected Bitmap doInBackground(String... strings)

使用方法

(1)创建AsyncTask的子类,并指定参数类型。如果某个参数不需要,则指定为Void类型,
(2)实现AsyncTask的方法,如doTnBackground (Params•••):后台线程将要完成的功能,一般有获取网络资源等耗时性的操作;第二个方法onPostExecute (Result result):在do InBackground ( 方法执行完以后,系统会自动调用onPostExecute 0方法,并接受其返回值。这里一般负责更新UI线程等操作。
(3)调用AsyncTask子类的实例的execute (Params•• params)方法执行耗时操作


新建一个项目

1.添加控件

在activity_main.xml中添加一个ImageView和一个Button控件(我采用的是线性布局)。

<ImageView
        android:id="@+id/img"
        android:layout_width="match_parent"
        android:layout_height="195dp" />

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载" />

2.声明控件并对Button设置监听

在MainActivity中对刚添加的两个控件声明,并对Button设置监听。
创建一个异步任务类

@Override
            public void onClick(View view) {
                ImageDownTask task=new ImageDownTask(img);
                task.execute(url);
            }

声明一个url,该url名称必须与task.execute(url);中url名称相同。

private String url="图片链接";

完整代码:

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import java.net.URL;

public class MainActivity extends AppCompatActivity {
    private ImageView img;
    private Button btn;
    private String url="http://pic1.win4000.com/mobile/2018-11-05/5bdfd9407a9b2.jpg";

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

    private void initView() {
        img=(ImageView)findViewById(R.id.img);
        btn=(Button)findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ImageDownTask task=new ImageDownTask(img);
                task.execute(url);
            }
        });
    }
}

3.继承AsyncTask

新建一个Java Class,命名为ImageDownTask.java
继承AsyncTask

public class ImageDownTask extends AsyncTask<String,Void, Bitmap>

4.定义下载图片功能(后台处理逻辑)

在ImageDownTask.java中添加以下代码
URL url=new URL(strings[0]);是因为只传递了一个参数,URL是一个数组,所以这里写0。

//后台处理逻辑(下载图片的功能在此方法中实现)
    @Override
    protected Bitmap doInBackground(String... strings) {
        //形参接受输入的参数(下载图片的地址)
        Bitmap bmp=null;
        try {
            URL url=new URL(strings[0]);
            //通过URL是客户端与服务器端建立连接
            HttpURLConnection coon=(HttpURLConnection) url.openConnection();
            //I/O流
            InputStream is=coon.getInputStream();
            //缓冲流
            BufferedInputStream bis=new BufferedInputStream(is);
            //将缓冲流中数据封装成图片
            bmp = BitmapFactory.decodeStream(bis);
            //下载完成后,关闭I/O管道
            bis.close();
            is.close();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return bmp;
    }

对img进行初始化,否则在MainActivity中ImageDownTask task=new ImageDownTask(img);会获取为空,这里直接通过构造方法进行初始化。

private ImageView img;
    public ImageDownTask(ImageView img) {
        //通过构造方法进行依赖注入
        this.img = img;
    }

当图片下载完成后需要更新,显示出图片

//更新
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        img.setImageBitmap(bitmap);
    }
}

5.开启联网权限

20211019134156.jpg
20211019134156.jpg

写完上面的代码后,还需要开启模拟器的联网权限。
在项目目录中点击manifests,选择AndroidManifest.xml,在<application ··· </application>标签后添加如下代码

<uses-permission android:name="android.permission.INTERNET"/>

<application ··· </application>标签内添加如下代码

android:usesCleartextTraffic="true"

6.完成

20211019140129.jpg
20211019140129.jpg

7.完整代码下载连接