1

Very new to Android. I have an Activity which creates some N custom views. Each custom view it creates gets added to the Activity LinearLayout and shows up on the screen. This works just fine until I rotate the screen. Suddenly the custom views don't display their data correctly. In my test scenario the Activity created 2 instances of my custom view and the first one showed "Name 1" while the second one showed "Name 2" in each custom view's EditText. When I switch the orientation (this is all done on my Nexus 7), Both custom view's EditText say "Name 2". I used println statements in the Activity and in the constructor of the custom view to make sure that the correct values were still being passed in but it just displays differently. Any ideas? Here is some simplified code:

public class EditTemplateWorkout extends Activity{

private int templateWorkoutId = -1;
private TemplateWorkout templateWorkout;

@SuppressWarnings("unchecked")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_edit_template);
    Intent intent = this.getIntent();
    templateWorkoutId = intent.getIntExtra(Messages.TEMPLATEWORKOUTID_MESSAGE, -1);                 
    templateWorkout = templateWorkoutId == -1 ? new TemplateWorkout() : LiftDroidDbHelper.TemplateWorkoutService.get(templateWorkoutId, true, this);            
    final EditText editTextName = (EditText) this.findViewById(R.id.editTextName);        
    editTextName.setText(templateWorkout.getName());
    editTextName.addTextChangedListener(new TextWatcher() {
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {                
            if(!s.equals("") ){ 
                String txtVal = editTextName.getText().toString();                  
                templateWorkout.setName(txtVal);
            }
        }
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {

        }
        public void afterTextChanged(Editable s) {

        }
    });

    LinearLayout root = (LinearLayout)this.findViewById(R.id.rootLayout);   
    root.removeAllViews();      
    for(TemplateExercise te : templateWorkout.getTemplateExercises()){
        root = (LinearLayout)this.findViewById(R.id.rootLayout);

        System.out.println("activity adding view for "+te.getName());
        EditTemplateExerciseView editTemplateExercise = new EditTemplateExerciseView(te, this, null);                   
        editTemplateExercise.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        root.addView(editTemplateExercise);
    }

    int moot = 3;
}

}

public class EditTemplateExerciseView extends LinearLayout {

TemplateExercise templateExercise;  

public EditTemplateExerciseView(TemplateExercise te, Context context, AttributeSet attrs) {
    super(context, attrs);      
    templateExercise = te;
    setOrientation(LinearLayout.HORIZONTAL);
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    inflater.inflate(R.layout.view_edit_template_exercise, this, true);
    TextView txtName = (TextView) this.findViewById(R.id.templateExerciseNameTxt);        
    txtName.setText(templateExercise.getName() + templateExercise.getTemplateExerciseID());        
    System.out.println("templateXercise id ="+te.getTemplateExerciseID());
    System.out.println("set name:"+templateExercise.getName() + ", confirmed val="+txtName.getText());

}//constructor      

}

Here is a copy of my simplified custom view:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Name:"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/templateExerciseNameTxt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:ems="10" >

        <requestFocus />
    </EditText> 
</LinearLayout>    
</merge>

Here is a link to the Screenshots: http://imgur.com/a/2HqmS

Here is the prinln output results from the code when it renders the good expected view:

01-17 17:44:49.588: I/System.out(22474): activity adding view for Bench Press
01-17 17:44:49.618: I/System.out(22474): templateXercise id =4
01-17 17:44:49.618: I/System.out(22474): set name:Bench Press, confirmed val=Bench  Press4
01-17 17:44:49.618: I/System.out(22474): activity adding view for Incline Bench
01-17 17:44:49.648: I/System.out(22474): templateXercise id =6
01-17 17:44:49.648: I/System.out(22474): set name:Incline Bench, confirmed val=Incline Bench6

Here is the println output results from the code when the screen orientation changes and the Activity's onCreate method is called:

01-17 17:45:31.568: I/System.out(22474): activity adding view for Bench Press
01-17 17:45:31.588: I/System.out(22474): templateXercise id =4
01-17 17:45:31.588: I/System.out(22474): set name:Bench Press, confirmed val=Bench   Press4
01-17 17:45:31.588: I/System.out(22474): activity adding view for Incline Bench
01-17 17:45:31.618: I/System.out(22474): templateXercise id =6
01-17 17:45:31.618: I/System.out(22474): set name:Incline Bench, confirmed val=Incline Bench6
01-17 17:45:31.648: W/IInputConnectionWrapper(22474): showStatusIcon on inactive InputConnection
01-17 17:45:31.808: W/IInputConnectionWrapper(22474): getTextBeforeCursor on inactive InputConnection
01-17 17:45:31.878: W/IInputConnectionWrapper(22474): getTextBeforeCursor on inactive InputConnection
01-17 17:45:31.978: W/IInputConnectionWrapper(22474): getTextBeforeCursor on inactive InputConnection
01-17 17:45:32.178: W/IInputConnectionWrapper(22474): getTextBeforeCursor on inactive InputConnection
01-17 17:45:32.318: W/IInputConnectionWrapper(22474): getTextBeforeCursor on inactive InputConnection
01-17 17:45:32.338: W/IInputConnectionWrapper(22474): getTextBeforeCursor on inactive InputConnection

You can see that I am passing the expected values into the first custom view but it shows the value of the second one. The code you see here is greatly simplified from what the views originally did. Any android gurus know what I am doing wrong here?

1 Answers1

0

What you need it save your CustomViews State , when you Change the orientation of the device the android OS initialize your view from the beginning so try to implements in your view methods

onSaveInstanceState 

which will called by onpause method before the orientation changed and here you will save your data from edittext

and

onRestoreInstanceState

which will called after the orientation done and add the correct data to your views

and here full code :

How to prevent custom views from losing state across screen orientation changes

Community
  • 1
  • 1
mohammed momn
  • 3,230
  • 1
  • 20
  • 16
  • But in my Activity when orientation changes, I was clearing the custom views and then re-adding them. Would your approach only be necessary if the custom views had been declared in xml, rather than programatically? What surprises me is that I create two instances of my custom view, one for each record in the database and when the orientation changes, they each have the exact same value when I clearly passed unique values to them. – user3208751 Jan 18 '14 at 07:33
  • It looks like the same methodology works for my Activity wrt rebuilding my Views from the onRestoreInstanceState method. Why does onCreate mess up the Views but onRestoreInstanceState does not after screen orientation change? Thanks for the tips Mohammed Momn. – user3208751 Jan 18 '14 at 08:30
  • 1
    onCreate method making new initialize for activity so it will clear all your variables and views data but android os may be if you declared view with unique id will save the state for your view but if you using one id in custom view and using your custom view twice the android os will put the initial value for two custom view with same child view id – mohammed momn Jan 18 '14 at 18:16
  • onRestoreInstanceState called when the activity created and in here Bunndle object will saving the last state of the destroyed activity , you can see more about it in topic android life cycle – mohammed momn Jan 18 '14 at 18:18