基本上,用户点击一个按钮就可以从图库中抓取图像。然后该图像被发送到另一个要显示的活动。这是我抓住图像的第一个活动。
private void grabImage()
{
Intent imageGetter = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(imageGetter, RESULT_LOAD_IMAGE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data)
{
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};//Array size of 1, and we put in a string
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
user_image_path = cursor.getString(columnIndex);//here we have our image path.
cursor.close();
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(BitmapFactory.decodeFile(user_image_path));
}
Intent theIntent = new Intent(this,CardModel.class);
theIntent.putExtra("imagePath", user_image_path);
}
现在这是我尝试显示该图像的第二个活动。
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.card_model_layout);
String grabImagePath = getIntent().getStringExtra("imagePath");
ImageView img = (ImageView) findViewById(R.id.userImage);
img.setImageBitmap(BitmapFactory.decodeFile(grabImagePath));
}
我一直收到OutOfMemoryError错误,我不想添加: android:largeHeap =“true”来解决问题。
有人可以给我一个干净的示例(包含所有代码),说明如何在两个活动之间正确传递图像(使用其字符串路径)。我相信很多开发人员都可以从中受益。谢谢!
还有一种方法可以在不调用onActivityResult的情况下执行此操作,而只需使用自己的方法并将代码放在那里并在onCreate()方法中调用它。
答案 0 :(得分:1)
事实是 -
鉴于你正在使用有限的内存,理想情况下你只想要 在内存中加载较低分辨率的版本。分辨率较低 version应与显示它的UI组件的大小相匹配。一个 具有更高分辨率的图像不会提供任何明显的好处, 但仍占用宝贵的记忆并带来额外的表现 由于额外的飞行缩放而产生的开销。
[参考链接:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html]
这就是为什么你需要缩小图像的原因。希望,以下代码可以帮到你!
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class BitmapUtility {
public static Bitmap decodeSampledBitmapFromResource(String path,int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path,options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
private 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 inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
}
您可以使用以上代码,如下所示: 而不是使用:
imageView.setImageBitmap(BitmapFactory.decodeFile(user_image_path));
你可以使用:
imageView.setImageBitmap(BitmapUtilty.decodeSampledBitmapFromResource("path/to/image",300,400)
答案 1 :(得分:0)
使用图片(特别是来自您无法控制的来源,如互联网或用户数据),您无法加载它们。这可能是巨大的。以前的答案显示了如何正确地做到这一点。
要注意的另一件事是回收图像数据占用的本机内存。由于某些原因,当OOM已经在这里时,它不会自动回收或者为时已晚。要做到这一点,应该保持引用计数,这需要一些扩展几个类的工作。这就是我解决问题的方法。我想我使用了android教程中的一些代码并对其进行了扩展。无论如何,这是几年前所以我不确定)这就是。
package com.companyname.myapp.ui.cache;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
import com.companyname.myapp.MyApp;
import com.companyname.myapp.BuildConfig;
/**
* A BitmapDrawable that keeps track of whether it is being displayed or cached.
* When the drawable is no longer being displayed or cached,
* {@link Bitmap#recycle() recycle()} will be called on this drawable's bitmap.
*/
public class RecyclingBitmapDrawable extends BitmapDrawable {
private int cacheRefCount = 0;
private int displayRefCount = 0;
private boolean hasBeenDisplayed;
public RecyclingBitmapDrawable(Resources res, Bitmap bitmap) {
super(res, bitmap);
}
/**
* Notify the drawable that the displayed state has changed. Internally a
* count is kept so that the drawable knows when it is no longer being
* displayed.
*
* @param isDisplayed
* - Whether the drawable is being displayed or not
*/
public void setIsDisplayed(boolean isDisplayed) {
synchronized (this) {
if (isDisplayed) {
displayRefCount++;
hasBeenDisplayed = true;
} else {
displayRefCount--;
}
}
// Check to see if recycle() can be called
checkState();
}
/**
* Notify the drawable that the cache state has changed. Internally a count
* is kept so that the drawable knows when it is no longer being cached.
*
* @param isCached
* - Whether the drawable is being cached or not
*/
public void setIsCached(boolean isCached) {
synchronized (this) {
if (isCached) {
cacheRefCount++;
} else {
cacheRefCount--;
}
}
// Check to see if recycle() can be called
checkState();
}
private synchronized void checkState() {
// If the drawable cache and display ref counts = 0, and this drawable
// has been displayed, then recycle
if (cacheRefCount <= 0 && displayRefCount <= 0 && hasBeenDisplayed && hasValidBitmap()) {
if (BuildConfig.DEBUG)
Log.d(MyApp.TAG, "No longer being used or cached so recycling. " + toString());
getBitmap().recycle();
}
}
private synchronized boolean hasValidBitmap() {
Bitmap bitmap = getBitmap();
return bitmap != null && !bitmap.isRecycled();
}
}
这是另一个课程。
package com.mycompanyname.myapp.ui.cache;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Sub-class of ImageView which automatically notifies the drawable when it is
* being displayed.
*/
public class RecyclingImageView extends ImageView {
public RecyclingImageView(Context context) {
super(context);
}
public RecyclingImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* @see android.widget.ImageView#onDetachedFromWindow()
*/
@Override
protected void onDetachedFromWindow() {
// This has been detached from Window, so clear the drawable
setImageDrawable(null);
super.onDetachedFromWindow();
}
/**
* @see android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)
*/
@Override
public void setImageDrawable(Drawable drawable) {
// Keep hold of previous Drawable
final Drawable previousDrawable = getDrawable();
// Call super to set new Drawable
super.setImageDrawable(drawable);
// Notify new Drawable that it is being displayed
notifyDrawable(drawable, true);
// Notify old Drawable so it is no longer being displayed
notifyDrawable(previousDrawable, false);
}
@Override
public void setImageResource(int resId) {
// Keep hold of previous Drawable
final Drawable previousDrawable = getDrawable();
super.setImageResource(resId);
// Notify new Drawable that it is being displayed
final Drawable newDrawable = getDrawable();
notifyDrawable(newDrawable, true);
// Notify old Drawable so it is no longer being displayed
notifyDrawable(previousDrawable, false);
}
/**
* Notifies the drawable that it's displayed state has changed.
*
* @param drawable
* @param isDisplayed
*/
private static void notifyDrawable(Drawable drawable, final boolean isDisplayed) {
if (drawable != null) {
if (drawable instanceof RecyclingBitmapDrawable) {
// The drawable is a CountingBitmapDrawable, so notify it
((RecyclingBitmapDrawable) drawable).setIsDisplayed(isDisplayed);
} else if (drawable instanceof LayerDrawable) {
// The drawable is a LayerDrawable, so recurse on each layer
LayerDrawable layerDrawable = (LayerDrawable) drawable;
for (int i = 0, z = layerDrawable.getNumberOfLayers(); i < z; i++) {
notifyDrawable(layerDrawable.getDrawable(i), isDisplayed);
}
}
}
}
}
现在在您的资源文件中(活动或其他)。让我们说这是用户个人资料头像。我有时看到它可能是几MB或更多)
<com.mycompanyname.myapp.ui.cache.RecyclingImageView
android:id="@+id/profile_icon"
android:layout_width="120dp"
android:layout_height="120dp"
android:adjustViewBounds="true"
android:contentDescription="@string/dummy_desc"
android:scaleType="centerCrop"
android:src="@drawable/icon_avatar_placeholder" />
如果您需要在应用中加载大量图片(比方说,它是用户个人资料列表及其头像),那么您还需要某种图像缓存。不确定你现在需要它。如果你确实需要它,只需在stackoverflow上ping我,我会添加更多。
希望这有帮助。