0

I have a CountDownTimer which calls the ChangeWallpaper() method every 15 seconds. The Wallpaper changes as it should but when I try and open the App, it makes the App Drawer screen unresponsive for few seconds. When the App finally opens, everything that I select takes 5-10 seconds to respond. I read about AsyncTask in Android Developer which is supposed to load the Bitmaps outside the UI thread and prevent the App from hanging, but it doesn't seem to be working.

The following code is inside my Activity class:

/** changeWallpaper() **/ - called by CountDownTimer every 15 seconds
protected void changeWallpaper() throws IOException {
    Integer totalimages = finallist.size();

    if (lastloopcount == totalimages) { // if end of the list of images is reached, it resets and goes back to top.
        loopcount = 0;
        lastloopcount = 0;
    }

    for (String imagepath : finallist) { // "finallist" is global variable with all the image's paths in an array list. The Loop count is to select the next image in the array list every 15 seconds.
        loopcount++;
        if (loopcount > lastloopcount) {
            lastloopcount = loopcount;
            loopcount = 0;

            WallpaperManager wm = WallpaperManager.getInstance(this);
            wm.setBitmap(decodeImageFromPath(imagepath));

            break;
        }
    }
}

/** AsyncTask Wallpaper Load **/
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    public BitmapWorkerTask(ImageView imageView) {
        new WeakReference<ImageView>(imageView);
    }

    @Override
    protected Bitmap doInBackground(Integer... params) {
        return null;
    }
}

/** decodeImageFromPath() **/
public Bitmap decodeImageFromPath(String imagepath) {
    DisplayMetrics displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    int height = displayMetrics.heightPixels;
    int width = displayMetrics.widthPixels << 2;

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imagepath, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, width, height);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(imagepath, options);
}

/** WallpaperManager (Method) **/
public static int calculateInSampleSize(
    BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // ... Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;

    int stretch_width = Math.round((float)width / (float)reqWidth);
    int stretch_height = Math.round((float)height / (float)reqHeight);

    if (stretch_width <= stretch_height) return stretch_height;
    else return stretch_width;
}
  1. Have I used the AsyncTask function correctly?
  2. Is there an easier way to write this?

Thanks in advance.

EDIT:

/** Spinner **/
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    String chosenTime = parent.getItemAtPosition(position).toString();
    int chosenTimeNew = 0;
    if (chosenTime.contains("sec")) {
        chosenTime = chosenTime.replace(" sec","");
        chosenTimeNew = Integer.parseInt(chosenTime) * 500;
    } else if (chosenTime.contains("min") ) {
        chosenTime = chosenTime.replace(" min","");
        chosenTimeNew = Integer.parseInt(chosenTime) * 30000;
    } else if (chosenTime.contains("hour")) {
        chosenTime = chosenTime.replace(" hour","");
        chosenTimeNew = (Integer.parseInt(chosenTime) * 30000) * 60;
    } else if (chosenTime.contains("day")) {
        chosenTime = chosenTime.replace(" day","");
        chosenTimeNew = ((Integer.parseInt(chosenTime) * 30000) * 60) * 24;
    }
    rSpeed = chosenTimeNew;
}

EDIT 2:

Called by CountDownTimer():

new BitmapWorkerTask(null).execute(imagepath);

Then:

    /** AsyncTask Wallpaper Load **/
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {

    public BitmapWorkerTask(ImageView imageView) {
        new WeakReference<ImageView>(imageView);
    }

    @Override
    protected Bitmap doInBackground(String... params) {

        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int height = displayMetrics.heightPixels;
        int width = displayMetrics.widthPixels << 2;

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(params[0], options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, width, height);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;

        Bitmap bmp = BitmapFactory.decodeFile(params[0], options);
        return bmp;
    }

    protected void onPostExecute(Bitmap bmp) {

        Context context = getApplicationContext();
        WallpaperManager wm = WallpaperManager.getInstance(context);
        try {
            wm.setBitmap(bmp);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

    /** WallpaperManager (Method) **/
public static int calculateInSampleSize(
    BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // ... Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;

    int stretch_width = Math.round((float)width / (float)reqWidth);
    int stretch_height = Math.round((float)height / (float)reqHeight);

    if (stretch_width <= stretch_height) return stretch_height;
    else return stretch_width;
}
KickAss
  • 4,210
  • 8
  • 33
  • 41
  • 2
    You don't even use your `BitmapWorkerTask`! There's no magic that does arbitrary parts of your code in background just when you write some `AsyncTask`into your code. You've got to use it too, you know. – Ridcully Apr 01 '13 at 17:07
  • if I add the decodeImageFromPath() to the doInBackground(), how can I pass the imagepath variable to the decodeImageFromPath()?, imagepath is need to be defined inside decodeImageFromPath() but instead of defining it, I need to use the contents of imagepath determined inside the ChangeWallpaper() – KickAss Apr 01 '13 at 17:12
  • See the edit to my answer, please. – Ridcully Apr 01 '13 at 17:21
  • Changed the code. But the UI still behaves the same. Unresponsive – KickAss Apr 01 '13 at 18:41

2 Answers2

1

Your main code(processing the bitmap) should be called from within the doInBackground method. Else it's the same as a synchronous call here.

    @Override
    protected Bitmap doInBackground(String... params) {
        Bitmap bmp = decodeImageFromPath(params[0]);
        return bmp;
    }

     protected void onPostExecute(Bitmap bmp) {
        wm.setBitmap(bmp)
     }
new BitmapWorkerTask ().execute(imagePath);

http://developer.android.com/reference/android/os/AsyncTask.html

You can refer to the example on this link.

Kumar Bibek
  • 9,016
  • 2
  • 39
  • 68
0

You don't even use your BitmapWorkerTask! There's no magic that does arbitrary parts of your code in background just when you write some AsyncTaskinto your code. You've got to use it too, you know.

Move the long lasting parts of your codes into the doInBackground() method of the AsyncTask and invoke it like so: new BitmapWorkerTask().execute();

EDIT

To pass the image-path, change the definition of your BitmapWorkerTask like to something like this ... extends AsyncTask<String, Void, Bitmap> ... (note the String instead of the Integer), and pass the image-path as parameter to the execute() method.

new BitmapWorkerTask().execute(imagePath);

Be aware that now this runs asynchronously, so the execute() call returns immediately, but the loading of the image will take some time still.

Also read the Painless Threading article.

Ridcully
  • 23,362
  • 7
  • 71
  • 86