显示图像的片段中的内存问题

时间:2012-02-13 09:15:08

标签: android bitmap android-fragments drawable out-of-memory

我正在使用片段来显示图像/页面。我有一个Activity(Main),其中包含所有片段。

package com.example.hscroll.demo;

import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.ListFragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import com.crittercism.app.Crittercism;
import com.example.hscroll.customer.BitmapWeakReference;
import com.example.hscroll.customer.PromotionalPriceListAdditionsDataAdaptor;
import com.example.hscroll.customer.PromotionalPriceListDataAdaptor;
import com.example.hscroll.library.imagezoom.ImageViewTouch;

public class MainAct extends FragmentActivity{

private ImageViewTouch  mImageView;
MyPagerAdapter mPagerAdapter;
ViewPager viewPager;
 static final int NUM_ITEMS = 58;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState); 
    Crittercism.init(getApplicationContext(), "4f391d0fb09315319d00048d");
    PreferenceManager.setDefaultValues(this, R.xml.preference, false);

    setContentView(R.layout.viewpager_layout);

    mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager());

    viewPager = (ViewPager)findViewById(R.id.viewpager);
    viewPager.setAdapter(mPagerAdapter);
}


public static class MyPagerAdapter extends FragmentStatePagerAdapter {
    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {
            return newInstance(position);
    }


}

static Fragment newInstance(int position) {

    Fragment data = null;
    switch(position){

    case 0 :
        data = new Fragment1();
    break;

    case 1 :
        data = new FragmentSignupForm();
    break;

    case 2 :
        data = new Fragment2();
    break;

    case 3 :
        data = new Fragment3();
    break;

    case 4 :
        data = new Fragment4();
    break;

    case 5:
        data = new Fragment5();
    break;

    case 6 :
        data = new Fragment6();
    break;

    case 7 :
        data = new Fragment7();
    break;

    case 8 :
        data = new Fragment8();
    break;

    case 9 :
        data = new Fragment9();
    break;

    case 10 :
        data = new MyMapFragment();
    break;

    case 11:
        data = new FragmentQuestionaire();
        break;

    case 12:
        data = new Fragment10();
        break;

    case 13:
        data = new Fragment11();
        break;

    case 14:
        data = new Fragment12();
        break;

    case 15:
        data = new Fragment13();
        break;

    case 16:
        data = new Fragment14();
        break;

    case 17:
        data = new Fragment15();
        break;

    case 18:
        data = new Fragment16();
        break;

    case 19:
        data = new Fragment17();
        break;

    case 20:
        data = new Fragment18();
        break;

    case 21:
        data = new Fragment19();
        break;

    case 22:
        data = new Fragment20();
        break;

    case 23:
        data = new Fragment21();
        break;

    case 24:
        data = new Fragment22();
        break;

    case 25:
        data = new Fragment23();
        break;

    case 26:
        data = new Fragment24();
        break;

    case 27:
        data = new Fragment25();
        break;

    case 28:
        data = new Fragment26();
        break;

    case 29:
        data = new Fragment27();
        break;

    case 30:
        data = new Fragment28();
        break;

    case 31:
        data = new Fragment29();
        break;

    case 32:
        data = new Fragment30();
        break;

    case 33:
        data = new Fragment31();
        break;

    case 34:
        data = new Fragment32();
        break;

    case 35:
        data = new Fragment33();
        break;

    case 36:
        data = new Fragment34();
        break;

    case 37:
        data = new Fragment35();
        break;

    case 38:
        data = new Fragment36();
        break;

    case 39:
        data = new Fragment37();
        break;

    case 40:
        data = new Fragment38();
        break;

    case 41:
        data = new Fragment39();
        break;

    case 42:
        data = new Fragment40();
        break;

    case 43:
        data = new Fragment41();
        break;

    case 44:
        data = new Fragment42();
        break;

    case 45:
        data = new Fragment43();
        break;

    case 46:
        data = new Fragment44();
        break;

    case 47:
        data = new Fragment45();
        break;

    case 48:
        data = new Fragment46();
        break;

    case 49:
        data = new Fragment47();
        break;

    case 50:
        data = new Fragment48();
        break;

    case 51:
        data = new Fragment49();
        break;

    case 52:
        data = new Fragment50();
        break;

    case 53:
        data = new Fragment51();
        break;

    case 54:
        data = new Fragment52();
        break;

    case 55:
        data = new Fragment53();
        break;

    case 56:
        data = new Fragment54();
        break;

    case 57:
        data = new Fragment55();
        break;

    default :
        data = new FragmentQuestionaire();
    break;  

    }

        return data;
}

@Override
protected void onDestroy() {
    super.onDestroy();
    FragmentSignupForm.CUSTOMER_ADDRESS = "";
    FragmentSignupForm.CUSTOMER_ADDRESS1 = "";
    FragmentSignupForm.CUSTOMER_ADDRESS2 = "";
    FragmentSignupForm.CUSTOMER_EMAIL = "";
    FragmentSignupForm.CUSTOMER_ID = "";
    FragmentSignupForm.CUSTOMER_POSTCODE = "";
    FragmentSignupForm.CUSTOMER_NAME = "";
    FragmentSignupForm.Telephone = "";
    Fragment50.Total = "0";
    Fragment47.amount2 = 0;
    Fragment47.systemSize = "";
    PromotionalPriceListAdditionsDataAdaptor.TotalAdditionalPrice = 0;
    PromotionalPriceListDataAdaptor.TotalPrice = 0;
    PromotionalPriceListDataAdaptor.Capacity = "";
    PromotionalPriceListDataAdaptor.NumberOfPanels = "";
    PromotionalPriceListDataAdaptor.PanelSize = "";
    PromotionalPriceListDataAdaptor.PanelCapacity = "";
    PromotionalPriceListDataAdaptor.SurfaceAreaReuired = "";
    PromotionalPriceListDataAdaptor.Price = "";
    PromotionalPriceListDataAdaptor.PromotionalOffer = "";
    PromotionalPriceListDataAdaptor.TotalOfferPrice = "";
   }

   }

这是片段类中的代码 -

package com.example.hscroll.demo;

import java.io.BufferedInputStream;
import java.io.FileInputStream;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import com.example.hscroll.customer.BitmapWeakReference;
 import com.example.hscroll.library.imagezoom.ImageViewTouch;

public class Fragment2 extends Fragment{

ImageViewTouch imgview ;
LayoutInflater inflater;
FileInputStream in;
BufferedInputStream buf;
BitmapWeakReference bitmap;
ViewGroup con;

private final String  PATH = "/mnt/sdcard/Ideal Solar/Layout_1.png";

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance)
{
    this.inflater = inflater;
    if(container == null)return null;
    container = (LinearLayout)inflater.inflate(R.layout.fragment0_layout, container, false);
    con = container;
    imgview= (ImageViewTouch)container.findViewById(R.id.imageView1);
    bitmap = new BitmapWeakReference(imgview.selectImage(inflater.getContext(), PATH));
    if(bitmap!=null)
        imgview.setImageBitmapReset( bitmap.get(), true );

    return container;
}   

/* @Override
    public void onResume() {

        if(bitmap == null)
        {
            bitmap = SelectImageFunctions.selectImage(inflater.getContext(), PATH);
        }
        super.onResume();
    }*/

 @Override
public void onDestroyView() {
     super.onDestroyView();
        imgview.setImageBitmap(null);
        bitmap.clear();
        bitmap = null;
        Fragment1.unbindDrawables(con.findViewById(R.id.ll));
        System.gc();
    }

   }

每次当我移动到下一个片段时,前一个片段的onDestroyView()被调用,我将删除位图和图像视图的所有引用,但仍然没有释放位图或绘图的内存并且内存不断增加。最后它会在50MB左右坠毁。

任何人都可以帮助吗?我正在为galaxy tab开发这个应用程序。

更新 - 动态页面代码 -

 package com.example.hscroll.demo;


   import java.io.BufferedReader;
   import java.io.IOException;
   import java.io.InputStream;
   import java.io.InputStreamReader;
   import java.util.ArrayList;

   import org.apache.http.HttpEntity;
   import org.apache.http.HttpResponse;
   import org.apache.http.NameValuePair;
   import org.apache.http.client.HttpClient;
   import org.apache.http.client.entity.UrlEncodedFormEntity;
   import org.apache.http.client.methods.HttpPost;
   import org.apache.http.impl.client.DefaultHttpClient;
   import org.apache.http.message.BasicNameValuePair;
   import org.json.JSONArray;
   import org.json.JSONObject;

   import android.content.Context;
   import android.os.AsyncTask;
   import android.os.Bundle;
   import android.support.v4.app.Fragment;
   import android.view.LayoutInflater;
   import android.view.View;
   import android.view.ViewGroup;
   import android.view.inputmethod.InputMethodManager;
   import android.widget.Button;
   import android.widget.EditText;
   import android.widget.LinearLayout;
   import android.widget.ScrollView;
   import android.widget.Toast;


   public class FragmentSignupForm extends Fragment {

LayoutInflater inflater;
String result = null;
InputStream is = null;
StringBuilder sb = null;
JSONArray jArray;
EditText c_nameText;
EditText c_addressText;
EditText c_postcodeText;
EditText c_emailText;
EditText s_nameText;
EditText c_addressLine2Text;
EditText telephone_Text;
public static String CUSTOMER_NAME = "";
public static String CUSTOMER_ADDRESS = "";
public static String CUSTOMER_ADDRESS1 = "";
public static String CUSTOMER_ADDRESS2 = "";
public static String CUSTOMER_POSTCODE = "";
public static String CUSTOMER_ID;
public static String CUSTOMER_EMAIL = "";
public static String SALES_CONTACT = "";
public static String Telephone = "";

String output = null;

ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
ViewGroup con;


public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance)
{
    this.inflater = inflater;
    if(container == null)return null;
    container = (ScrollView)inflater.inflate(R.layout.signup_form_layout, container, false);
    con = container;
    ScrollView sv = (ScrollView)container.findViewById(R.id.SV);
    sv.setBackgroundDrawable(AssestUtil.getBitmapFromAsset(inflater.getContext(), "bg.jpg"));

    LinearLayout ll = (LinearLayout)container.findViewById(R.id.ll);
    ll.setBackgroundDrawable(AssestUtil.getBitmapFromAsset(inflater.getContext(), "formbg2.png"));

    c_nameText = (EditText)container.findViewById(R.id.cust_name);
    c_nameText.setText(CUSTOMER_NAME);
    c_addressText = (EditText)container.findViewById(R.id.cust_address);
    c_addressText.setText(CUSTOMER_ADDRESS1);
    c_addressLine2Text = (EditText)container.findViewById(R.id.cust_Address2);
    c_addressLine2Text.setText(CUSTOMER_ADDRESS2);
    c_postcodeText = (EditText)container.findViewById(R.id.postcode);
    c_postcodeText.setText(CUSTOMER_POSTCODE);
    c_emailText = (EditText)container.findViewById(R.id.cust_email);
    c_emailText.setText(CUSTOMER_EMAIL);
    s_nameText = (EditText)container.findViewById(R.id.sales_name);
    s_nameText.setText(SALES_CONTACT);
    telephone_Text = (EditText)container.findViewById(R.id.telephone);
    telephone_Text.setText(Telephone);             

        Button save = (Button)container.findViewById(R.id.save_btn);
        Button Reset = (Button)container.findViewById(R.id.reset_btn);
        final Context context = inflater.getContext();
          //Send form data to server on click action
       save.setOnClickListener(new View.OnClickListener()
       {

            public void onClick(View v) {

                CUSTOMER_NAME = c_nameText.getText().toString();
                System.out.println(CUSTOMER_NAME);
                CUSTOMER_ADDRESS = c_addressText.getText().toString() + ","+ c_addressLine2Text.getText().toString()+","+c_postcodeText.getText().toString();;
                CUSTOMER_POSTCODE = c_postcodeText.getText().toString();
                Telephone = telephone_Text.getText().toString();

                new SendDataToServer().execute(c_nameText.getText().toString(),c_addressText.getText().toString(),c_addressLine2Text.getText().toString(),c_postcodeText.getText().toString(),c_emailText.getText().toString(),s_nameText.getText().toString(),telephone_Text.getText().toString());
                InputMethodManager imm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
              imm.hideSoftInputFromWindow(s_nameText.getWindowToken(), 0);
            }
       });

     Reset.setOnClickListener(new View.OnClickListener()
       {

            public void onClick(View v) {

                c_nameText.setText(""); 
                c_addressText.setText("");
                c_addressLine2Text.setText("");
                c_postcodeText.setText("");
                c_emailText.setText("");
                s_nameText.setText("");
                telephone_Text.setText("");
            }
       });

    return container;
}

private class SendDataToServer extends AsyncTask<String, Void, String>
{

    @Override
    protected String doInBackground(String... params) {

        try
        {                   
        nameValuePairs.add(new BasicNameValuePair("cust_name",params[0]));
        nameValuePairs.add(new BasicNameValuePair("cust_address",params[1]+","+params[2]));
        nameValuePairs.add(new BasicNameValuePair("cust_postcode",params[3]));
        nameValuePairs.add(new BasicNameValuePair("cust_email",params[4]));
        nameValuePairs.add(new BasicNameValuePair("sales_name",params[5]));
        nameValuePairs.add(new BasicNameValuePair("pvgis_data", params[6]));    

             HttpClient httpclient = new DefaultHttpClient();
              HttpPost httppost = new HttpPost("http://ideal.contrastgroup.info/idealsolar/initializeCustomer.php");
                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                HttpResponse response = httpclient.execute(httppost);
                HttpEntity entity = response.getEntity();
                is = entity.getContent();

                JSONObject myAway = new JSONObject(read(is));
                CUSTOMER_ID = myAway.getString("custID");
                output = myAway.getString("message");


        }
        catch(Exception e)
        {
            output = "null";

        }
        return output;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        if(result.equalsIgnoreCase("success"))
        {
        Toast.makeText(inflater.getContext(), "Database updated", Toast.LENGTH_SHORT).show();
        }
        else
        {
            Toast.makeText(inflater.getContext(), "Error in Connection", Toast.LENGTH_SHORT).show();
        }
    }

}

public static String read(InputStream in) throws IOException {
    StringBuilder sb = new StringBuilder();
    BufferedReader r = new BufferedReader(new InputStreamReader(in));

    for (String line = r.readLine(); line != null; line = r.readLine()) {
        sb.append(line);
    }

    in.close();
    System.out.println(sb.toString());
    return sb.toString();
}


@Override
public void onDestroyView() {
    super.onDestroyView();

    Fragment1.unbindDrawables(con.findViewById(R.id.SV));
    System.gc();
}

}

     public static void unbindDrawables(View view) {
        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();
        }

4 个答案:

答案 0 :(得分:1)

来自谷歌:

  

片段状态寻呼机支持       演示如何使用支持类ViewPager和FragmentStatePagerAdapter来构建用户界面的用户界面   向左或向右移动以在片段之间切换。这个版本的   适配器不会保留ViewPager所具有的片段实例   破坏。

http://developer.android.com/resources/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStatePagerSupport.html

与普通寻呼机的区别在于它扩展了FragmentStatePagerAdapter。

编辑: 在谷歌代码中,你在适配器中有这个:

public static class MyAdapter extends FragmentStatePagerAdapter {
    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {
        return ArrayListFragment.newInstance(position);
    }
}

注意getItem()实现。我们按需获得一个新片段,因此我们不会在需要之前创建片段。这与您创建所有片段并将其添加到矢量的方法形成对比。 (java更喜欢arraylists btw。)根据你的方法,片段不会从内存中删除,因为总会有片段的引用。

编辑2: 再具体一点。在下面:

@Override
public Fragment getItem(int position) {
    return ArrayListFragment.newInstance(position);
}
你可以做点什么:

    @Override
    public Fragment getItem(int position) {
if(position == 1) {
return Fragment1.newInstance(position);
} else {
return Fragment2.newInstance(position);
}

    }

答案 1 :(得分:1)

根据文档OnDestroyView在片段不再可见时调用,如onStop用于活动,但OnDestroy(Fragments)等同于OnDestroy for Activity。

因此,从片段的OnDestroy调用unBindDrawable应释放所有内存。

@Override
        public void onDestroy() {
            super.onDestroy();
            Utils.log(TAG, "onDestroy   position ImageGridFragment");
            unbindDrawables(mGridView);
            mGridView = null;
            gridAdapter = null;
            System.gc();
            Runtime.getRuntime().gc();
         }

答案 2 :(得分:0)

首先对所有位图变量进行null检查,例如

if(null==yourBitmapVar)
//initialize yourBitmapVar here

所以它总是不会初始化位图

我认为这是正确的方式..并且应该有效 假设您在活动中使用了两个片段f1和f2,

你在f1

中有2位图
bitmap a;
bitmap b;

再次在f2中的2位图

bitmap a;
bitmap b;

现在无论何时初始化这些var只需使用null检查,如果这些只是null,那么初始化它们或者不要..那么你就不会遇到任何内存问题,

如果你想清除你的位图

bitmap.clear();

然后当您在片段之间切换时,您应该在显示任何内容之前初始化位图..这意味着在超级方法之前。并确保当片段到达可见性时,位图被初始化

我认为你需要做的一切:) 快乐的编码

答案 3 :(得分:0)

感谢all-ok响应,我设法解决了我的错误。使用甚至onDestroy我一直在记忆中。我在片段中添加了这个: 其中rl_todo是包含gridview的RelativeLayout。 gv_productos它是gridview filtro是包含所有视图的活动。

@Override
public void onDestroy() {
    super.onDestroy();
    Log.i("onDestroy", "onDestroy position ImageGridFragment");
    RelativeLayout rl_todo=(RelativeLayout) activity.findViewById(R.id.rl_todo);
    Utilidades.unbindDrawables(rl_todo);

    gv_productos = null;
    filtro = null;
    System.gc();
    Runtime.getRuntime().gc();
}


@Override
public void onDestroyView() {
    super.onDestroyView();
    Log.i("onDestroy", "onDestroy position ImageGridFragment");
    RelativeLayout rl_todo=(RelativeLayout) activity.findViewById(R.id.rl_todo);
    Utilidades.unbindDrawables(rl_todo);

    gv_productos = null;
    filtro = null;
    System.gc();
    Runtime.getRuntime().gc();
}