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
相关文章推荐
- android 多媒体框架服务之StagefrightPlayer和OMXCodec实现原理学习
- 这么理解RxAndroid之一认识RxAndroid
- Android 高仿 IOS 滚轮选择控件
- android自定义Button样式(清晰简单)
- Android 混淆打包之类名指定
- 安卓动画入门教程 Animation in Android(2)
- android获取cpu信息
- Fragment,Activity,FragmentManager之间那点事
- 集成下intent意图
- Android广播的意义及两种注册方式的优缺点
- Android 代码混淆,混淆打包
- Android应用程序(APK)的编译打包过程
- 获取剩余内存和剩余SD卡内存
- Android学习知识点(3)--调用短信功能的实现
- Android 进程间通信之Messenger
- Android AutoCompleteTextView
- Android学习知识点(2)--点击事件的几种写法
- <Android 应用 之路> 百度地图API使用(2)
- <Android 应用 之路> 百度地图API使用(2)
- Android之服务Service