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

来源:互联网 发布:淘宝图片美工软件 编辑:程序博客网 时间:2024/05/16 17:57

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

1 0