问题
I am using an image to set as the background for all my activities but it was causing a memory overflow issue and crash the app. Now I am unbinding my drawables on pause() and on Destroy() in my activity and now it shows blank screen on pressing back button. So how can I avoid this without using extra memory.
protected void onPause(){
super.onPause();
unbindDrawables(findViewById(R.id.login_root));
}
protected void onDestroy() {
unbindDrawables(findViewById(R.id.login_root));
super.onDestroy();
}
private void unbindDrawables(View view) {
System.gc();
Runtime.getRuntime().gc();
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
Initially I was inflating my layout using android:background="@drawable/" which always caused memory overflow error saying that VM won't let us allocate 10MB (app.) Now I am getting a bitmap from that drawable without scaling down and binding it on runtime.Now it says VM won't let us allocate 5MB (app.) without using unbindDrawables(..) Obviously the quality of background image which is shown has decreased but I am not able to understand that if I am using a png file of 13KB, how does JVM requires 5 or 10MB space to process the request ?
I have shift my layout statements from onCreate() to onResume() method but the application again runs out of memory on pressing back button.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
protected void onResume(){
setContentView(R.layout.home);
Bitmap bmp;
ImageView background = (ImageView)findViewById(R.id.iv_home_background);
InputStream is = getResources().openRawResource(R.drawable.background);
bmp = BitmapFactory.decodeStream(is);
background.setImageBitmap(bmp);
super.onResume();
}
protected void onPause(){
super.onPause();
unbindDrawables(findViewById(R.id.home_root));
}
private void unbindDrawables(View view) {
System.gc();
Runtime.getRuntime().gc();
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
回答1:
I have found a work around for this problem. Now I am scaling my bitmaps at runtime to a very small size and then storing them in internal storage. The program calls the scaled bitmaps from the storage at runtime and if its not present there, it calls it from drawable folder, scale it, write it to storage and then bind it to the view. In this way there is no need to call unbindDrawables method at any point of time and the application remains responsive throughout. My only concern right now is the quality of bitmaps, I think I need to play around with the scaling size to find out the least possible size with maximum quality.
回答2:
You are calling GC for each sub view. Try calling it only once when all the unbinds are done.
unbindDrawables(findViewById(R.id.login_root));
System.gc();
GC is a heavy load and it is useless to call it too often. in fact, if there are no leaks it should be nesesary at all.
Also have in mind that png file sizes have nothing to do with a bitmap on memory. Here is more info on that http://developer.android.com/training/displaying-bitmaps/index.html
来源:https://stackoverflow.com/questions/12395068/unbinding-drawables-onpause-causing-unresponsive-back-navigation-and-skipping