在我的小部件中,我有一个 imageView,它从用户图库中收集图像,然后将该图像设置为另一个活动的背景。它工作正常,但是当我尝试添加太大的图像文件(例如来自相机的图像)或上传许多图像文件时,我收到“内存不足”错误。看了一会stackoverflow,发现大家都用的基本方法:
public static Bitmap decodeSampleImage(File f, int width, int height) {
try {
System.gc(); // First of all free some memory
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// The new size we want to scale to
final int requiredWidth = width;
final int requiredHeight = height;
// Find the scale value (as a power of 2)
int sampleScaleSize = 1;
while (o.outWidth / sampleScaleSize / 2 >= requiredWidth && o.outHeight / sampleScaleSize / 2 >= requiredHeight)
sampleScaleSize *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = sampleScaleSize;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (Exception e) {
Log.d(TAG, e.getMessage()); // We don't want the application to just throw an exception
}
return null;
}
我还注意到人们也回收了未使用的位图。我理解这是如何工作的,但我不知道我应该把它放在我的编码中的什么地方。
这是我的两个类(Personalize.java,其中收集背景的 imageView 是。它具有 imageView 和两个按钮(一个用于从图库中选择图像,然后将图像显示到 imageView 中,另一个用于设置图像作为背景)。
首先是 Personalize.java:
package com.example.awesomefilebuilderwidget;
IMPORTS
public class Personalize extends Activity implements View.OnClickListener {
Button button;
ImageView image; //the imageview for setting the background
ImageView image2; //the imageview for setting the icon (not focusing on)
Button btnChangeImage;
Button btnChangeImageForIcon;
Button btnSetBackground;
private static final int SELECT_PICTURE = 1;
private static final int SELECT_PICTURE_2 = 2;
private String selectedImagePath;
Bitmap background;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.personalize);
image = (ImageView) findViewById(R.id.imageView1);
image2 = (ImageView) findViewById(R.id.imageView2Icon);
Button btnChangeImage = (Button) findViewById(R.id.btnChangeImage);
btnChangeImage.setOnClickListener(this);
Button btnChangeImageForIcon = (Button) findViewById(R.id.btnChangeImageForIcon);
btnChangeImageForIcon.setOnClickListener(this);
Button btnSetBackground = (Button) findViewById(R.id.btnSetBackground);
btnSetBackground.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnChangeImage:
launchImageChooser();
break;
case R.id.btnChangeImageForIcon:
launchImageChooser();
break;
case R.id.btnSetBackground:
setBackgroundImageInDragAndDrop();
break;
}
}
private void setBackgroundImageInDragAndDrop() {
Log.d("Personalize", "setBackgroundImageInDragAndDrop() called");
Intent i = getIntent();
//Convert bitmap to byte array to send back to activity
// See: http://stackoverflow.com/questions/11010386/send-bitmap-using-intent-android
ByteArrayOutputStream stream = new ByteArrayOutputStream();
background.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[]byteArray = stream.toByteArray();
i.putExtra("myBackgroundBitmap", byteArray);
setResult(RESULT_OK, i);
finish();
}
private void launchImageChooser() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, SELECT_PICTURE);
}
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String imagePath = cursor.getString(column_index);
if(cursor != null) {
cursor.close();
}
return imagePath;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE)
{
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
background = getAndDecodeImage(selectedImagePath);
if(background != null){
image.setImageBitmap(background);
}
} else if (requestCode == SELECT_PICTURE_2)
{
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
Bitmap b2 = getAndDecodeImage(selectedImagePath);
if(b2 != null){
image2.setImageBitmap(b2);
}
}
}
}
private Bitmap getAndDecodeImage(String selectedImagePath){
try {
Log.d("Personalize", "selectedImagePath: " + selectedImagePath);
FileInputStream fileis=new FileInputStream(selectedImagePath);
BufferedInputStream bufferedstream=new BufferedInputStream(fileis);
byte[] bMapArray= new byte[bufferedstream.available()];
bufferedstream.read(bMapArray);
Bitmap bMap = BitmapFactory.decodeByteArray(bMapArray, 0, bMapArray.length);
if (fileis != null)
{
fileis.close();
}
if (bufferedstream != null)
{
bufferedstream.close();
}
return bMap;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public boolean saveImageToInternalStorage(Bitmap image) {
try {
FileOutputStream fos = this.openFileOutput("desiredFilename.png", Context.MODE_PRIVATE);
image.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
return true;
} catch (Exception e) {
return false;
}
}
}
然后这是我的 Drag_and_Drop_App.java (重要部分的片段——收集位图并设置为背景):
package com.example.awesomefilebuilderwidget;
IMPORTS
public class Drag_and_Drop_App extends Activity {
private static final int SET_BACKGROUND = 10;
private ListView mListAppInfo;
// Search EditText
EditText inputSearch;
public AppInfoAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set layout for the main screen
setContentView(R.layout.drag_and_drop_app);
// import buttons
Button btnLinkToFeedback = (Button) findViewById(R.id.btnLinkToFeedback);
Button btnLinkToPersonalize = (Button) findViewById(R.id.btnLinkToPersonalize);
// Link to Personalize Screen
btnLinkToPersonalize.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent i = new Intent(getApplicationContext(),
Personalize.class);
startActivityForResult(i, SET_BACKGROUND);
}
});
}
public Bitmap getThumbnail(String filename) {
Bitmap thumbnail = null;
try {
File filePath = this.getFileStreamPath(filename);
FileInputStream fi = new FileInputStream(filePath);
thumbnail = BitmapFactory.decodeStream(fi);
} catch (Exception ex) {
Log.e("getThumbnail() on internal storage", ex.getMessage());
}
return thumbnail;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.i("Drag_and_Drop_App", "requestCode: " + requestCode + ", resultCode: " + resultCode);
if(requestCode == SET_BACKGROUND && resultCode == RESULT_OK){
byte[] byteArray = data.getByteArrayExtra("myBackgroundBitmap");
Bitmap myBackground = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
setBackgroundImage(myBackground);
}
}
@SuppressLint("NewApi")
private void setBackgroundImage(Bitmap bitmap) {
RelativeLayout yourBackgroundView = (RelativeLayout) findViewById(R.id.rl_drag_and_drop_app);
Drawable d = new BitmapDrawable(getResources(), bitmap);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
yourBackgroundView.setBackgroundDrawable(d);
} else {
yourBackgroundView.setBackground(d);
}
}
}
那么我在哪里可以实现该编码,我还可以在哪里摆脱内存中其他未使用的位图?(回收它们?)