2

我在我的 Android 设备上运行了以下代码。它工作得很好,可以很好地显示我的列表项。它也很聪明,它只在 ArrayAdapter 需要数据时才下载数据。但是,在下载缩略图时,整个列表会停止,并且在完成下载之前无法滚动。有没有什么方法可以让这个线程继续滚动,所以它仍然会愉快地滚动,也许显示下载图像的占位符,完成下载,然后显示?

我想我只需要将我的 downloadImage 类放入它自己的线程中,以便它与 UI 分开执行。但是如何将它添加到我的代码中是个谜!

对此的任何帮助将不胜感激。

private class CatalogAdapter extends ArrayAdapter<SingleQueueResult> {

    private ArrayList<SingleQueueResult> items;

    //Must research what this actually does!
    public CatalogAdapter(Context context, int textViewResourceId, ArrayList<SingleQueueResult> items) {
        super(context, textViewResourceId, items);
        this.items = items;

    }

    /** This overrides the getview of the ArrayAdapter. It should send back our new custom rows for the list */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View v = convertView;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.mylists_rows, null);

        }
        final SingleQueueResult result = items.get(position);
        // Sets the text inside the rows as they are scrolled by!
        if (result != null) {

            TextView title = (TextView)v.findViewById(R.id.mylist_title);
            TextView format = (TextView)v.findViewById(R.id.mylist_format);
            title.setText(result.getTitle());
            format.setText(result.getThumbnail());

            // Download Images
            ImageView myImageView = (ImageView)v.findViewById(R.id.mylist_thumbnail);
            downloadImage(result.getThumbnail(), myImageView);

        }

        return v;
    }
}

// This should run in a seperate thread
public void downloadImage(String imageUrl, ImageView myImageView) {

    try {
        url = new URL(imageUrl);
        URLConnection conn = url.openConnection();
        conn.connect();
        InputStream is = conn.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(is);
        Bitmap bm = BitmapFactory.decodeStream(bis);
        bis.close();
        is.close();
        myImageView.setImageBitmap(bm);
    } catch (IOException e) {
        /* Reset to Default image on any error. */
        //this.myImageView.setImageDrawable(getResources().getDrawable(R.drawable.default));
    }
}
4

3 回答 3

4

这是我在应用程序中使用的简化版本:

// this lives in Application subclass and is reused
public static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();

// the method itself

    public void attachImage(final String fileUrl, final ImageView view) {
        EXECUTOR.execute(new Runnable() {

            @Override
            public void run() {
                final Drawable image = methodThatGetsTheImage(fileUrl);
                if (image != null) {
                    view.post(new Runnable() {

                        @Override
                        public void run() {
                            view.setImageDrawable(drawable);
                        }
                    });
                }
            }
        });
    }
于 2010-04-05T13:17:27.807 回答
1

您还可以查看cwac-thumbnail以获取插入式解决方案(尽管它比上述更简单的解决方案具有更多开销)。我几乎在任何需要下载网络图像的地方都使用它并取得了巨大的成功;您基本上为您的应用程序设置了一些全局缓存选项,然后只需将 ListAdapter 包装在 ThumbnailAdapter 中,其中包含列表中图像视图的 android:ids 列表,并在适配器的 getView 方法中对图像视图调用 setTag(imageUrl) ,然后它处理其余的。

于 2010-04-05T14:15:54.580 回答
0

是的。您应该尽可能避免在 UI 线程上运行。当您在 getView() 中时,您就在 UI 线程上。要打破这样做:

new Thread(new Runnable(){

  public void run() {
    // your code here

  }}).start();

然后,当您需要以某种方式修改视图时,请返回 UI 线程,如下所示:

runOnUiThread(new Runnable(){

  public void run() {
    // your view-modifying code here

  }});

.. 或使用 View.post() 机制。

在您的示例中,将发生的情况是该项目将在图像可供显示之前显示在屏幕上。我建议使用“加载”微调器或其他占位符来向用户指示正在发生的事情。

在实践中,您可以像这样嵌套多次,尽管您会达到简化设计的顺序。匿名类在内存方面可能效率低下,并且在没有取消机制的情况下触发大量线程可能有其自身的缺点。

在 getView() 退出后修改视图的副作用可能会导致您遇到一些困难。某些视图可能需要调用 invalidate() 才能使其更改生效。还要注意,如果您在 getView() 中回收视图,则应确保在执行更改视图的代码时,视图仍在用于您正在应用的内容。setTag()/getTag() 在这里非常有用,可以存储一些数据 ID,您可以稍后检查以确保您的 View 没有被回收。

于 2010-04-05T13:01:43.100 回答