【问题标题】:Android load images from URL into custom listview adapter without PicassoAndroid 将图像从 URL 加载到没有 Picasso 的自定义列表视图适配器中
【发布时间】:2016-05-29 14:20:17
【问题描述】:

我正在尝试从 url 加载图像并且我使用了 Picasso,但是如果可能的话,我想知道如何在没有外部库的情况下做到这一点。我知道我必须让 Asynctask 运行,但我不确定如何实现它。

这是我的 getview 代码

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View row = convertView;
    if(position==0){

        NewsObj currNews = news.get(position);
        DataHandler dh;
        if(convertView==null){
            LayoutInflater inflater = (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            row = inflater.inflate(R.layout.firstnews,parent,false);
            dh = new DataHandler();
            dh.newsTitle = (TextView)row.findViewById(R.id.newsTitle);
            dh.newsDate = (TextView)row.findViewById(R.id.newsDate);
            dh.newsIcon = (ImageView)row.findViewById(R.id.newsIcon);
            row.setTag(dh);
        }else{
            dh = (DataHandler)row.getTag();
        }
        NewsObj no = (NewsObj)this.getItem(position);
        new AsyncDownloadTask().execute(row,no.getImgurl());
        dh.newsTitle.setText(no.getTitle());
        dh.newsDate.setText(no.getDate());

    }else{

        NewsObj currNews = news.get(position);
        DataHandler dh;
        if(convertView==null){
            LayoutInflater inflater = (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            row = inflater.inflate(R.layout.newslist,parent,false);
            dh = new DataHandler();
            dh.newsTitle = (TextView)row.findViewById(R.id.newsTitle);
            dh.newsDate = (TextView)row.findViewById(R.id.newsDate);
            dh.newsIcon = (ImageView)row.findViewById(R.id.newsIcon);
            row.setTag(dh);
        }else{
            dh = (DataHandler)row.getTag();
        }
        NewsObj no = (NewsObj)this.getItem(position);
        new AsyncDownloadTask().execute(row,no.getImgurl());

        dh.newsTitle.setText(no.getTitle());
        dh.newsDate.setText(no.getDate());

    }
    return row;
}


 private class AsyncDownloadTask extends AsyncTask<Object, String, Bitmap>{

    private View view;
    private Bitmap bitmap = null;
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if(bitmap!=null&&view!=null){
            ImageView newsIcon = (ImageView)view.getTag(R.id.newsIcon);
            newsIcon.setImageBitmap(bitmap);
        }
    }

    @Override
    protected Bitmap doInBackground(Object... params) {
        view = (View)params[0];
        String uri = (String)params[1];
        try{
            InputStream inputStream = new URL(uri).openStream();
            bitmap = BitmapFactory.decodeStream(inputStream);
        }catch (Exception e){
            e.printStackTrace();
        }
        return bitmap;
    }
}

这是我的异步任务

更新:遇到空指针异常

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageBitmap(android.graphics.Bitmap)' on a null object reference

【问题讨论】:

    标签: android listview custom-adapter


    【解决方案1】:

    您可以编写自己的代码。但是使用库处理与库关联的所有样板代码。除非另有说明,我还建议您使用库。以下是您在编写自己的代码时需要考虑的一些样板内容。

    1. 内存管理:外部库负责确保图像不会占用您的应用程序可用的所有内存。 Android 位图处理起来非常注重内存,因此最好将此部分交给库。

    2. 处理活动销毁:如果您在图片下载过程中旋转手机,它将重新创建活动,然后您需要处理取消之前的请求并启动它们再次。

    3. 取消以前的请求: 写入图像库后,不再可见的列表视图项目不会继续下载。假设您向下滚动。那么下载属于第一行的图像就没有意义了。您应该取消此类下载并开始下载新图像。图像下载器库就是为了处理这些问题而编写的。

    4. 缓存:图像库使用内存缓存和磁盘缓存来存储下载的位图。因此,他们只会下载新图像,除非它们不可用。

    5. 从 UI 线程加载大位图:假设您的应用程序包含大位图。为了将它们加载到您的视图中,您必须首先从磁盘加载它们。您需要编写代码,以便加载它们不会阻塞主 UI 线程。

    6. 加载相关的图像尺寸:您的应用程序可以运行屏幕密度高的新 Android 设备或屏幕密度低的旧设备。根据您的目标设备,如果您的设备不支持这样的屏幕密度,您将不需要加载全分辨率图像。通常图书馆会为你处理这个,

    这些只是需要考虑的一些样板文件。因此,我强烈建议您为图像加载部分使用一个好的库,除非它非常需要!!!

    【讨论】:

    • 我用毕加索来处理 url 图片的东西。这只是一行。不幸的是,客户不想要额外的库。
    • 您为什么不尝试通过说明我在回答中所说的话来说服客户。多搜索一下就能找到更多解释!
    【解决方案2】:

    您可以使用java.net.URL 将图像加载到 ImageView 中,就像

        ImageView loadedImage;
    
        @override
        protected Bitmap doInBackground(String... url) {
            String URL_OF_IMAGE = url[0];
            Bitmap bitmap = null;
            try {
                InputStream in = new java.net.URL(URL_OF_IMAGE).openStream();
                bitmap= BitmapFactory.decodeStream(in);
            } catch (Exception e) {
            }
            return bitmap;
        }
    
        protected void onPostExecute(Bitmap result) {
            loadedImage.setImageBitmap(result);
        }
    

    但请注意,您应该扩展AsyncTask,它的第一个参数应该是String,最后一个参数应该是Bitmap,就像

    private class DowmloadImage extends AsyncTask<String, Void, Bitmap>
    

    【讨论】:

    • 您好,谢谢您,但是在我的 getview 中我应该在哪里调用它?
    • @JianYA Yah 在getView(); 中通过图片的url 执行AsyncTask。
    • 您可以将其添加到您的答案中吗?我仍然很困惑,因为我不确定如何传递 url。
    • 您必须在使用 getTag 方法之前设置标签,就像 OP(提问者)在他的 newView 方法中设置的一样。见question
    • 这确实直接回答了这个问题。但是在实践中,当您尝试自己处理图像加载时会出现很多问题。我在下面给出了一个清单。请看看他们!
    【解决方案3】:

    您可以使用网络图像视图代替 Imageview。它肯定会让你的生活更轻松。

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/networkImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:background="#000000"/>
    

    这应该替换为所需 XML 文件中的图像视图。

    public ImageLoader getImageLoader() {
        getRequestQueue();
        if (mImageLoader == null) {
            mImageLoader = new ImageLoader(this.mRequestQueue,
                    new LruBitmapCache());
        }
        return this.mImageLoader;
    }
    

    上面的类还创建了一个 ImageCache,它与普通的 volley 缓存一起使用,但只缓存请求的图像。

    设置图像 URL。

    advImage.setImageUrl("Your Image URL", AppController.getInstance().getImageLoader());
    

    相应地调用图像加载器函数。您还可以设置默认占位符图像。

    【讨论】:

    • 对不起,我也不能使用凌空。必须是本地人
    • 没问题.. 但我认为这仍然是比使用 java.net.URL 更好的选择
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 2011-07-08
    相关资源
    最近更新 更多