简体   繁体   中英

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 . 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.

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 .

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.

I can't use AsyncTask since I am extending ContextWrapper and thus can't also extend AsyncTask . Is there a way to wait for my thread to finish and then return without blocking my UI thread ?

I can't use AsyncTask since I am extending ContextWrapper and thus can't also extend AsyncTask.

So, get rid of of 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 .

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

after downloading the Image

resultDrawable = Drawable.createFromPath(imagePath); 

place the RunOnUIThread and create callback to the Fragment/Activity. this callback infrom the UI that the Image is ready so you can place it inside the 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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