ImageView显示透明base64字符串图像的黑/白背景

时间:2016-03-24 10:23:48

标签: java android image bitmap

我正在使用从开发者android网站下载的DisplayingBitmap.zip将图像异步加载到imageview中。我从webservice接收base64字符串。所以修改了代码,将base64转换为ImageFetcher.class中的位图(DisplaysBitmaps),而不是从url下载图像。

注意:我以base64字符串的形式接收gif图片。

将base64转换为位图

        public Bitmap convertBase64ToImage(String mBase64String) {
            Bitmap bitmap = null;
            try {
                String imageDataBytes = mBase64String.substring(mBase64String.indexOf(",") + 1);
                InputStream stream = new ByteArrayInputStream(Base64.decode(imageDataBytes.getBytes(), Base64.DEFAULT));
                bitmap = BitmapFactory.decodeStream(stream);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return bitmap;
        }
    }

将base64位图转换为文件,以便使用ImageFetcher.class(ShowingBitmaps)中的processBitmap方法获取已解码的已调整大小的位图:

/**
         * The main process method, which will be called by the ImageWorker in the AsyncTask background
         * thread.
         *
         * @param data The data to load the bitmap, in this case, a regular http URL
         * @return The downloaded and resized bitmap
         */
        private Bitmap processBitmap(String data, String imageID) {
            if (BuildConfig.DEBUG) {
                PrintLog.error(TAG, "processBitmap --- imageID " + imageID);
            } 
            Bitmap bitmap = null;
            bitmap = convertBase64ToImage(data);
            if (bitmap != null) {
                File f = null;
                try {
                    //create a file to write bitmap data
                    f = new File(mContext.getFilesDir(), imageID);
                    f.createNewFile();

                    //Convert bitmap to byte array
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100/*ignored for PNG*/, bos);
                    byte[] bitmapdata = bos.toByteArray();

                    //write the bytes in file
                    FileOutputStream fos = new FileOutputStream(f);
                    fos.write(bitmapdata);
                    fos.flush();
                    fos.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                bitmap = decodeSampledBitmapFromFile(f.getAbsolutePath(), mImageWidth, mImageHeight, getImageCache());
            }

            return bitmap;
        }

        @Override
        protected Bitmap processBitmap(Object data, String imageID) {
            return processBitmap(String.valueOf(data), imageID);
        }
来自ImageResizer.class的

decodeSampledBitmapFromFile方法

public static Bitmap decodeSampledBitmapFromFile(String filename, int reqWidth, int reqHeight, ImageCache cache) {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filename, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // If we're running on Honeycomb or newer, try to use inBitmap
        if (DeviceUtils.hasHoneycomb()) {
            addInBitmapOptions(options, cache);
        }

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

在我的课程中实施ImageFetcher.class(ShowingBitmaps.zip)

    private static final String IMAGE_CACHE_DIR = "clubsCategoryIcons";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ImageCache.ImageCacheParams cacheParams = new ImageCache.ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
        cacheParams.setMemCacheSizePercent(0.25f); // Set memory cache to 10% of app memory

        // The ImageFetcher takes care of loading images into our ImageView children asynchronously
        mImageFetcher = new ImageFetcher(getActivity(), getResources().getDimensionPixelSize(R.dimen.image_icon_size));
        mImageFetcher.setLoadingImage(R.drawable.settings_clubs);
        mImageFetcher.addImageCache(getActivity().getSupportFragmentManager(), cacheParams);
    }

将此mImageFetcher对象传递给适配器类,以便为每个项目异步加载图像。

ClubsCategoryAdapter clubsAdapter = new ClubsCategoryAdapter(getActivity(), new ArrayList<ClubsCategoryParser.ClubsCategory>(), mImageFetcher);
recyclerView.setAdapter(clubsAdapter);

ClubsCategoryAdapter.class

public class ClubsCategoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ImageFetcher mImageFetcher;

public ClubsCategoryAdapter(Context context, ArrayList<ClubsCategoryParser.ClubsCategory> clubsCategoryList, ImageFetcher mImageFetcher ) {
        this.context = context;
        this.clubsCategoryList = clubsCategoryList;
        this.mImageFetcher = mImageFetcher;
}

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        final ViewHolder viewHolder = (ViewHolder) holder;
        final ClubsCategoryParser.ClubsCategory singleItem = clubsCategoryList.get(position);
        if (!TextUtils.isNullOrEmpty(singleItem.image_url)) {
                mImageFetcher.loadImage(singleItem.image_url, String.valueOf(singleItem.ID), viewHolder.imgCategoryIcon);
            } 
ImageWorker.class中的

loadImage方法(ShowingBitmaps)

public void loadImage(Object data, String imageID, ImageView imageView) {
        if (data == null) {
            return;
        }

        BitmapDrawable value = null;

        if (mImageCache != null) {
            value = mImageCache.getBitmapFromMemCache(imageID);
        }

        if (value != null) {
            // Bitmap found in memory cache
            imageView.setImageDrawable(value);
        } else if (cancelPotentialWork(data, imageView)) {
            //BEGIN_INCLUDE(execute_background_task)
            final BitmapWorkerTask task = new BitmapWorkerTask(data, imageID, imageView);
            final AsyncDrawable asyncDrawable = new AsyncDrawable(mResources, mLoadingBitmap, task);
            imageView.setImageDrawable(asyncDrawable);
            // NOTE: This uses a custom version of AsyncTask that has been pulled from the
            // framework and slightly modified. Refer to the docs at the top of the class
            // for more info on what was changed.
            task.executeOnExecutor(AsyncTask.DUAL_THREAD_EXECUTOR);
            //END_INCLUDE(execute_background_task)
        }
    }

实际异步处理异步处理图像

 /**
     * The actual AsyncTask that will asynchronously process the image.
     */
    private class BitmapWorkerTask extends AsyncTask<Void, Void, BitmapDrawable> {
        private Object mData;
        private String imageID;
        private final WeakReference<ImageView> imageViewReference;

        public BitmapWorkerTask(Object data, String imageID, ImageView imageView) {
            mData = data;
            this.imageID = imageID;
            imageViewReference = new WeakReference<ImageView>(imageView);
        }

        /**
         * Background processing.
         */
        @Override
        protected BitmapDrawable doInBackground(Void... params) {
            //BEGIN_INCLUDE(load_bitmap_in_background)
            if (BuildConfig.DEBUG) {
                PrintLog.error(TAG, "doInBackground - starting work");
            }

            final String dataString = String.valueOf(mData);
            Bitmap bitmap = null;
            BitmapDrawable drawable = null;

            // Wait here if work is paused and the task is not cancelled
            synchronized (mPauseWorkLock) {
                while (mPauseWork && !isCancelled()) {
                    try {
                        Log.e("pauseWork", "iswaiting -------------");
                        mPauseWorkLock.wait();
                    } catch (InterruptedException e) {
                    }
                }
            }

            Log.e("pauseWork", "iswaiting end -------------");
            // If the image cache is available and this task has not been cancelled by another
            // thread and the ImageView that was originally bound to this task is still bound back
            // to this task and our "exit early" flag is not set then try and fetch the bitmap from
            // the cache
            if (mImageCache != null && !isCancelled() && getAttachedImageView() != null && !mExitTasksEarly) {
                bitmap = mImageCache.getBitmapFromDiskCache(imageID);
            }

            // If the bitmap was not found in the cache and this task has not been cancelled by
            // another thread and the ImageView that was originally bound to this task is still
            // bound back to this task and our "exit early" flag is not set, then call the main
            // process method (as implemented by a subclass)
            if (bitmap == null && !isCancelled() && getAttachedImageView() != null && !mExitTasksEarly) {
                bitmap = processBitmap(mData, imageID);
            }

            // If the bitmap was processed and the image cache is available, then add the processed
            // bitmap to the cache for future use. Note we don't check if the task was cancelled
            // here, if it was, and the thread is still running, we may as well add the processed
            // bitmap to our cache as it might be used again in the future
            if (bitmap != null) {
                if (DeviceUtils.hasHoneycomb()) {
                    // Running on Honeycomb or newer, so wrap in a standard BitmapDrawable
                    drawable = new BitmapDrawable(mResources, bitmap);
                } else {
                    // Running on Gingerbread or older, so wrap in a RecyclingBitmapDrawable
                    // which will recycle automagically
                    drawable = new RecyclingBitmapDrawable(mResources, bitmap);
                }

                if (mImageCache != null) {
                    mImageCache.addBitmapToCache(imageID, drawable);
                }
            }

            if (BuildConfig.DEBUG) {
                PrintLog.error(TAG, "doInBackground - finished work");
            }

            return drawable;
            //END_INCLUDE(load_bitmap_in_background)
        }

        /**
         * Once the image is processed, associates it to the imageView
         */
        @Override
        protected void onPostExecute(BitmapDrawable value) {
            //BEGIN_INCLUDE(complete_background_work)
            // if cancel was called on this task or the "exit early" flag is set then we're done
            if (isCancelled() || mExitTasksEarly) {
                value = null;
            }

            final ImageView imageView = getAttachedImageView();
            if (value != null && imageView != null) {
                if (BuildConfig.DEBUG) {
                    PrintLog.error(TAG, "onPostExecute - setting bitmap");
                }
                setImageDrawable(imageView, value);
            }
            //END_INCLUDE(complete_background_work)
        }

        @Override
        protected void onCancelled(BitmapDrawable value) {
            super.onCancelled(value);
            synchronized (mPauseWorkLock) {
                mPauseWorkLock.notifyAll();
            }
        }

        /**
         * Returns the ImageView associated with this task as long as the ImageView's task still
         * points to this task as well. Returns null otherwise.
         */
        private ImageView getAttachedImageView() {
            final ImageView imageView = imageViewReference.get();
            final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

            if (this == bitmapWorkerTask) {
                return imageView;
            }

            return null;
        }
    }

图片在安装应用时第一次显示正常,但在杀死应用并加载后,同一页显示带有黑/白背景的图片。

我尝试过很多例子和文章......但没有任何帮助。在杀死/退出应用程序后,我不知道它为什么会出现黑/白背景。

1 个答案:

答案 0 :(得分:1)

您的应用程序首次显示图像并在重新打开应用程序后显示黑色背景,因为“ShowingBitmap”应用程序使用JPEG格式将图像缓存到文件系统。如您所知,JPEG不支持透明模式。

请打开 ImageCache 课程并查看#68 行:

private static final CompressFormat DEFAULT_COMPRESS_FORMAT = CompressFormat.JPEG;

为避免黑色背景,我将此值更改为PNG格式:

private static final CompressFormat DEFAULT_COMPRESS_FORMAT = CompressFormat.PNG;

<强>更新

此外,您可以将compressFormat设置为JPEG:

ImageCache.ImageCacheParams cacheParams = new ImageCache.ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
        cacheParams.setMemCacheSizePercent(0.25f);
cacheParams.compressFormat = Bitmap.CompressFormat.JPEG;

它对我有用,希望对你有所帮助。