0

i know that GC take care of objects that there is no Reference to it , but i do not know how it works exactly. in this simple android code we have an activity and textview in it, i know when screen rotates the entire activity destroyed and android create a new one. GC can destroy the previous activity? is it right that because textview hold a Reference to the activity the entire activity survive from GC ? do i need do something in activity onfinish(or something similar) to release Reference ?

@Override
 protected void onCreate(Bundle state) {
   super.onCreate(state);
   TextView textview = new TextView(this);
   textview .setText("Leaks are bad");
   setContentView(textview );
 }

Edite:

this my codes. i used MAT: Biggest Object :com.android.internal.policy.impl.PhoneWindow$DecorView

by using MAT i found that DecorView object is the problem, when i rotate screen 7 times app crash with OOM and exactly there is 7 DecorView Object in MAT report.

package atsoft.law.reader;

import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;

import atsoft.law.R;
import atsoft.law.selecttext.NewHighlightDialog;

public class ReaderActivity extends BaseReaderActivity
{
    Bundle bundle;
    MainDialogFragment mainDialogFragment;
    NewHighlightDialog newHighlightDialog;




    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        bundle = getIntent().getExtras();
        setLawID(bundle.getInt("law_id", 0));
        setCurrentPage(bundle.getInt("madde_id", 0));
        mainDialogFragment = new MainDialogFragment();
        adapter.setMainDialogFragment(mainDialogFragment);


        requestLaw(lawID);

    }

/////////////////OnLawReceived//////////////
    @Override
    protected void OnLawReceived()
    {
        adapter.PrePairAdapter(getSupportFragmentManager(),null, this, lawID);
        viewPager.setAdapter(adapter);
        viewPager.setCurrentItem(getCurrentPage());

        Log.i("total", String.valueOf(Runtime.getRuntime().totalMemory()));
        Log.i("max", String.valueOf(Runtime.getRuntime().maxMemory()));
        Log.i("free", String.valueOf(Runtime.getRuntime().freeMemory()));
    }


    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);
        outState.putInt("current_viewpager_page", viewPager.getCurrentItem());
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState)
    {
        super.onRestoreInstanceState(savedInstanceState);
        if(savedInstanceState != null)
        {
            setCurrentPage(savedInstanceState.getInt("current_viewpager_page", 0));
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        if(keyCode==KeyEvent.KEYCODE_MENU)
        {
            adapter.Prepair2();
            mainDialogFragment.Initialize(this, viewPager, adapter);
            mainDialogFragment.show(getSupportFragmentManager(),null);

            return true;
        }
        else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
        {
            viewPager.setCurrentItem(viewPager.getCurrentItem()+1);
            return true;
        }
        else if(keyCode == KeyEvent.KEYCODE_VOLUME_UP)
        {
            viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
            return true;
        }
        else if(keyCode == KeyEvent.KEYCODE_BACK)
        {
            if(mainDialogFragment.isAdded())
            {
                mainDialogFragment.dismiss();
            }
        }

        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.reader, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings)
        {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


    /////////ViewPager Page Events/////
    @Override
    public void onPageScrolled(int i, float v, int i2) {

    }

    @Override
    public void onPageSelected(int i) {

        if (newHighlightDialog != null) newHighlightDialog.dismissAndDeactivateTextSelector();
    }

    @Override
    public void onPageScrollStateChanged(int i) {

    }

    public NewHighlightDialog getHighlightDialog()
    {
        if(this.newHighlightDialog == null) this.newHighlightDialog = new NewHighlightDialog(this);
        return this.newHighlightDialog;
    }


    @Override
    protected void onDestroy()
    {
        Log.i("BaseReaderActivity", "onDestroy ");
        super.onDestroy();
        unbindDrawables(findViewById(R.id.root_in_readeractivity_layout));
        mainDialogFragment.releaseReference();
        mainDialogFragment = null;
        if(newHighlightDialog != null)
        {
            newHighlightDialog.realestReference();
            newHighlightDialog = null;
        }
        getAdapter().releaseReference();

        System.gc();


    }
    private void unbindDrawables(View view) {
        if (view.getBackground() != null)
            view.getBackground().setCallback(null);

        if (view instanceof ImageView) {
            ImageView imageView = (ImageView) view;
            imageView.setImageBitmap(null);
        } else if (view instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) view;
            for (int i = 0; i < viewGroup.getChildCount(); i++)
                unbindDrawables(viewGroup.getChildAt(i));

            if (!(view instanceof AdapterView))
                viewGroup.removeAllViews();
        }
    }
}










public abstract class BaseReaderActivity extends ActionBarActivity implements OnThreadFinishListener, ViewPager.OnPageChangeListener
{



    protected int lawID = 0;
    protected int vpCurrentPage = 0;
    protected FragmentAdapter adapter;
    protected ViewPager viewPager;
    private GlobalData globalData;
    ProgressDialog progressDialog;



    private void Init()
    {
        globalData= (GlobaData) this.getApplicationContext();
        adapter = FragmentAdapter.getInstance(getSupportFragmentManager());
        viewPager = (ViewPager) findViewById(R.id.vp);
        viewPager.setOnPageChangeListener(this);
        progressDialog = new ProgressDialog(this);
    }

    protected FragmentAdapter getAdapter()
    {
        return FragmentAdapter.getInstance(getSupportFragmentManager());
    }

    protected ViewPager getPager()
    {
        return this.viewPager;
    }
    protected GlobalStack getGlobalData()
    {
        return this.globalData;
    }
    protected DbCenter getDb()
    {
        return DbCenter.getInstance(this);
    }

    protected void setLawID(int id)
    {
        this.lawID = id;
    }
    protected int getLawID()
    {
        return this.lawID;
    }
    protected void setCurrentPage(int page)
    {
        this.vpCurrentPage = page;
    }
    protected int getCurrentPage()
    {
        return this.vpCurrentPage;
    }
    protected void requestLaw(int lawID)
    {

        if(!getGlobalData().checkLawAvailability(lawID))
        {

            this.UploadLawToGlobalData(lawID);
            return;
        }
        else
        {

            this.OnLawReceived();
        }
    }

    protected abstract void OnLawReceived();
    protected void UploadLawToGlobalData(int lawID)
    {
        progressDialog.setText(LawIDs.getFaNameById(lawID));
        progressDialog.show();

        getDb().Prepair(lawID, this);
    }
    public Law getCurrentLaw()
    {
        return getGlobalData().getTheLaw();
    }
    @Override
    public void threadFinished() throws IOException, XmlPullParserException
    {
        getGlobalData().UploadToGlobalData(getDb().getLaw());
        this.OnLawReceived();
        Log.i("BaseReaderActivity","upload completed !");
        Log.i("BaseReaderActivity", "OnLawReceived");
        progressDialog.hide();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide();
        setContentView(R.layout.activity_main_);
        Init();
        getGlobalData().Init();

        viewPager.setOffscreenPageLimit(2);
        viewPager.setSoundEffectsEnabled(true);
        adapter.setViewPager(viewPager);
    }
}
mehrdad
  • 51
  • 1
  • 7

2 Answers2

0

GC is cleaning your objects and (in practise) you can't do anything with that, this is language property (awesome feature in my opinion). you don't have to do anything in "onFinish", system will clean stuff for you, yes - all your objects, widgets etc. if you want to keep some data when device rotate (so like you said Activity is destroyed and all it's references) you might use onSaveInstanceState. More about saving data against GC HERE

snachmsm
  • 17,866
  • 3
  • 32
  • 74
  • my problem is not saving stuff, i have memory leak problem. – mehrdad Dec 30 '14 at 19:55
  • my activitys is not destroyed. – mehrdad Dec 30 '14 at 19:55
  • Tell me you don't have `android:configChanges` in your manifest? And there is no leak in the code you have shown. – Simon Dec 30 '14 at 19:59
  • yeah GC destroy Activity BUT if there is no reference pointing to the Activity, there is such a reference (by textview)to the activity in the code? – mehrdad Dec 30 '14 at 20:00
  • The `TextView` has no references as soon as `onCreate()` finishes. I repeat, there is NO leak in the code you have shown. – Simon Dec 30 '14 at 20:01
  • i edited my answer, see setContentView(), now textview has ref? – mehrdad Dec 30 '14 at 20:31
  • No. It makes no difference. The TextView cannot have a life time greater than the Activity and is therefore eligible for collection. If you have a leak, it is not in the code shown. This is getting a bit pointless. Why not post the entire Activity and ask a **specific** question? – Simon Dec 30 '14 at 20:37
  • this is not my code, i want to understand the GC logic, my code is near 10,000 lines. and has complexity ... , can you introduce some good article for outOfmemory, i get OOM when i rotates screen several times. – mehrdad Dec 30 '14 at 21:24
  • 1
    Use MAT to view your heap. And post the code for the Activity which crashes. That's not 10,000 lines. – Simon Dec 30 '14 at 22:29
0

Based on your scenario, you just want to destroy the previous setup from your previous orientation, right?

The best way to do it is android:configChanges="orientation|screenSize"

On-topic question, check this Why is it bad practice to call System.gc()?

calling system.gc in your app you don't have the control of what might the collector kill in your app and it might cause a lot of trouble like nullpointers and etc.

Community
  • 1
  • 1
MaChee Neraid
  • 603
  • 1
  • 7
  • 17