使用图像的 Uri 传递图像仍然会导致内存不足异常
Passing around images with images' Uri still causes Out of Memory Exception
目标
为了 activities/fragments.
传递图像(它占据了屏幕的四分之一,所以它很大)
我尝试做的事情
有人研究/建议我传递图像 Uri,而不是传递 BitMap。问题是,每当我单击将启动 HomeDescActivity
的 "Preview Button" 时,都会出现 Out of Memory Exception
。
GalleryFragment
public class GalleryFragment extends Fragment {
private static final int SELECT_PICTURE = 1;
public static final String IMAGE_URI_ARRAY_LIST = "IMAGE_URI_ARRAY_LIST";
private ArrayList<String> mImageUriArrayList = new ArrayList<>();
RecyclerView recyclerView;
GalleryAdapter galleryAdapter;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.profile_tab_become_a_host_set_the_scene_gallery_fragment, container, false);
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//convert string uri to uri object
Uri imageUri = Uri.parse(getArguments().getString(PhotoFragment.IMAGE_URI));
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
galleryAdapter = new GalleryAdapter();
galleryAdapter.addImage(imageUri);
mImageUriArrayList.add(imageUri.toString());
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2);
recyclerView.setLayoutManager(gridLayoutManager);
view.findViewById(R.id.ivAddPhoto).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
//Launch Gallery
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
}
});
view.findViewById(R.id.bPreview).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getContext(), HomeDescActivity.class);
intent.putStringArrayListExtra(IMAGE_URI_ARRAY_LIST, mImageUriArrayList);
startActivity(intent);
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
//get selected image from gallery
Uri imageUri = data.getData();
galleryAdapter.addImage(imageUri);
mImageUriArrayList.add(imageUri.toString());
//refresh adapter
recyclerView.setAdapter(galleryAdapter);
}
}
}
}
HomeDescActivity(启动时会出现内存不足异常)
public class HomeDescActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.explore_tab_home_desc_activity);
HomeDescFragment homeDescFragment = new HomeDescFragment();
// Get images (uri) from GalleryFragment + PhotoFragment
if(getIntent().getExtras().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST) != null){
Bundle bundle = new Bundle();
bundle.putStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST,
getIntent().getExtras().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST));
homeDescFragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction().replace(R.id.rootLayout, homeDescFragment).commit();
}
}
}
HomeDescFragment
public class HomeDescFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.explore_tab_home_desc_fragment, container, false);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//convert strng uri to uri object
if(getArguments().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST) != null){
ArrayList<String> uriArrayList = getArguments().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST);
ImageView ivHomePhoto = (ImageView) view.findViewById(R.id.ivHomePhoto);
for(String uriString : uriArrayList){
ivHomePhoto.setImageURI(Uri.parse(uriString));
}
}
}
}
更新
堆栈跟踪
android.teamtreehouse.com.airbnb E/AndroidRuntime: FATAL EXCEPTION: main
Process: googleplayservices.samples.android.teamtreehouse.com.airbnb, PID: 12434
java.lang.OutOfMemoryError: Failed to allocate a 207360012 byte allocation with 13482248 free bytes and 76MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:988)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:2474)
at android.content.res.Resources.loadDrawable(Resources.java:2381)
at android.content.res.TypedArray.getDrawable(TypedArray.java:749)
at android.widget.ImageView.(ImageView.java:146)
at android.widget.ImageView.(ImageView.java:135)
at android.support.v7.widget.AppCompatImageView.(AppCompatImageView.java:57)
at android.support.v7.widget.AppCompatImageView.(AppCompatImageView.java:53)
at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:106)
at android.support.v7.app.AppCompatDelegateImplV9.createView(AppCompatDelegateImplV9.java:1013)
at android.support.v7.app.AppCompatDelegateImplV9.onCreateView(AppCompatDelegateImplV9.java:1072)
at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:47)
at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:180)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:725)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
at googleplayservices.samples.android.teamtreehouse.com.airbnb.ExploreTab.HomeDescFragment$override.onCreateView(HomeDescFragment.java:29)
at googleplayservices.samples.android.teamtreehouse.com.airbnb.ExploreTab.HomeDescFragment$override.access$dispatch(HomeDescFragment.java)
at googleplayservices.samples.android.teamtreehouse.com.airbnb.ExploreTab.HomeDescFragment.onCreateView(HomeDescFragment.java:0)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2189)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1299)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:757)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2355)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2146)
at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2098)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2008)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:607)
at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1236)
at android.app.Activity.performStart(Activity.java:6006)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access0(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
向我们显示堆栈跟踪。
给我们提供有关导致异常的图像的详细信息,它的宽度和高度是多少,需要多少内存?
我猜你正在尝试加载像 6000x6000 这样愚蠢的高分辨率图像,这是导致异常的原因,但没有更多信息,我不能说更多。
您应该使用像 "Glide" 这样的库来为您加载图像,因为如果图像太大,它会在向用户显示时缩小图像。它在使用最少的内存处理图像方面也非常高效。
目标
为了 activities/fragments.
传递图像(它占据了屏幕的四分之一,所以它很大)我尝试做的事情
有人研究/建议我传递图像 Uri,而不是传递 BitMap。问题是,每当我单击将启动 HomeDescActivity
的 "Preview Button" 时,都会出现 Out of Memory Exception
。
GalleryFragment
public class GalleryFragment extends Fragment {
private static final int SELECT_PICTURE = 1;
public static final String IMAGE_URI_ARRAY_LIST = "IMAGE_URI_ARRAY_LIST";
private ArrayList<String> mImageUriArrayList = new ArrayList<>();
RecyclerView recyclerView;
GalleryAdapter galleryAdapter;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.profile_tab_become_a_host_set_the_scene_gallery_fragment, container, false);
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//convert string uri to uri object
Uri imageUri = Uri.parse(getArguments().getString(PhotoFragment.IMAGE_URI));
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
galleryAdapter = new GalleryAdapter();
galleryAdapter.addImage(imageUri);
mImageUriArrayList.add(imageUri.toString());
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2);
recyclerView.setLayoutManager(gridLayoutManager);
view.findViewById(R.id.ivAddPhoto).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
//Launch Gallery
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
}
});
view.findViewById(R.id.bPreview).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getContext(), HomeDescActivity.class);
intent.putStringArrayListExtra(IMAGE_URI_ARRAY_LIST, mImageUriArrayList);
startActivity(intent);
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
//get selected image from gallery
Uri imageUri = data.getData();
galleryAdapter.addImage(imageUri);
mImageUriArrayList.add(imageUri.toString());
//refresh adapter
recyclerView.setAdapter(galleryAdapter);
}
}
}
}
HomeDescActivity(启动时会出现内存不足异常)
public class HomeDescActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.explore_tab_home_desc_activity);
HomeDescFragment homeDescFragment = new HomeDescFragment();
// Get images (uri) from GalleryFragment + PhotoFragment
if(getIntent().getExtras().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST) != null){
Bundle bundle = new Bundle();
bundle.putStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST,
getIntent().getExtras().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST));
homeDescFragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction().replace(R.id.rootLayout, homeDescFragment).commit();
}
}
}
HomeDescFragment
public class HomeDescFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.explore_tab_home_desc_fragment, container, false);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//convert strng uri to uri object
if(getArguments().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST) != null){
ArrayList<String> uriArrayList = getArguments().getStringArrayList(GalleryFragment.IMAGE_URI_ARRAY_LIST);
ImageView ivHomePhoto = (ImageView) view.findViewById(R.id.ivHomePhoto);
for(String uriString : uriArrayList){
ivHomePhoto.setImageURI(Uri.parse(uriString));
}
}
}
}
更新
堆栈跟踪
android.teamtreehouse.com.airbnb E/AndroidRuntime: FATAL EXCEPTION: main Process: googleplayservices.samples.android.teamtreehouse.com.airbnb, PID: 12434 java.lang.OutOfMemoryError: Failed to allocate a 207360012 byte allocation with 13482248 free bytes and 76MB until OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method) at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609) at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444) at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:988) at android.content.res.Resources.loadDrawableForCookie(Resources.java:2474) at android.content.res.Resources.loadDrawable(Resources.java:2381) at android.content.res.TypedArray.getDrawable(TypedArray.java:749) at android.widget.ImageView.(ImageView.java:146) at android.widget.ImageView.(ImageView.java:135) at android.support.v7.widget.AppCompatImageView.(AppCompatImageView.java:57) at android.support.v7.widget.AppCompatImageView.(AppCompatImageView.java:53) at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:106) at android.support.v7.app.AppCompatDelegateImplV9.createView(AppCompatDelegateImplV9.java:1013) at android.support.v7.app.AppCompatDelegateImplV9.onCreateView(AppCompatDelegateImplV9.java:1072) at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:47) at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:180) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:725) at android.view.LayoutInflater.rInflate(LayoutInflater.java:806) at android.view.LayoutInflater.rInflate(LayoutInflater.java:809) at android.view.LayoutInflater.rInflate(LayoutInflater.java:809) at android.view.LayoutInflater.rInflate(LayoutInflater.java:809) at android.view.LayoutInflater.rInflate(LayoutInflater.java:809) at android.view.LayoutInflater.inflate(LayoutInflater.java:504) at android.view.LayoutInflater.inflate(LayoutInflater.java:414) at googleplayservices.samples.android.teamtreehouse.com.airbnb.ExploreTab.HomeDescFragment$override.onCreateView(HomeDescFragment.java:29) at googleplayservices.samples.android.teamtreehouse.com.airbnb.ExploreTab.HomeDescFragment$override.access$dispatch(HomeDescFragment.java) at googleplayservices.samples.android.teamtreehouse.com.airbnb.ExploreTab.HomeDescFragment.onCreateView(HomeDescFragment.java:0) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2189) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1299) at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595) at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:757) at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2355) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2146) at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2098) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2008) at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388) at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:607) at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178) at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1236) at android.app.Activity.performStart(Activity.java:6006) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) at android.app.ActivityThread.access0(ActivityThread.java:151) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) at android.os.Handler.dispatchMessage(Handler.java:102)
向我们显示堆栈跟踪。
给我们提供有关导致异常的图像的详细信息,它的宽度和高度是多少,需要多少内存?
我猜你正在尝试加载像 6000x6000 这样愚蠢的高分辨率图像,这是导致异常的原因,但没有更多信息,我不能说更多。
您应该使用像 "Glide" 这样的库来为您加载图像,因为如果图像太大,它会在向用户显示时缩小图像。它在使用最少的内存处理图像方面也非常高效。