文章目录

  • 一、同步与异步的概念
  • 二、Android异步处理技术
  • 三、AsyncTask原理
  • 四、Demo演示



对于网络请求或者下载方案,本人经过简单学习,小小总结了一下,有这么四种:第一种:使用OKHttp(异步GET)+Handler;第二种:OkHttp(同步GET)+AsyncTask,第三种,HttpURLconnection+Thread+Handler;第四种是:HttpURLConnection+AsyncTask。如有不对,请不吝指出错误之处。

出现问题:使用HttpURLConnection访问网络正常,但是使用第三方库OKHttpClient访问网络出现安全问题,参照


以及

还是出现以下提示,网上的解决方案也不能奏效。(Sdk 是android7.0 API 24)。

D/NetworkSecurityConfig: Using Network Security Config from resource
network_security_config debugBuild: true

解决方案是:使用在doInBackground方法中使用OKhttp3的同步get方法,而不是异步Get方法

一、同步与异步的概念

同步是指所有的操作按顺序从头到尾都做完,才把结果返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉。这种情况下,用户不能关闭界面,如果关闭了,即程序就中断了。比如:当客户端发送请求给服务端,在等待服务端响应的请求时,客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待。用户使用起来会有不友好。

异步的概念和同步时相对的。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知或者回调来通知调用者。比如:当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了时间,提高了效率。

二、Android异步处理技术

在android中有两条原则,第一条是:我们不能再主线程(UI Thread)中进行耗时的操作 以免阻塞主线程。第二条是:不能在主线程之外的其他线程中操纵UI元素。所以异步处理技术是解决主线程和子线程之间通信的关键。
在Android 中实现异步任务机制有两种方式:Handler和AsyncTask。

Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新。
优点:结构清晰,功能定义明确;处理多个后台任务时,简单、清晰
缺点:在单个后台异步处理时,显得代码臃肿,结构过于复杂。

AsyncTask模式是Android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度。最后将执行的结果反馈给UI主线程。
优点:简单、快捷、过程可控
缺点:在使用多个异步操作和需要进行UI更新时,变得复杂。

android SharedPreferences 替代方案 asynctask替代方案_android

三、AsyncTask原理

3.1. AsyncTask是一个抽象类,当我们继承使用它的时候我们需要指明它的三个泛型

public Abstract class AsyncTask <Params, Progress, Result>{…}

Params: 指定的是启动任务执行时,输入的参数的类型,比如HTTP的url地址。
Progress: 指定的是异步任务执行的进度的参数类型,这个值返回给UI线程。
Result: 指定的是异步任务执行完后返回给UI线程的结果的类型,如string,Integer等
不指定的话都写成Void

class DownLoadFile extends AsyncTask <Void, String, Boolean>{
....}

3.2. AsyncTask异步任务执行分为4个步骤:

第一步: onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出ProgressDialog
第二步: doInBackground(Params… params): 在onPreExecute()方法执行完后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread来执行这个方法(即在worker thread当中执行),执行完后将执行结果发送给最后一个 onPostExecute 方法,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作
第三步:onProgressUpdate(Progess… values): 这个方法也是在UI Thread当中执行的,在异步任务执行的时候,有时需要将执行的进度返回给UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进度,就可以使用这个方法来更新进度。这个方法调用条件:需要在 doInBackground 方法中通过方法 publishProgress(Progress) 将进度时刻传递给 onProgressUpdate 方法并执行来更新UI进度条。 第四步:onPostExecute(Result… result): 当异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上

3.3.为了正确的使用AsyncTask类,必须遵守一下几个原则:

1).Task的实例必须在UI线程中创建
2).execute()方法必须在UI线程中调用
3.)不要手动调用 onPreExecute() 、doInBackground(Object[] objects) 、 onProgressUpdate(Object[] values) 、 onPostExecute(Object o) 这几个方法,需要在UI线程中实例化这个task来调用。
4).该task只能被执行一次,多次调用时会出现异常。
5).doInBackground() 方法和onPostExecute()的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接收的参数,第2个为显示进度的参数,第3个为doInBackground返回和onPostExcecute()传入的参数。

四、Demo演示

使用AsyncTask异步下载网络文件,并将网络文件的内容显示在屏幕上
4.1 编写布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_get"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="73dp"
        android:layout_marginTop="54dp"
        android:text="Button"
        app:layout_constraintBottom_toTopOf="@+id/imageView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/et_url"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/et_url"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="76dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="54dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="Name"
        app:layout_constraintBottom_toTopOf="@+id/imageView"
        app:layout_constraintEnd_toStartOf="@+id/btn_get"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="272dp"
        android:layout_height="0dp"
        android:layout_marginBottom="287dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_get"
        app:srcCompat="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="217dp"
        android:layout_marginLeft="70dp"
        android:layout_marginStart="70dp"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>

4.2 编写MainActivity.java文件,获取布局文件上的组件,定义进度条对话框,设置“下载”按钮的监听事件。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btn_get;
    private EditText et_url;
    private ImageView imageView;
    private String mUrl;
    Bitmap bitmap;
    private TextView tv;
    private String json;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();

    }

    private void initView() {
        btn_get = (Button) findViewById(R.id.btn_get);
        et_url = (EditText) findViewById(R.id.et_url);
        imageView = (ImageView) findViewById(R.id.imageView);
        et_url.setText("https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2449529543,2725053068&fm=26&gp=0.jpg");
        btn_get.setOnClickListener(this);
        tv = (TextView) findViewById(R.id.textView);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_get:
                mUrl = et_url.getText().toString();
                NetAsyncTask asyncTask = new NetAsyncTask();
                asyncTask.execute();
                break;
        }
    }
 }

4.3编写内部类DownLoadFile.java,并继承与AsyncTask,实现定义的4个方法。

//定义DownLoadFile类,并继承AsyncTask
 class NetAsyncTask extends AsyncTask<Object,Integer,Object> {

        @Override
        protected Object doInBackground(Object[] objects) {
            try {
                URL url=new URL(et_url.getText().toString());
                HttpURLConnection connection= (HttpURLConnection) url.openConnection();
                InputStream inputStream=connection.getInputStream();
                connection.connect();
                bitmap= BitmapFactory.decodeStream(inputStream);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return  bitmap;
        }

        @Override
        protected void onPostExecute(Object o) {
            super.onPostExecute(o);
            imageView.setImageBitmap((Bitmap) o);

        }
    }