加载位图时,应用程序UI变得无法响应

时间:2013-04-01 17:00:52

标签: java android bitmap android-asynctask wallpaper

我有一个CountDownTimer,它每隔15秒调用一次ChangeWallpaper()方法。壁纸会改变,但是当我尝试打开应用程序时,它会使应用程序抽屉屏幕无响应几秒钟。当应用程序最终打开时,我选择的所有内容都需要5-10秒才能响应。我在Android Developer中读到了AsyncTask,它应该在UI线程之外加载Bitmaps并阻止App挂起,但它似乎没有用。

以下代码位于我的Activity类中:

/** 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. 我是否正确使用了AsyncTask功能?
  2. 有更简单的方式来写这个吗?
  3. 提前致谢。

    编辑:

    /** 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;
    }
    

    编辑2:

    由CountDownTimer()调用:

    new BitmapWorkerTask(null).execute(imagepath);
    

    然后:

        /** 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;
    }
    

2 个答案:

答案 0 :(得分:1)

应该在doInBackground方法中调用主代码(处理位图)。否则它与此处的同步调用相同。

    @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

您可以参考此链接上的示例。

答案 1 :(得分:0)

您甚至不使用BitmapWorkerTask!当你在代码中写一些AsyncTask时,没有任何魔法能够在后台执行代码的任意部分。你知道,你也必须使用它。

将代码的持久部分移动到AsyncTask的doInBackground()方法中,然后调用它:new BitmapWorkerTask().execute();

修改

要传递图像路径,请将BitmapWorkerTask的定义更改为类似... extends AsyncTask<String, Void, Bitmap> ...的内容(请注意字符串而不是整数),并将图像路径作为execute()方法的参数。

new BitmapWorkerTask().execute(imagePath);

请注意,现在这是异步运行的,所以execute()调用会立即返回,但是加载图像还需要一些时间。

另请阅读Painless Threading文章。