文章目录
- 一、同步与异步的概念
- 二、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更新时,变得复杂。
三、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);
}
}