将原始资产设置为选定drawable的壁纸

时间:2017-07-05 21:05:29

标签: java android gridview wallpaper android-wallpaper

我有一个gridview,其中包含我的drawable文件夹中的图像数组。我现在已经解决了将drawable发送到另一个活动,用户将在将原始文件夹中的图片设置为壁纸之前查看图像。我无法使用drawable资产,因为压缩和合适的图像会因内存不足而导致崩溃。

带有gridview的我的MainActivity文件:

GridView androidGridView;

private Integer asset1 = R.drawable.asset1;
private Integer asset2 = R.drawable.asset2;
private Integer asset3 = R.drawable.asset1;
private Integer asset4 = R.drawable.asset2;
private Integer asset5 = R.drawable.asset1;
private Integer asset6 = R.drawable.asset2;
private Integer[] images = {
        asset1, asset2, asset3,
        asset4, asset5, asset6
};

Integer[] imagesIDs = {
        R.raw.asset1, R.raw.asset2, R.drawable.asset1,
        R.drawable.asset1, R.drawable.asset1, R.drawable.asset1,
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    androidGridView = findViewById(R.id.gridview_android_example);
    androidGridView.setAdapter(new ImageAdapterGridView(this));

    androidGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent,
                                View v, int position, long id) {
            int imageRes = images[position];

            Intent intent = new Intent(MainActivity.this, ViewActivity.class);
            intent.putExtra("IMAGE_RES", imageRes);
            startActivity(intent);
        }
    });

}

public class ImageAdapterGridView extends BaseAdapter {
    private Context mContext;

    public ImageAdapterGridView(Context c) {
        mContext = c;
    }

    public int getCount() {
        return images.length;
    }

    public Object getItem(int position) {
        return null;
    }

    public long getItemId(int position) {
        return 0;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView mImageView;

        if (convertView == null) {
            mImageView = new ImageView(mContext);
            mImageView.setLayoutParams(new GridView.LayoutParams(525, 350));
            mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
            mImageView.setPadding(16, 16, 16, 16);
        } else {
            mImageView = (ImageView) convertView;
        }
        mImageView.setImageResource(images[position]);
        return mImageView;
    }

我的ViewActivity文件,用户在将其设置为壁纸之前将预览图像:

private Integer asset1 = R.raw.asset1;
private Integer asset2 = R.raw.asset2;
private Integer asset3 = R.raw.asset1;
private Integer asset4 = R.raw.asset2;
private Integer asset5 = R.raw.asset1;
private Integer asset6 = R.raw.asset2;
private Integer[] images = {
        asset1, asset2, asset3,
        asset4, asset5, asset6
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_view);

    Bundle extras = getIntent().getExtras();
    int imageRes = extras.getInt("IMAGE_RES");

    ImageView preview = findViewById(R.id.preview);
    preview.setImageResource(imageRes);
    preview.setScaleType(ImageView.ScaleType.CENTER_CROP);

    Button set = findViewById(R.id.setButton);
    set.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        }
    });
}

我不确定自己是否走在正确的轨道上,但如果有人能指出我的方向会很棒,那就太棒了!

1 个答案:

答案 0 :(得分:0)

在Android应用程序中处理位图和图像时,有很多关于内存不足错误的内容:hereherehere

出于在设备上设置壁纸的特殊目的,您可以尝试这种方法。我并不保证你总是会以这种方式避免OOM错误,但它应该阻止大部分错误。

当它将资源解码为位图时,试图保持在应用程序的当前空闲内存中。它还在最后回收位图。

一个优点是您不必提出输出位图所需的宽度和高度。它基于自由记忆为你做到了这一点。 (这也是一个缺点 - 你不能自由选择你想要的任何位图尺寸。它们可能太大而导致崩溃。)

进行解码可能需要一些时间,这就是它在后台线程上完成的原因。

无论如何,这对我有用:

将ExecutorService和方法decodeBitmapWithinFreeMemory添加到ViewActivity:

private ExecutorService executor = Executors.newSingleThreadExecutor();

...

// adapted from https://developer.android.com/topic/performance/graphics/load-bitmap.html
private Bitmap decodeResourceWithinFreeMemory(Resources resources, int resourceId, float requiredAspectRatio) {

    // get just the size of the resource image
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(resources, resourceId, options);

    // estimate number of pixels we can work with in current free memory   
    long freeMem = Runtime.getRuntime().freeMemory();
    long spaceForARGV8888Px = freeMem / 4; // est. number of ARGV_8888 pixels that can be stored

    // calculate the sides of a rectangle with approximately that number of pixels
    long squareRootLowerBound = (long) Math.floor(Math.pow(spaceForARGV8888Px, 0.5));
    int requestedWidth = (int) Math.floor(squareRootLowerBound * requiredAspectRatio);
    int requestedHeight = (int) Math.floor(squareRootLowerBound / requiredAspectRatio);

    // find the right sample size by aggressively increasing sampleSize var: require only that
    // _one_ of the output dimensions be greater than the corresponding requested dimension
    int sampleSize = 1;
    while ((options.outHeight / (2 * sampleSize) ) >= requestedHeight
            || (options.outWidth / (2 * sampleSize) ) >= requestedWidth) {
        sampleSize *= 2;
    }

    // output the bitmap by sampling the input resource at the calculated sampleSize
    options.inSampleSize = sampleSize;
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(resources, resourceId, options);
}

在按钮的onClick方法中调用decodeBitmapWithinFreeMemory,为其提供设备的屏幕宽高比:

DisplayMetrics metrics = getResources().getDisplayMetrics();
final float screenAspectRatio = (float)metrics.widthPixels/(float)metrics.heightPixels;
executor.submit(new Runnable() {
    @Override
    public void run() {
        try {
            Bitmap drawableAsBitmap = decodeResourceWithinFreeMemory(getResources(),
                    R.raw.asset1, screenAspectRatio);
            WallpaperManager.getInstance(MainActivity.this).setBitmap(drawableAsBitmap);
            drawableAsBitmap.recycle();
        } catch (IOException ioe) {
            Log.e(TAG, "Could not set wallpaper to bitmap", ioe);
        }
    }
});

另请注意,您可以选择将BroadcastReceiver添加到您的活动中,以通知已设置壁纸。 (参见setBitmap.

的文档