您的位置:首页 > 移动开发 > Android开发

AsyncTask异步加载图片 进度条显示进度 -- Android学习之路

2016-08-28 02:24 791 查看

AsyncTask 异步加载网络图片 并使用进度条显示进度

这里我还使用了Thread方式进行加载 作为比较

如果app要进行联网操作请在清单文件(AndroidManifest.xml)中设置权限 在application节点下面就行了

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


为什么使用AsyncTask

AsyncTask定义

AsyncTask执行原理

AsyncTask方法执行步骤

AsyncTask使用时注意事项

AsyncTask取消正在执行的任务

Example 示例

为什么使用AsyncTask

异步任务

由于Android规定,主线程要进行UI绘制和事件响应,UI绘制和事件响应必须在主线程进行 一些耗时的操作不能在主线程中进行,一旦时间超过5秒 就会出现 ANR(无响应)问题,每次耗时操作都要另开线程进行操作,但是呢有些操作我们还涉及到一些UI控件的操作,由于一切关于UI的操作必须在主线程进行 这样 来回切换显得特别麻烦,所以AsyncTask的作用就显现出来了

AsyncTask定义

public abstract class AsyncTask<Params,Progress,Result>


Params 第一个参数:输入参数 是doInbackground()方法的参数类型

Progress 第二个参数:进度值 onProgressUpdate()方法的参数类型 ;主要用来反映进度值 ,如果不需要 可设置为Void

Result 第三个参数:结果类型 doInbackground()方法的的返回值类型 也是 doPostExecute()的参数类型

AsyncTask执行原理

知道了 为什么使用 AsyncTask就好理解了,它的主要任务就是为了在 主线程和子线程中来回切换比较方便,所以它的执行 就分为主线程执行和后台执行;一张图简单明了



AsyncTask 方法执行步骤

其实上面一张图已经能看出大概了,这里再详细的记一下

execute() 在主线程调用 用来启动 异步任务 ,一定要在主线程调用哦

onPreExecute() 在execute()执行后立即执行此方法 一般在执行后台任务前对一些UI进行标记 对后台数据进行处理

doInbackground() 在 onPreExecute()执行后 立即执行此方法 参数是 execute()方法 的参数 会传入到这里,主要在里进行一些耗时的操作,可以使用publishProgress()来跟新进度 返回值就是后台任务的返回结果,

onProgressUpdate() 在 doInbackground 中调用publishProgress才会执行 ,不调用就不会执行 是传入进度值 在界面显示进度

onPostExecute() 在doInbackground()执行完毕后调用 参数时 doInbackground的返回结果 ,在这里对结果进行处理显示到UI控件中

cancel() 取消任务 ,这个手动调用哦

注意事项

execute() 必须在UI主线程中调用

不能在 doInbackground()中进行有关于 UI的操作

除了 execute方法可以手动调用 ,其他方法都不能手动调用

一个AsyncTask 任务实例只能执行一次 ,第二次就会报错

关于取消任务 cancel(true)

在取消任务时 如果任务正在执行 (doInbackground()方法正在运行) 时取消 不会影响 doInbackground方法的执行

只是不会调用doPostExecute()方法而已 ,而且就算调用了publishProgress方法 onProgressUpdate也不会执行了,

所以 不是真正的取消操作 ,只是取消了 在UI主线程的操作,不调用onPostExecute()和onProgressUpdate()方法;

亲测日志:



这是在doInbackground()中的日志信息 可以看出 任务已经在取消状态,但是还是在运行

正确取消姿势:在doInbackground中加判断代码

if (isCancelled()){        //如果取消了任务 就不执行
return null;
}


取消任务的代码:

if (myAsync!=null && myAsync.getStatus() == AsyncTask.Status.RUNNING){
myAsync.cancel(true);

}


加载网络图片 并显示进度

开始贴代码咯

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.skymxc.demo.downloadimage.MainActivity">

<EditText
android:id="@+id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入图片下载URL"
android:singleLine="true"/>

<Button
android:id="@+id/down_thread"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="结合Thread 下载"
android:onClick="click"
android:textAllCaps="false"/>
<ImageView
android:id="@+id/img1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="center"
android:maxWidth="100dp"
android:maxHeight="100dp"
android:scaleType="fitCenter"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/down_async"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="使用 AsyncTask 下载"
android:onClick="click"
android:textAllCaps="false"/>
<Button
android:id="@+id/cancel_async"
android:layout_width="0dp"
android:layout_weight="0.5"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="停止任务"
android:onClick="click"
android:enabled="false"
android:textAllCaps="false"/>
</LinearLayout>

<ProgressBar
android:id="@+id/pb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:max="100"
android:maxHeight="4dp"
android:minHeight="4dp"
style="?android:attr/progressBarStyleHorizontal"
/>
<!--android:progressDrawable="@drawable/progress_bg"-->

<ImageView
android:id="@+id/img2"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="center"
android:maxWidth="100dp"
android:maxHeight="100dp"
android:scaleType="fitCenter"/>
</LinearLayout>


完整java源码

package com.skymxc.demo.downloadimage;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends AppCompatActivity {

private EditText edit ;
private ImageView img1 ;
private ImageView img2;
private ProgressBar pb;
private String urlStr ;
private Button btstart;
private Button btCanel;
private MyAsync myAsync;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = (EditText) findViewById(R.id.url);
img1 = (ImageView) findViewById(R.id.img1);
img2 = (ImageView)findViewById(R.id.img2);
pb = (ProgressBar) findViewById(R.id.pb);
btCanel = (Button) findViewById(R.id.cancel_async);
btstart = (Button) findViewById(R.id.down_async);
}

public  void click(View v){

switch (v.getId()){
case R.id.down_thread:
Toast.makeText(MainActivity.this,"开始下载",Toast.LENGTH_SHORT).show();
loadImage();

break;
case R.id.down_async:
String url = edit.getText().toString();
myAsync = new MyAsync();
pb.setProgress(0);
myAsync.execute(url);
pb.setProgress(100);
break;
case R.id.cancel_async:
if (myAsync!=null && myAsync.getStatus() == AsyncTask.Status.RUNNING){
myAsync.cancel(true);
btCanel.setEnabled(false);
btstart.setEnabled(true);
}else{
btCanel.setEnabled(true);
btstart.setEnabled(false);
}
break;
}
}

/**
* 启动新线程下载图片
*/
private void loadImage(){
new Thread(){
@Override
public void run() {
urlStr = edit.getText().toString();       //获取下载的地址
Log.e("Tag","下载地址:"+urlStr);
HttpURLConnection connection = null;    //url连接
try {
URL url = new URL(urlStr);
connection= (HttpURLConnection) url.openConnection();   //打开连接
connection.setRequestMethod("GET");                 //设置访问方式 默认是GET 必须为大写
connection.setDoInput(true);                        //从网络读取数据 默认是true
//  connection.setDoOutput(false);                      //上传数据 但是请求方法必须是post 默认是true
connection.setReadTimeout(10000);                   //设置读取超时时间 毫秒单位
connection.setConnectTimeout(10000);                //设置连接超时时间 毫秒单位
// connection.setRequestProperty("Content-Type","text/plain;charset=utf-8");//上传数据时使用,可以对增加多个请求参数
int code = connection.getResponseCode();            //获取网络请求响应吗 常用:200,404 500
Log.e("Tag","========网络请求响应吗:"+code);
if (code==200){
InputStream is = connection.getInputStream();       //获取到输入流
final Bitmap bmp= BitmapFactory.decodeStream(is);          //通过位图工厂将输入流转换为位图
runOnUiThread(new Runnable() {
@Override
public void run() {
img1.setImageBitmap(bmp);
}
});
}else{
//关于UI的操作只能在 主线程进行  runOnUiThread :将操作寄送到主线程运行
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"网络请求错误",Toast.LENGTH_SHORT).show();
}
});
}

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}
finally {
if (connection!=null){
connection.disconnect();    //断开连接
}
}

}
}.start();
}

/**
* 使用 异步任务下载图片 并显示进度
* 参数1 String  就是 doInbackground() 的参数类型 我们的代码就在这里写 系统默认调用
* 参数2 Integer      onProgressUpdate() 的参数类型 系统不会自动调用此方法 手动调用:publishProgress()
* 参数3 Bitmap       doInbackground() 的返回值类型 也是 onPostExecute() 的参数类型
*/
class MyAsync extends AsyncTask<String ,Integer,Bitmap>{

/**
* 在 doInbackground() 执行前,系统自动调用 在主线程运行
*/
@Override
protected void onPreExecute() {
Toast.makeText(MainActivity.this,"异步任务开始执行下载",Toast.LENGTH_SHORT).show();
//  super.onPreExecute();
btstart.setEnabled(false);
btCanel.setEnabled(true);
}

/**
* 不在主线程 执行
* @param strings url
* @return 位图
*/
@Override
protected Bitmap doInBackground(String... strings) {

HttpURLConnection connection =null;
try {
URL url = new URL(strings[0]);
connection= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setConnectTimeout(20000);
int code = connection.getResponseCode();
if (code==200){
//为了显示进度条这里使用 字节数组输出流
InputStream is = connection.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int length =-1 ;
int progress =0;    //进度
int count = connection.getContentLength();  //获取内容产固定
byte[] bs = new byte[5];
while ((length=is.read(bs))!=-1){
progress+=length;    //进度累加
if (count ==0){
publishProgress(-1);
}else{
//进度值改变通知
publishProgress((int)((float)progress/count*100));
}

Log.e("Tag","=任务是否取消:"+isCancelled()+"=======任务进度:"+(int)((float)progress/count*100)+"%");
if (isCancelled()){//如果取消了任务 就不执行
return null;
}
//由于我这网速太快,为了看到进度条就睡眠一会吧
//     Thread.sleep(10);

bos.write(bs,0,length);
}
Log.e("Tag","=========任务完成");
return BitmapFactory.decodeByteArray(bos.toByteArray(),0,bos.size());

}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (connection!=null){
connection.disconnect();
}
}
return null;
}

/**
* 在 doInbackground() 执行后 系统自动调用  在主线程运行
* @param bitmap 位图
*/
@Override
protected void onPostExecute(Bitmap bitmap) {
Log.e("Tag","===============任务是否取消:"+isCancelled());
Toast.makeText(MainActivity.this, "AsyncTask 下载完成,进行UI绘制", Toast.LENGTH_SHORT).show();
img2.setImageBitmap(bitmap);    //设置位图
// super.onPostExecute(bitmap);
btstart.setEnabled(true);
btCanel.setEnabled(false);
}

/**
* 系统不会自动调用 使用 publishProgress() 调用
* 在主线程执行
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values) {
int progress = values[0];       //进度值
if (progress!=-1) {
pb.setProgress(progress);
}
}
}
}


来张效果图吧





github地址:

https://github.com/sky-mxc/AndroidDemo/tree/master/downloadimage
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: