Android save and restore TextView text ViewPager fragments - android

In my ViewPager i have some fragments which i change some TextView texts dynamically, after switch between pages texts of TextViews clear, and i can't save and restore them from instance
this is my code and dont work
private String value1;
private String value2;
private String value3;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//#formatter:off
context = getActivity().getBaseContext();
activity = getActivity();
//#formatter:on
}
#Override
public void onViewStateRestored(#Nullable Bundle inState) {
super.onViewStateRestored(inState);
if (inState != null) {
inState.getString("value1", value1);
inState.getString("value2", value2);
inState.getString("value3", value3);
sahmiyeh_value_1.setText(value1);
sahmiyeh_value_2.setText(value2);
sahmiyeh_value_3.setText(value3);
}
}
#Override
public void onSaveInstanceState(#Nullable Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("value1", sahmiyeh_value_1.getText().toString());
outState.putString("value2", sahmiyeh_value_2.getText().toString());
outState.putString("value3", sahmiyeh_value_3.getText().toString());
}

You can try freezesText
<TextView
...
android:freezesText="true" />
From documentation :
If set, the text view will include its current complete text inside of its frozen icicle in addition to meta-data such as the current cursor position. By default this is disabled; it can be useful when the contents of a text view is not stored in a persistent place such as a content provider

You didn't declare the string value.
value1, value2, value3 is empty. That's why there's no value on your TextView or EditText.
#Override
public void onViewStateRestored(#Nullable Bundle inState) {
super.onViewStateRestored(inState);
if (inState != null) {
value1 = inState.getString("value1");
value2 = inState.getString("value2");
value3 = inState.getString("value3");
sahmiyeh_value_1.setText(value1);
sahmiyeh_value_2.setText(value2);
sahmiyeh_value_3.setText(value3);
}
}
Or you can do it like this.
sahmiyeh_value_1.setText(inState.getString("value1"));
sahmiyeh_value_2.setText(inState.getString("value2"));
sahmiyeh_value_3.setText(inState.getString("value3"));

Related

How can I use savedInstanceState and show text in editText?

I want to save text in a editText and when I rotate the cell phone then it's showed again.
but, "it's showed again" this part doesn't work but, Toast is working.
I thought "setText" is the one...
here is the
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = findViewById(R.id.editText);
button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
name = editText.getText().toString();
showToast("saved : " + name);
}
});
if (savedInstanceState != null){
name = savedInstanceState.getString("name");
showToast("restore : " + name);
editText.setText("name");
}
}
#Override
protected void onSaveInstanceState(#NonNull Bundle outState) {
outState.putString("name", name);
super.onSaveInstanceState(outState);
}
public void showToast(String data){
Toast.makeText(this, data, Toast.LENGTH_LONG).show();
}
}
You have wrapped the variable name in "" so you're inputting the actual text name as a string into the edit text, rather than the contents of that variable. Remove the quotation marks like so:
if (savedInstanceState != null) {
String text = savedInstanceState.getString("name");
editText.setText(text);
}
EDIT
I would also suggest that you capture the value of the text inside the edit text at the time of saveInstanceState(), incase the global 'name' variable happens to be null. Like so:
#Override
protected void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
String text = editText.getText().toString();
outState.putString("name", text);
}

get input from fragments

I have a ViewPager with 3 fragments in it, each fragment has a next and prev. button, and you can also swipe left and right to navigate through fragments. and although I'm able to get the input from each fragment when the next button is clicked, I sill can't figure out a way to get the input when the user scrolls between fragments.
this is the code in my first fragment:
public class signupfrag1 extends Fragment {
private TextInputEditText fName, lName;
public Spinner spncountry, spncity;
private Button next1;
private String vfName, vlName, vcountry, vcity;
private String method;
signupfrag1Listener activityCommander;
public interface signupfrag1Listener{
public void getDataFromFrag1(String fName, String lName, String countryName, String cityName);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
activityCommander = (signupfrag1Listener) context;
}catch (ClassCastException e){
throw new ClassCastException(context.toString());
}
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.signupfrag1, container, false);
fName = (TextInputEditText) view.findViewById(R.id.edtFName);
lName = (TextInputEditText) view.findViewById(R.id.edtLName);
spncountry = (Spinner) view.findViewById(R.id.cmbCountry);
spncity = (Spinner) view.findViewById(R.id.cmbCities);
next1 = (Button) view.findViewById(R.id.btnNext2);
next1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
vfName = fName.getText().toString();
vlName = lName.getText().toString();
if(vfName.equals("") || vfName.length()==1){
fName.setError("please enter a correct first name!");
}
else if(vlName.equals("") || vlName.length()==1){
lName.setError("Please enter a correct first name!");
}
else
startFrag2(view);
}
});}
public void startFrag2(View view){
activityCommander.getDataFromFrag1(vfName, vlName, vcity, vcountry);
}
this is the code from my main activity:
public class Main2Activityforfragments extends AppCompatActivity implements signupfrag1.signupfrag1Listener, signupfrag2.signupfrag2Listener {
private ViewPager fragsViewPager;
private SectionsPagerAdapter1 sectionsPagerAdapter1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2_activityforfragments);
fragsViewPager = (ViewPager) findViewById(R.id.fragsViewPager);
sectionsPagerAdapter1 = new SectionsPagerAdapter1(getSupportFragmentManager());
fragsViewPager.setAdapter(sectionsPagerAdapter1);
}
//this get called when the next button is clicked
#Override
public void getDataFromFrag1(String fName, String lName, String cityName, String countryName) {
if(fragsViewPager.getCurrentItem() == 0){
fragsViewPager.setCurrentItem(1);}
}
if you are in the first fragment then create ref. of interface and call its method and pass the values on Click what you want and it is needed to implement Two interface in SecondFragment. call its method in the First Fragment. you can create interface Two in SecondFragment
Two Second=new SecondFragment(); // it will be called on click of firstFragment which pass the value.
Second.two("Value one","Value two");
interface Two{
void two(String value,String value); // implement this inteface in SecondFragment and call it in FirstFragment
}
When you reach to second you get the value from the first fragment and continue with the third fragment as same.

Fragment doesnt remeber EditText's content on orientation change

I'm having some trouble with my EditText's on orientation change. For some reason they dont restore whatever was typed in them.
I have 2 classes. The main activity and the fragment which goes in the activity
Main activity:
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(
setContentView(R.layout.
getFragmentManager().beginTransaction().replace(R.id.controlsBar, new AddItemFragment()).commit();
}
}
And the fragment:
public class AddItemFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_add_item, container, false);
EditText item = (EditText) view.findViewById(R.id.itemNameAdd);
EditText amount = (EditText) view.findViewById(R.id.itemAmount);
if (savedInstanceState != null) {
System.out.println(savedInstanceState.getString("item"));
item.setText(savedInstanceState.getString("item", ""));
amount.setText(savedInstanceState.getString("amount", ""));
}
//item.setText("SOME TEXT");
//amount.setText("SOME TEXT");
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
EditText item = (EditText) getActivity().findViewById(R.id.itemNameAdd);
EditText amount = (EditText) getActivity().findViewById(R.id.itemAmount);
outState.putString("item", item.getText().toString());
outState.putString("amount", amount.getText().toString());
}
}
The funny thing is that the line "System.out.println(savedInstanceState.getString("item"));" prints out the correct word in the console.
And furthermore the outcommented lines where i set the text to "SOME TEXT" also works.
Its only when i set the text to savedInstanceState.getString("amount", ""), it wont work
Thank you
Try adding the line marked "<---- THIS LINE" to public void onSaveInstanceState(Bundle outState):
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); // <---- THIS LINE
EditText item = (EditText) getActivity().findViewById(R.id.itemNameAdd);
EditText amount = (EditText) getActivity().findViewById(R.id.itemAmount);
outState.putString("item", item.getText().toString());
outState.putString("amount", amount.getText().toString());
}
Also, look at using onActivityCreated, and check out the resources in my comment below.

SherlockFragmentActivity EditText getText() nullpointerexception

I have this error nullpointerexception, when i do getText().toString() from EditTex:
public class SendMessActivity extends SherlockFragmentActivity {
private EditText tEmail;
private Button sendButton;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.send_mess_layout);
tEmail = (EditText)findViewById(R.id.editEmailTo);
sendButton = (Button)findViewById(R.id.btn_sendmess);
endButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//String textEmail = tEmail.getText().toString(); //nullpointerexception
Editable textEmail1Editable = tEmail.getText(); //nullpointerexception
String textEmail = textEmail1Editable.toString()
Log.d(DEBUGTAG, "SENDING START:::::::: " + textEmail);
}
});
}}
Please, tell me how to do it
UPDATE Q
David, thank you, for your surmise,the problem was really in the my tangled Layouts
I had all 4 levels of nesting LinearLayouts.
After I left the simplified scheme and only 2 levels I have, all began to work
You need to call setContentView(your_layout.xml) so it knows what layout to use. Without setting the layout, all of your calls to findViewById(...) that try to find the views in your layout will return null.
public class SendMessActivity extends SherlockFragmentActivity {
private EditText tEmail;
private Button sendButton;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(your_layout.xml); //set your activity layout here.
tEmail = (EditText)findViewById(R.id.editEmailTo);
sendButton = (Button)findViewById(R.id.btn_sendmess);
endButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String textEmail = tEmail.getText().toString(); //nullpointerexception
Log.d(DEBUGTAG, "SENDING START:::::::: " + textEmail);
}
});
}}
If you have no assigned text then I would assume that the EditText retrieval of the text would be a null entry and you are attempting to make a string of that null entry.

How to retain EditText data on orientation change?

I have a Login screen which consists of 2 EditTexts for Username and Password. My requirement is that on orientation change , input data(if any) in EditText should remain as it is and a new layout should also be drawn. I have 2 layout xml files- one in layout folder and other in layout-land folder. I am trying to implement following 2 approaches but none of them is perfect:
(1) configChanges:keyboardHidden - In this approach, I don't provide "orientation" in configChanges in manifest file. So I call setContentView() method in both onCreate() and onConfigurationChanged() methods. It fulfills both my requirements. Layout is changed and input data in EditTexts also remains as it is. But it has a big problem :
When user clicks on Login button, a ProgressDialog shows until server-response is received. Now if user rotates the device while ProgressDialog is running, app crashes. It shows an Exception saying "View cannot be attached to Window." I have tried to handle it using onSaveInstanceState (which DOES get called on orientation change) but app still crashes.
(2) configChanges:orientation|keyboardHidden - In this approach, I provide "orientation" in manifest. So now I have 2 scenarios:
(a) If I call setContentView() method in both onCreate() and onConfigurationChanged(), Layout is changed accordingly but EditText data is lost.
(b) If I call setContentView() method in onCreate() , but not in onConfigurationChanged(), then EditText data is not lost but layout also not changes accordingly.
And in this approach, onSaveInstanceState() is not even called.
So I am in a really intimidating situation. Is there any solution to this problem? Please help. Thanx in advance.
By default, Edittext save their own instance when changing orientation.
Be sure that the 2 Edittexts have unique IDs and have the same IDs in both Layouts.
That way, their state should be saved and you can let Android handle the orientation change.
If you are using a fragment, be sure it has a unique ID also and you dont recreate it when recreating the Activity.
A better approach is to let android handle the orientation change. Android will automatically fetch the layout from the correct folder and display it on the screen. All you need to do is to save the input values of the edit texts in the onSaveInsanceState() method and use these saved values to initialize the edit texts in the onCreate() method.
Here is how you can achieve this:
#Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.login_screen);
...
...
String userName, password;
if(savedInstanceState!=null)
{
userName = savedInstanceState.getString("user_name");
password= savedInstanceState.getString("password");
}
if(userName != null)
userNameEdtTxt.setText(userName);
if(password != null)
passEdtTxt.setText(password);
}
>
#Override
protected void onSaveInstanceState (Bundle outState)
{
outState.putString("user_name", userNameEdtTxt.getText().toString());
outState.putString("password", passEdtTxt.getText().toString());
}
Give the element an id and Android will manage it for you.
android:id="#id/anything"
in onConfigurationChanged method, first get the data of both the edit texts in global variables and then call setContentView method. Now set the saved data again into the edit texts.
There are many ways to do this. The simplest is 2(b) in your question. Mention android:configChanges="orientation|keyboardHidden|screenSize" in your manifest so that Activity doesn't get destroyed on Orientation changes.
Call setContentView() in onConfigChange(). but before calling setContentView() get the EditText data into a string and set it back after calling setContentView()
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mEditTextData = mEditText.getText().tostring();//mEditTextData is a String
//member variable
setContentView(R.layout.myLayout);
initializeViews();
}
private void initializeViews(){
mEditText = (EditText)findViewById(R.id.edittext1);
mEdiText.setText(mEditTextData);
}
The following should work and is standard to the activities and fragments
#Override
public void onSaveInstanceState (Bundle outState)
{
outState.putString("editTextData1", editText1.getText().toString());
outState.putString("editTextData2", editText2.getText().toString());
super.onSaveInstanceState(outState);
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate();
... find references to editText1, editText2
if (savedInstanceState != null)
{
editText1.setText(savedInstanceState.getString("editTextData1");
editText2.setText(savedInstanceState.getString("editTextData2");
}
}
Im restoring instance to restore values and it works fine for me :)
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.addtask2);
if(savedInstanceState!=null)
onRestoreInstanceState(savedInstanceState);
}
Remove android:configChanges attribute from the menifest file and let android handle the orientation change your data in edittext will automatically remain.
Now The problem you mentioned is with the progress dialog force close this is because when the orientation is changed the thread running in backgroud is trying to update the older dialog component whihc was visible. You can handle it by closing the dialog on savedinstancestate method and recalling the proceess you want to perform onRestoreInstanceState method.
Below is a sample hope it helps solving your problem:-
public class MyActivity extends Activity {
private static final String TAG = "com.example.handledataorientationchange.MainActivity";
private static ProgressDialog progressDialog;
private static Thread thread;
private static boolean isTaskRunnig;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new EditText.OnClickListener() {
#Override
public void onClick(View v) {
perform();
isTaskRunnig = true;
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void perform() {
Log.d(TAG, "perform");
progressDialog = android.app.ProgressDialog.show(this, null,
"Working, please wait...");
progressDialog
.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
//isTaskRunnig = false;
}
});
thread = new Thread() {
public void run() {
Log.d(TAG, "run");
int result = 0;
try {
// Thread.sleep(5000);
for (int i = 0; i < 20000000; i++) {
}
result = 1;
isTaskRunnig = false;
} catch (Exception e) {
e.printStackTrace();
result = 0;
}
Message msg = new Message();
msg.what = result;
handler.sendMessage(msg);
};
};
thread.start();
}
// handler to update the progress dialgo while the background task is in
// progress
private static Handler handler = new Handler() {
public void handleMessage(Message msg) {
Log.d(TAG, "handleMessage");
int result = msg.what;
if (result == 1) {// if the task is completed successfully
Log.d(TAG, "Task complete");
try {
progressDialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
isTaskRunnig = true;
}
}
}
};
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, "onRestoreInstanceState" + isTaskRunnig);
if (isTaskRunnig) {
perform();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "onSaveInstanceState");
if (thread.isAlive()) {
thread.interrupt();
Log.d(TAG, thread.isAlive() + "");
progressDialog.dismiss();
}
}
As pointed out by Yalla T it is important to not recreate the fragment. The EditText will not lose its content if the existing fragment is reused.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_frame);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Display the fragment as the main content.
// Do not do this. It will recreate the fragment on orientation change!
// getSupportFragmentManager().beginTransaction().replace(android.R.id.content, new Fragment_Places()).commit();
// Instead do this
String fragTag = "fragUniqueName";
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = (Fragment) fm.findFragmentByTag(fragTag);
if (fragment == null)
fragment = new Fragment_XXX(); // Here your fragment
FragmentTransaction ft = fm.beginTransaction();
// ft.setCustomAnimations(R.xml.anim_slide_in_from_right, R.xml.anim_slide_out_left,
// R.xml.anim_slide_in_from_left, R.xml.anim_slide_out_right);
ft.replace(android.R.id.content, fragment, fragTag);
// ft.addToBackStack(null); // Depends on what you want to do with your back button
ft.commit();
}
Saving state = Saving (Fragment State + Activity State)
When it comes to saving the state of a Fragment during orientation change, I usually do this way.
1) Fragment State:
Save and Restore EditText value
// Saving State
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("USER_NAME", username.getText().toString());
outState.putString("PASSWORD", password.getText().toString());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.user_name_fragment, parent, false);
username = (EditText) view.findViewById(R.id.username);
password = (EditText) view.findViewById(R.id.password);
// Retriving value
if (savedInstanceState != null) {
username.setText(savedInstanceState.getString("USER_NAME"));
password.setText(savedInstanceState.getString("PASSWORD"));
}
return view;
}
2) Activity State::
Create a new Instance when the activity launches for the first time
else find the old fragment using a TAG and the FragmentManager
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
fragmentManager = getSupportFragmentManager();
if(savedInstanceState==null) {
userFragment = UserNameFragment.newInstance();
fragmentManager.beginTransaction().add(R.id.profile, userFragment, "TAG").commit();
}
else {
userFragment = fragmentManager.findFragmentByTag("TAG");
}
}
You can see the the full working code HERE
Below code is work for me. Need to care two things.
Each Input Field (Edit Text or TextInputEditText) assign unique id.
Manifest activity declaration should have on configuration change attribute with below values.
android:configChanges="orientation|keyboardHidden|screenSize"
Sample activity declaration in manifest.
<activity
android:name=".screens.register.RegisterActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true"
android:label="Registration"
android:theme="#style/AppTheme.NoActionBar" />
Sample declaration of
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/inputLayout"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:boxCornerRadiusBottomEnd="#dimen/boxCornerRadiusDP"
app:boxCornerRadiusBottomStart="#dimen/boxCornerRadiusDP"
app:boxCornerRadiusTopEnd="#dimen/boxCornerRadiusDP"
app:boxCornerRadiusTopStart="#dimen/boxCornerRadiusDP">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/inputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:fontFamily="#font/proxima_nova_semi_bold"
android:inputType="textCapWords"
android:lines="1"
android:textColor="#color/colorInputText"
android:textColorHint="#color/colorInputText" />
</com.google.android.material.textfield.TextInputLayout>
this may help you
if your android:targetSdkVersion="12" or less
android:configChanges="orientation|keyboardHidden">
if your android:targetSdkVersion="13" or more
android:configChanges="orientation|keyboardHidden|screenSize">

Categories

Resources