当前位置: 首页 > 知识库问答 >
问题:

在后台线程中从流中获取位图

况浩邈
2023-03-14

我有ListView显示从服务器下载的图像。我需要执行的步骤是:

  1. 调用api获取流。
  2. 从该流中获取字节[]。
  3. 将这些字节保存在File对象(在sd卡中)中。
  4. 从该文件路径/位置获取位图。
  5. 在ImageView中显示位图。

前4个步骤需要在后台线程中执行,以保持主线程未被占用,以便用户可以在后台下载图像时顺利滚动列表。第 5 步需要在 UI 线程上执行。

我在后台执行这些步骤时遇到问题。

这就是我在从图像下载API获得成功响应后尝试在后台执行上述4步骤的方式。

Thread thread = new Thread(new Runnable() {
                public void run() {
                    try {
                        // Get bytes from Response
                        byte[] bytes = getBytesFromStream(response.getBody().in());
                        // Save bytes in phone sd card
                        saveBytesToFile(bytes, photoPath);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        // Get bitmap from path
                        Bitmap webBitmap = getBitmap(photoPath);
                        // Show bitmap
                        showBitmap(webBitmap);
                    }
                }
            });

            thread.start();


private void showBitmap(Bitmap bitmap) {
    BitmapDisplayer bd = new BitmapDisplayer(bitmap, photoToLoad);
    Activity a = (Activity) photoToLoad.imageView.getContext();
    a.runOnUiThread(bd);
}

getBytesFromStream()方法从流中提取字节并返回它们。saveBytesToFile()方法将这些字节保存在File对象(sd卡)中。getBitmap()方法从特定路径获取位图。showBitmap()方法显示ImageView上的位图。

现在我的问题是:

>

  • 我做的一切都对吗?

    在Android中,在后台线程中执行某些东西的最佳方式是什么?

    我认为上面的代码仍然阻塞了主线程,因此我无法顺利地滚动列表。如何正确执行这些步骤?

    请帮助我。

  • 共有2个答案

    谈桐
    2023-03-14
    1. 你的5步理论上是对的。
    2. 基本上,最简单的方法是AsyncTask,使用Thread是可以的,但是当您需要经常做后台工作时,您可能需要尝试一些线程策略,例如Execitor来重用线程。
    3. 至于有效地获取加载图像,它不像您的5个步骤那么简单,您应该考虑更多的事情,例如首次下载后将图像缓存在磁盘上,将一些最近加载的位图缓存在内存中并对其进行管理。和滚动一样。当用户滚动列表时,尽量不要加载图像,并且始终加载“正确”(避免加载已经滚动且不可见的图像)ImageView也很重要。
    4. 最后,Smicthe和通用图像加载器是关于图像异步加载的好库。您可以参考它们并制定自己的策略。
    卫仲卿
    2023-03-14

    请改用Picasso。在listview的适配器中执行以下操作:

    @Override 
    public void getView(int position, View convertView, ViewGroup parent) {
          //
          // Other codes
          //
    
          Picasso.with(context).load(string_url).into(imageview);
        }
    
     类似资料:
    • 本文向大家介绍在C#中如何从线程中获取线程ID,包括了在C#中如何从线程中获取线程ID的使用技巧和注意事项,需要的朋友参考一下 线程被定义为程序的执行路径。每个线程定义唯一的控制流。如果您的应用程序涉及复杂且耗时的操作,那么设置不同的执行路径或线程(每个线程执行一个特定的工作)通常会很有帮助。 线程是轻量级进程。使用线程的一个常见示例是现代操作系统对并发编程的实现。使用线程可以节省CPU周期,并提

    • 问题内容: 我想知道是否有替代 使用 流 ? 问题答案: 定制收集器可以这样写: 并像这样使用它:

    • 问题内容: 我有一个Java应用程序,其中创建了一些线程(通过)。通过使用,我可以看到它们具有不同的线程ID(LWP列),我想从Java应用程序中获取这些ID。 在我发现的与此主题相关的大多数文章中,解决方案是使用。 但是,使用该方法可以为我提供主线程的PID(即使我从其中一个线程调用它),因此它并不能真正解决我的问题。 有什么方法可以获取应用程序创建的每个线程的线程ID ? 是否可以使用JNI完

    • 本文向大家介绍如何在C#中检查线程是否为后台线程,包括了如何在C#中检查线程是否为后台线程的使用技巧和注意事项,需要的朋友参考一下 要检查线程是否是后台线程,代码如下: 示例 输出结果 这将产生以下输出- 示例 让我们看另一个例子- 输出结果 这将产生以下输出-

    • 问题内容: 我想从主Java程序中产生一个Java线程,并且该线程应单独执行而不会干扰主程序。应该是这样的: 用户启动的主程序 做一些业务工作,应该创建一个可以处理后台进程的新线程 一旦创建线程,主程序就不要等到生成的线程完成。实际上,它应该是无缝的。 问题答案: 一种简单的方法是自己手动生成线程: 另外,如果您需要产生多个线程或需要重复执行,则可以使用更高级别的并发API和执行程序服务: