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