4.下载图片文件

作者: Jennyni1122 | 来源:发表于2018-11-08 10:34 被阅读4次

    4.1 问题

    应用程序需要从Web或其他远程服务器下载一张图片并显示。

    4.2 解决方案

    (API Level 4)
    使用AsyncTask在后台线程中下载数据。AsyncTask是封装类,它可以很方便地让需要长时间允许操作的线程在后台允许;同样,它通过一个内部线程池管理线程的并发。除了管理后台线程外,在操作执行前、中、后都会提供回调方法,让你可以做任何需要在主UI线程中进行的更新。

    4.3 实现机制

    在下载图片的环境中,我们会创建ImageView的一个子类,叫做WebImageView,它会从远程来源中延迟加载一张图片并且在该图片可用时就显示它。下载过程会在一个AsyncTask操作中执行(参见以下代码清单)。
    WebImageView

    public class WebImageView extends ImageView {
    
        private Drawable mPlaceholder,mImage; 
    
        public WebImageView(Context context) {
            super(context,null);
        }
    
        public WebImageView(Context context, AttributeSet attrs) {
            super(context, attrs,0);
        }
    
        public WebImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public void setPlaceholder(Drawable drawable) {
            this.mPlaceholder = drawable;
            if (mImage == null){
                setImageDrawable(mPlaceholder);
            }
        }
    
        public void setPlaceholder(int resid) {
            mPlaceholder = getResources().getDrawable(resid);
            if (mImage == null){
                setImageDrawable(mPlaceholder);
            }
        }
        
        public void setImageURl(String url) {
            DownloadTask task = new DownloadTask();
            task.execute(url);
        }
    
    
        private class DownloadTask extends AsyncTask<String,Void,Bitmap> {
            @Override
            protected Bitmap doInBackground(String... params) {
                String url = params[0];
                try {
                    URLConnection connection = (new URL(url)).openConnection();
                    InputStream is = connection.getInputStream();
                    BufferedInputStream bis = new BufferedInputStream(is);
    
                    ByteArrayBuffer baf = new ByteArrayBuffer(50);
                    int current = 0;
                    while ((current = bis.read()) != -1) {
                        baf.append((byte) current);
                    }
                    byte[] imageData = baf.toByteArray();
                    return BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
                } catch (Exception exc) {
                    return null;
                }
            }
    
            @Override
            protected void onPostExecute(Bitmap result) {
                mImage = new BitmapDrawable(getContext().getResources(),result);
                if (mImage != null){
                    setImageDrawable(mImage);
                }
            }
        }
    }
    

    正如你所看到的那样,WebImageView是Android的mageView小部件的一个简单扩展。在远程内容下载完成之前,setPlaceholderImage()会为要显示的图片设置一个本地Drawable。大多数有趣的工作都是从使用setImageUrl()向视图传入一个给定远程URL开始的,该方法表示自定义的AsyncTask开始工作了。
    请注意,AsyncTask是强类型化的,它需要三个值:输入参数、进度值、结果值。在这种情况下,会传递给任务的execute()方法一个字符串,而后台操作应该返回一个Bitmap。对于中间的进度值,我们在本例中并不会使用,因此它被设置为Void。继承AsyncTask后,唯一需要实现的方法就是doInBackground(),它定义了后台线程中需要大量运行的操作。在前面的示例中,这里是与提供的远程URL进行连接以及下载图片的地方。完成后,我们会试图用下载的数据创建一个Bitmap。发生任何错误时,操作将中止并返回null。

    要点:
    Android UI类是线程不安全的。确保在更新UI时使用运行在主线程上的回调方法。不要在doInBackground()中更新视图。

    以下两段代码清单展示了在一个Activity中使用这个类的示例。因为这个类不是android.widget或android.view包的一部分,所以在XML中使用它时必须先指定它的完全限定包名。

    res/layout/main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.jennyni.webimageviewdemo.MainActivity">
        
        <com.jennyni.webimageviewdemo.WebImageView
            android:id="@+id/webImage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
        </com.jennyni.webimageviewdemo.WebImageView>
    
    </LinearLayout>
    

    示例Activity

    public class WebImageActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            WebImageView  imageView = (WebImageView)findViewById(R.id.webImage);
            imageView.setPlaceholderImage(R.drawable.ic_launcher);
            imageView.setImageUrl("http://lorempixel.com/400/200");
    
        }
    }
    

    本例中,首先会设置一张本地图片(应用程序图标)作为WebImageView的占位图片,这张图片会立刻显示给用户。然后我们会告诉视图从Web上获取Apress的徽标图片。如前所述,这里会在后台下载图片,下载完成后会替换掉视图中的占位图片。正是因为创建后台操作的简单性,Android团队才会把AsyncTask叫作“无痛苦使用线程”。

    相关文章

      网友评论

        本文标题:4.下载图片文件

        本文链接:https://www.haomeiwen.com/subject/sclgwftx.html