Friday, May 3, 2013

UI elements lost after Activity/Fragment re-created

Last two post "Understand lifecycle of Activity and Fragment" and "Different case in lifecycle of Activity and Fragment", we have introduction about lifecycle. Now we check how it affect on real case.

In the layout of our fragment, we have 4 ImageView.
  • image_a: With android:src defined in XML.
  • image_b: Load image in onCreateView().
  • image_c: Load image in onCreateView(), only if savedInstanceState == null.
  • image_d: Load image in runtime, triggered by button clicked
In case image_c and image_d, the image will lost when orientation changed, or "Don't keep activities".




Code List -

Modify our custom FragmentActivity (MyFragmentActivity.java) and Fragment (MyFragment.java.java) to display savedInstanceState also.

MyFragmentActivity.java
package com.example.androidfragmenttest;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.widget.Toast;

public class MyFragmentActivity extends FragmentActivity {
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  recLifeCycle_with_savedInstanceState(savedInstanceState);
  super.onCreate(savedInstanceState);
 }
 
 @Override
 protected void onStart() {
  recLifeCycle();
  super.onStart();
 }

 @Override
 protected void onRestart() {
  recLifeCycle();
  super.onRestart();
 }

 @Override
 protected void onResume() {
  recLifeCycle();
  super.onResume();
 }

 @Override
 protected void onPause() {
  recLifeCycle();
  super.onPause();
 }
 
 @Override
 protected void onStop() {
  recLifeCycle();
  super.onStop();
 }

 @Override
 protected void onDestroy() {
  recLifeCycle();
  super.onDestroy();
 }

 public void recLifeCycle(){
  
  String className = getClass().getSimpleName();
  StackTraceElement[] s = Thread.currentThread().getStackTrace();
  String methodName = s[3].getMethodName();
  
  Toast.makeText(getApplicationContext(), 
    className + "." + methodName, Toast.LENGTH_SHORT).show();
  Log.i("MYTAG", className + "." + methodName);
  
 }
 
 public void recLifeCycle(String note){
  String className = getClass().getSimpleName();
  StackTraceElement[] s = Thread.currentThread().getStackTrace();
  String methodName = s[3].getMethodName();

  Toast.makeText(getApplicationContext(), 
    className + "." + methodName, Toast.LENGTH_SHORT).show();
  Log.i("MYTAG", className + "." + methodName + " / " + note);
 }
 
 public void recLifeCycle_with_savedInstanceState(Bundle state){
  
  String stateMsg;
  if(state == null){
   stateMsg = "savedInstanceState == null";
  }else{
   stateMsg = "savedInstanceState != null";
  }
  
  String className = getClass().getSimpleName();
  StackTraceElement[] s = Thread.currentThread().getStackTrace();
  String methodName = s[3].getMethodName();
  
  Toast.makeText(getApplicationContext(), 
    className + "." + methodName, Toast.LENGTH_SHORT).show();
  Log.i("MYTAG", className + "." + methodName + " / " + stateMsg);
 }

}


MyFragment.java
package com.example.androidfragmenttest;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

public class MyFragment extends Fragment {

 @Override
 public void onAttach(Activity activity) {
  recLifeCycle();
  super.onAttach(activity);
 }

 @Override
 public void onCreate(Bundle savedInstanceState) {
  recLifeCycle_with_savedInstanceState(savedInstanceState);
  super.onCreate(savedInstanceState);
 }

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  
  recLifeCycle_with_savedInstanceState(savedInstanceState);
  return super.onCreateView(inflater, container, savedInstanceState);
 }
 
 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
  recLifeCycle_with_savedInstanceState(savedInstanceState);
  super.onActivityCreated(savedInstanceState);
 }

 @Override
 public void onStart() {
  recLifeCycle();
  super.onStart();
 }

 @Override
 public void onResume() {
  recLifeCycle();
  super.onResume();
 }

 @Override
 public void onPause() {
  recLifeCycle();
  super.onPause();
 }

 @Override
 public void onStop() {
  recLifeCycle();
  super.onStop();
 }

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

 @Override
 public void onDestroy() {
  recLifeCycle();
  super.onDestroy();
 }

 @Override
 public void onDetach() {
  recLifeCycle();
  super.onDetach();
 }
 
 public void recLifeCycle(){
  
  String className = getClass().getSimpleName();
  StackTraceElement[] s = Thread.currentThread().getStackTrace();
  String methodName = s[3].getMethodName();
  
  String msg = className + "." + methodName;
  
  Toast.makeText(getActivity(), 
    msg, Toast.LENGTH_SHORT).show();
  Log.i("MYTAG", msg);
 }
 
 public void recLifeCycle(String note){
  
  String className = getClass().getSimpleName();
  StackTraceElement[] s = Thread.currentThread().getStackTrace();
  String methodName = s[3].getMethodName();
  
  String msg = className + "." + methodName;

  Toast.makeText(getActivity(), 
    msg, Toast.LENGTH_SHORT).show();
  Log.i("MYTAG", msg + " / " + note);
 }
 
 public void recLifeCycle_with_savedInstanceState(Bundle state){
  
  String stateMsg;
  if(state == null){
   stateMsg = "savedInstanceState == null";
  }else{
   stateMsg = "savedInstanceState != null";
  }
  
  String className = getClass().getSimpleName();
  StackTraceElement[] s = Thread.currentThread().getStackTrace();
  String methodName = s[3].getMethodName();
  
  String msg = className + "." + methodName + " / " + stateMsg;
  
  Toast.makeText(getActivity(), 
    msg, Toast.LENGTH_SHORT).show();
  Log.i("MYTAG", msg);
 }
 
}


The fragment layout, /res/layout/fragment_layout1.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Fragment 1"/>
    
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <LinearLayout 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            
            <LinearLayout 
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <TextView 
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="image_a"/>
                <ImageView
                    android:id="@+id/image_a"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/ic_launcher"/>
            </LinearLayout>
            <LinearLayout 
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <TextView 
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="image_b"/>
                <ImageView
                    android:id="@+id/image_b"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"/>
            </LinearLayout>
            <LinearLayout 
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <TextView 
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="image_c"/>
                <ImageView
                    android:id="@+id/image_c"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"/>
            </LinearLayout>
            <TextView 
                android:id="@+id/textstate"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
            <LinearLayout 
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <TextView 
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="image_d"/>
                <ImageView
                    android:id="@+id/image_d"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"/>
                <Button
                    android:id="@+id/loadimage_d"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Load image_d"/>
            </LinearLayout>

        </LinearLayout>
    </ScrollView>
    
</LinearLayout>


MainActivity.java
package com.example.androidfragmenttest;

import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends MyFragmentActivity {

 static public class MyFragment1 extends MyFragment {
  
  ImageView image_b, image_c, image_d;
  TextView textState;
  Button buttonLoadImage_d;

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
   super.onCreateView(inflater, container, savedInstanceState);
   View view = inflater.inflate(R.layout.fragment_layout1, null);
   
   image_b = (ImageView)view.findViewById(R.id.image_b);
   image_c = (ImageView)view.findViewById(R.id.image_c);
   image_d = (ImageView)view.findViewById(R.id.image_d);
   textState = (TextView)view.findViewById(R.id.textstate);
   buttonLoadImage_d = (Button)view.findViewById(R.id.loadimage_d);
   
   image_b.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher));
   
   if(savedInstanceState == null){
    image_c.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher));
    textState.setText("MyFragment1.savedInstanceState == null");
   }else{
    textState.setText("MyFragment1.savedInstanceState != null");
   }
   
   buttonLoadImage_d.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View arg0) {
     image_d.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher));
    }});
   
   return view;
  }

 }

 FrameLayout fragmentContainer;
 Button buttonFinish;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  buttonFinish = (Button)findViewById(R.id.finish);
  buttonFinish.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    finish();
   }});

  fragmentContainer = (FrameLayout) findViewById(R.id.container);
  if (savedInstanceState == null) {
   // if's the first time created
   
   MyFragment1 myListFragment1 = new MyFragment1();
   FragmentManager supportFragmentManager = getSupportFragmentManager();
   FragmentTransaction fragmentTransaction = supportFragmentManager
     .beginTransaction();
   fragmentTransaction.add(R.id.container, myListFragment1);
   fragmentTransaction.commit(); 
  }
 }

}


Main layout, /res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/finish"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="finish()"/>
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </FrameLayout>

</LinearLayout>




download filesDownload the files.

No comments: