Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory issues in fragments showing images

I am using fragments to show images/pages.I have one Activity(Main) which contains all the fragments.

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 = "";
   }

   }

Here is the code in fragment class -

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();
    }

   }

Everytime when i move to next fragment,the onDestroyView() of previous fragment get called and i am removing all the references of bitmaps and imageviews but still the memory of bitmaps or drawables dont get released and memory keeps on increasing.and finally it get crashed at around 50MB.

Can any one help one this?I am developing this app for galaxy tab only.

UPDATE - Code for dynamic page -

 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();
        }
like image 716
Khushwant Avatar asked Feb 13 '12 09:02

Khushwant


2 Answers

From google:

Fragment State Pager Support Demonstrates the use of the support class ViewPager with a FragmentStatePagerAdapter to build a user interface where the user can fling left or right to switch between fragments. This versions of the adapter doesn't keep around the fragment instances that ViewPager has destroyed.

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

The difference from normal pager is it extends FragmentStatePagerAdapter.

Edit: In the google code you have this in the adapter:

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);
    }
}

Notice getItem() implementation. We get a new fragment on demand, so we wont create the fragment before we need it. This stands in contrast to your approach where you create all fragments and add them to an vector. (java prefer arraylists btw.) With your approach the fragments wont be removed from memory as there always will be a reference to the fragments.

Edit 2: To be specific. In following:

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

you could do something like:

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

    }
like image 106
Warpzit Avatar answered Oct 14 '22 10:10

Warpzit


As per documentaions OnDestroyView get called when fragment is no longer visible like onStop for activity but on OnDestroy (Fragments) is equivalent to OnDestroy for Activity.

So calling unBindDrawable from OnDestroy of fragments should release all the memory.

@Override
        public void onDestroy() {
            super.onDestroy();
            Utils.log(TAG, "onDestroy   position ImageGridFragment");
            unbindDrawables(mGridView);
            mGridView = null;
            gridAdapter = null;
            System.gc();
            Runtime.getRuntime().gc();
         }
like image 38
all-ok Avatar answered Oct 14 '22 09:10

all-ok