将原始资产设置为选定可绘制的壁纸
问题描述:
我有一个gridview,其中包含我的可绘制文件夹中的图像数组。我现在已经制定了将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) {
}
});
}
我不知道是否不我走在正确的轨道上,但是如果任何人都能指引我走向正确的方向,那就太棒了!
答
例如,在Android应用中使用位图和图像时,已经在SO上编写了很多关于Out of Memory错误的文章:here,here和here。
为了在设备上设置墙纸的特殊目的,您可以尝试这种方法。我不能保证你会一直避免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);
}
调用decodeBitmapWithinFreeMemory按钮的onClick方法中,喂养它的设备的屏幕纵横比例:
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.的文档)