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
- AsyncTask异步加载图片 进度条显示进度 -- Android学习之路
- Android进阶之动态加载图片(AsyncTask异步加载并显示进度条)
- AsyncTask异步加载图片(显示进度条刻度)
- android之GridView异步加载图片时显示加载进度ProgressBar
- 文章标题android之listview异步加载图片时显示加载进度ProgressBar
- Android有效加载图片 之 使用AsyncTask异步加载图片
- Android 异步加载图片-AsyncTask
- Android 异步加载图片-AsyncTask
- Android异步加载学习笔记之三:用AsyncTask实现ListView中的图片数据加载
- AsyncTask案例——异步加载一张图片并显示进度条
- Android之AsyncTask异步加载
- Android异步加载之AsyncTask
- Android自定义圆形进度条,结合AsyncTask下载显示进度
- 学习andriod开发之 异步加载图片--- 使用系统进度条
- Android中的AsyncTask异步加载图片
- 异步加载图片AsyncTask
- AsyncTask异步加载图片
- AsyncTask异步加载图片
- 《C++ GUI Qt 4 编程》 笔记(二)
- Win+E 未指定的错误
- 导航条菜单的制作(一)
- 《C++ GUI Qt 4 编程》 笔记(三)
- 架构之基本概念
- AsyncTask异步加载图片 进度条显示进度 -- Android学习之路
- Swift-->ViewController跳转,转场以及自定义动画
- 文章标题
- sudo 取消密码
- android 多媒体框架服务之StagefrightPlayer和OMXCodec实现原理学习
- Android - 一个似神器而非神器之Palette探索与实践
- 某网络公司工作感想
- 线段树
- fragment更新activity中的界面