简体   繁体   English

如何等待下载线程完成然后返回而又不阻塞UI线程?

[英]How to wait for downloading thread to finish and then return without blocking UI thread?

I am trying to make a class to download an image, store it and then return it as a Drawable . 我正在尝试使一个类下载图像,存储图像,然后将其作为Drawable返回。 The file need not be downloaded multiple times, but only just the first time. 无需多次下载文件,而仅是第一次下载。

Here is my class : 这是我的课:

package com.ishan.drawabletest;
..........................
public class DrawableProvider extends ContextWrapper{

Drawable resultDrawable;

public DrawableProvider(Context base) {
    super(base);
}

public Drawable get(final String fileURL) {
    // File name that is being downloaded
    String downloadedFileName = fileURL.substring(fileURL.lastIndexOf("/")+1);
    final String imagePath = getFilesDir() + "/" + downloadedFileName;

    // Checking if the file exists or not
    final File file = new File(imagePath);
    if(file.exists()) {
        // The image already exists, have to only return it by converting into drawable
        resultDrawable = Drawable.createFromPath(imagePath);
        return resultDrawable;
    } else {
        // The image doesn't exists already.
        Thread t = new Thread() {
            @Override
            public void run() {
                try {
                    // Downloading the image here
                    ..................
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                resultDrawable = Drawable.createFromPath(imagePath);
            }
        };
        t.start();
        // Waiting for the thread to finish before returning using join
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return resultDrawable;
    }
}
}

and this class is called and used like this. 此类被称为和使用。 :

ImageView permanentImageView = (ImageView) findViewById(R.id.permaImageView);
    DrawableProvider dp = new DrawableProvider(this);
    permanentImageView.setImageDrawable(dp.get("http://youthvibe2014server.herokuapp.com/public/selenaGomez.jpg"));

It works fine for the cases when the image is already available. 对于图像已经可用的情况,它工作正常。 The problem is that if I do not wait ( ie if join is removed ) for the thread to finish and return immediately, then the screen does not contains an Image not even the default image (defined in XML) which should be there till the time the download finishes. 问题是,如果我不等待 (即如果删除了join)让线程完成并立即返回,则屏幕上将不包含Image,甚至没有默认图像(以XML定义),直到该时间为止下载完成。

It looks like this. 看起来像这样。

没有图像甚至没有默认图像的屏幕。

I guess it is like this because my get method isn't waiting for the thread to finish and returning null , thus the permanentImageView is containing null . 我猜是这样的,因为我的get方法没有等待线程完成并返回null ,因此permanentImageView包含null

But if I do wait for the thread to finish. 但是,如果我确实等待线程完成。 The screen eventually displays the downloaded image, but for the time being it goes blank, and looks like this. 屏幕最终显示下载的图像,但暂时变为空白,看起来像这样。 :

等待线程完成时的黑屏

I guess this is because when I am waiting for the thread to finish my UI thread is blocked for the time being. 我猜这是因为当我等待线程完成时,UI线程暂时被阻塞了。

I can't use AsyncTask since I am extending ContextWrapper and thus can't also extend AsyncTask . 我不能使用AsyncTask因为我正在扩展ContextWrapper ,因此也不能扩展AsyncTask Is there a way to wait for my thread to finish and then return without blocking my UI thread ? 有没有一种方法可以等待我的线程完成然后返回而不会阻塞我的UI线程?

I can't use AsyncTask since I am extending ContextWrapper and thus can't also extend AsyncTask. 我无法使用AsyncTask,因为我正在扩展ContextWrapper,因此也无法扩展AsyncTask。

So, get rid of of ContextWrapper . 因此,摆脱ContextWrapper You are not using it for its intended purpose anyway. 无论如何,您都没有将其用于预期目的。 Inheriting from it is not doing anything useful for you, so inherit from AsyncTask . 从它继承对您没有任何帮助,因此从AsyncTask继承。

Or, better yet, use any one of a seemingly infinite number of existing libraries that does this work for you. 或者,更好的是,使用看似无限数量的现有库中的任何一种来为您工作。

One Possible Solution : send the Activity to your class and use 一种可能的解决方案:将活动发送给您的班级并使用

activity.RunOnUiThread(Runnable runnable)

in the runnable you can inform the user like a Callback. 在运行时,您可以像回调一样通知用户。 you can call this function from a Background Thread. 您可以从后台线程调用此函数。

RunOnUiThread API Document RunOnUiThread API文档

after downloading the Image 下载图像后

resultDrawable = Drawable.createFromPath(imagePath); 

place the RunOnUIThread and create callback to the Fragment/Activity. 放置RunOnUIThread并创建对Fragment / Activity的回调。 this callback infrom the UI that the Image is ready so you can place it inside the ImageView. 此回调从图像准备就绪的UI进入,因此您可以将其放置在ImageView中。

for example create a function that called 例如创建一个函数

public Drawable getDrawable() {
      return resultDrawable;

}

in the Callback itself use this function to place the Image inside the ImageView. 在Callback本身中,使用此功能可将Image放置在ImageView中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM