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

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

转载于:https://my.oschina.net/skymxc/blog/799117

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio 中,可以使用 AsyncTask 来实现异步网站上的图片,并模拟下进度条。下面是一个简单的示例代码: ```java public class MainActivity extends AppCompatActivity { private ImageView imageView; private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.imageView); progressBar = findViewById(R.id.progressBar); new DownloadImageTask().execute("https://example.com/image.jpg"); } private class DownloadImageTask extends AsyncTask<String, Integer, Bitmap> { @Override protected void onPreExecute() { super.onPreExecute(); progressBar.setProgress(0); } @Override protected Bitmap doInBackground(String... urls) { String url = urls[0]; Bitmap bitmap = null; try { URL imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection(); conn.setDoInput(true); conn.connect(); int totalSize = conn.getContentLength(); InputStream is = conn.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is, 8192); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; int downloadedSize = 0; while ((len = bis.read(buffer)) != -1) { baos.write(buffer, 0, len); downloadedSize += len; publishProgress((int) ((downloadedSize / (float) totalSize) * 100)); } bitmap = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.size()); baos.flush(); baos.close(); bis.close(); is.close(); } catch (Exception e) { e.printStackTrace(); } return bitmap; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); progressBar.setProgress(values[0]); } @Override protected void onPostExecute(Bitmap result) { super.onPostExecute(result); imageView.setImageBitmap(result); progressBar.setVisibility(View.GONE); } } } ``` 在这个示例中,我们在主线程中调用 `new DownloadImageTask().execute(url)` 来开始异步图片。`DownloadImageTask` 继承自 `AsyncTask` 类,实现了图片的下进度条的更新。在 `doInBackground` 方法中,我们使用 `HttpURLConnection` 来下图片,并在下过程中使用 `publishProgress` 方法来更新进度条。在 `onPostExecute` 方法中,我们将下完成的图片设置到 ImageView 中,并将进度条隐藏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值