TextView forgets its value after tab switching - android

I've setup a tabhHost in my program with 3 tabs each with a fragment in its content that contains a textView. I've set a button in app that is supposed to update the content of every tab. However the problem i am now facing is that if i change a tab its content gets forgotten and new tab has no value aswell unless i click the button again. Each tab content has a different class but in each of them the class just returns the view with textview in it. I assumed that the values reset on each view inflate however i cannot find a reasonable way to make it work as i intend to it.
Here is the part of the code with the method ran by my button:
public void getNum(View view) {
proteinNeeded = weightNum.getValue() * FirstActivity.weightMultiplier;
carbohydrateNeeded = weightNum.getValue() * 5;
switch (weightMultiplier) {
case 2: {
resultTxt = String.format("Zapotrzebowanie:%nBiałko - %dg.%nWęglowodany - %dg.%n",
FirstActivity.proteinNeeded, FirstActivity.carbohydrateNeeded);
FragmentTab.tv.setText(resultTxt);
FragmentTab2.dietTxt = String.format("text1");
FragmentTab2.tv.setText(FragmentTab2.dietTxt);
FragmentTab3.foodTxt = String.format("text2");
FragmentTab3.tv.setText(FragmentTab3.foodTxt);....
And here is the code from FragmentTab.java, each tab has more or less same code so i'll post only this one for now:
public class FragmentTab extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public static View v;
public static TextView tv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_layout, container, false);
tv = (TextView) v.findViewById(R.id.textResult);
if (tv != null) {
tv.setText("nothing has been input yet");
}
return v;
}
}
TL;DR - How do I save my values in textView in such a way that if my text gets updated it won't revert to default values after the view gets refreshed?

An option to solve your problem is to use SQLite Database to save your data, and fetch it from database whenever you return to that tab.
You can refer to this link. Saving Data in SQL Databases.
For other android storage options, refer to this series of videos. Android Data Storage Options.

Related

How to pass an ArrayList from a custom adapter to a fragment

I have a fragment created that, in turn, loads two tabs with separate fragments (students and questions). These two fragments are two ListViews: one with the student's name and a checkbox, and another with some questions.
What I want is to know which students from the ListView are checked. This I get easily with an ArrayList in the custom adapter. I called 'selectedStudents'.
But now I want to pass that ArrayList 'selectedStudents' with the students checked to the main fragment. But I can not do it.
This is my code:
MainClass:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listaAlumnos = (ListView)findViewById(R.id.listViewAlumnosF);
listaCuestiones = (ListView)findViewById(R.id.listViewCuestionesF);
//HERE I WANT TO READ THE ARRAYLIST WITH STUDENTS CHECKED
}
});
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main2, container, false);
return rootView;
}
My Student Fragment:
public class StudentsFragment extends Fragment {
ListView listStudentsF;
ArrayList<String> IdAlumnos = new ArrayList<String>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_alumnos, container, false);
listStudentsF = (ListView)v.findViewById(R.id.listStudentsF);
perform();
}
public void perform() {
myAdapterUsers myAdapterUsers = new myAdapterUsers(getActivity(), R.layout.list_item_alumnos, IdAlumnos);
listStudentsF.setAdapter(myAdapterUsers);
}
}
And my Custom Adapter (method getView):
#Override
public View getView(final int position, View convertView, ViewGroup viewGroup) {
View v = convertView;
LayoutInflater layoutInflater = LayoutInflater.from(this.contextM);
v = layoutInflater.inflate(R.layout.list_item_alumnos, null);
final String currentIdAlumnos = IdAlumnos.get(position);
final CheckBox checkBox = v.findViewById(R.id.checkBox2);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
//Comprueba si está checkeado el registro y lo añade o quita a un ArrayList de usuarios seleccionados.
if (isChecked){
selectedStudents.add(currentIdAlumnos);
}else {
selectedStudents.remove(currentIdAlumnos);
}
Log.e("SELEC: ", String.valueOf(selectedStudents));
}
});
return v;
}
I have try create a method in adapter like:
public ArrayList<String> getArrayList() {
return selectedStudents;
}
And called from outer Activity, but don't work.
Let's start by saying that communication between fragments should be done using the parent activity, an interface, and some glue code. This has been asked multiple times, and it's also A google documentation section.
With all that being said, what I would do in your case, is separate the data from the views.
Your list of selected students, should not live or be modified in the activity or fragment.
Your Activity (and its fragments) are merely containers and policy delegates (if I may use Google's terminology) for what Android as a framework offers. You cannot have an Android app without them (at least an app that displays a UI), so you must have them around. But that doesn't mean all your code should live there.
Far from it. Activities and Fragments are complicated on their own (they have a lot of things to do), so instead...
Your Fragment should "ask for its data" to display the list, and push the changes to a place (let's call it repository), so once the user taps an "Alumno" from the list, the list tells the repo: "hey, this Alumno is selected".
The Repository will receive this information, filter the results and publish them.
On the other end, the Other fragment (the one interested in the selected Alumnos), will listen for these changes and will be told what to display.
Think of it as:
FragmentOther starts and asks the repo: "give me the data to display"
Repository will reply: Here's the list of Alumnos.
If the user changes the selection (in the students fragment), it will do what it did before, tell the repo: hey, here's the selected students again, they changed.
The repo will filter the question list again, and offer it to anyone interested.
If FragmentOther (questions) is open, it will receive it, if not, once it's opened, it will ask for the current list, and the repo will return it then.
So you see, the key in all this is the infamous separation of concerns.
Each class/object must have the least amount of responsibilities and be as reusable as possible.
For achieving all this using modern Android practices, I recommend you spend time learning:
LiveData, The Repository Pattern, and LifeCycle for example.
All these are part of Android Jetpack.

Xamarin FindViewById NullReference Exception

I have a problem, whenever i try to add an eventhandler to a button i get a null reference exception, i am trying to create a popup window with a DialogFragment, where inside it im calling the view PopUpWindow wich will show up on screen, but when i try to access the buttons by id and to assign them eventhandlers for example:
Button btnCopyText = dp.view.FindViewById<Button>(Resource.Id.btnCopyText);
btnCopyText.Click += BtnCopyText_Click;
then i get a null reference exception, can anyone help me, below is the necessary code.
class dialog_Popup:DialogFragment
{
public View view;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
view = inflater.Inflate(Resource.Layout.PopupWindow, container, false);
return view;
}
public override void OnActivityCreated(Bundle savedInstanceState)
{
Dialog.Window.RequestFeature(WindowFeatures.NoTitle);
base.OnActivityCreated(savedInstanceState);
}
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
//some code
}
public string itemclicked;
dialog_Popup dp;
private void Lv_ItemLongClick(object sender, AdapterView.ItemLongClickEventArgs e)
{
//View popUpView = LayoutInflater.Inflate(Resource.Layout.PopupWindow,
//null); // inflating popup layout
Button height = FindViewById<Button>(Resource.Id.btnCopyText);
//Then: change the width of the button
FragmentTransaction transaction = FragmentManager.BeginTransaction();
dp = new dialog_Popup();
dp.Show(transaction,"Popup");
itemclicked = lv.GetItemAtPosition(e.Position).ToString();
Button btnCopyText = dp.view.FindViewById<Button>(Resource.Id.btnCopyText);
btnCopyText.Click += BtnCopyText_Click;
Button btnSaveCurrentAya = dp.view.FindViewById<Button>(Resource.Id.btnSaveCurrentAya);
btnSaveCurrentAya.Click += BtnSaveCurrentAya_Click;
Button btnsavingsAya = dp.view.FindViewById<Button>(Resource.Id.savingsAya);
btnsavingsAya.Click += BtnsavingsAya_Click;*
Button btnShareFB = dp.view.FindViewById<Button>(Resource.Id.fbShare);
btnShareFB.Click += BtnShareFB_Click;
}
}
There are several reasons why a NullReferenceException can occur with FindViewById:
The layout does not contain the id -> check that the correct layout and id is inflated/ referenced
The type like Button is incorrect
In your case, check that dp and dp.view is not null.
One thing to mention here is, that it is not the best implementation to reference the control of a fragment in you main view. A fragment is something that should be able to life on her own. So I see two ways of implementing your desired behavior:
1) The fragment gets an event and you listen to that. This means your main view will contain the logic to save something.
2) The logic moves into the fragment.

Fragment with button clicks

Since, i am new to android, i am trying to learn fragments and how they work.I tried to make a length converter app which basically converts meter to centimeters.Simple, right?
Now I have two portions of the activity,one being the two edittexts which are the part of the activity layout, while the other one being the fragment.
This fragment basically contains keypad, in short, Numbers and operators displayed on it. Like a normal calci would have.
Now i read about the fragment life cycle and how it is supposed to work.
So The first thing that i did was to put everything in onCreateView method.
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
getRootView=inflater.inflate(R.layout.calci_keyboard,container,false);
GridLayout gridLayout=(GridLayout) getRootView.findViewById(R.id.calciKeyboardGrid);
for(int i=0;i<gridLayout.getChildCount();i++){
b=(Button)gridLayout.getChildAt(i);
b.setBackground(getResources().getDrawable(R.drawable.button_dark_gradient));
b.setOnClickListener(this);
}
return getRootView;
}
The thing is that, click events work but edittext settext doesn't seem to work. Edittexts are behaving weirdly.
Now, to remove that i thought i am accessing the Activity UI's , so i should do this inside onActivityCreated function ,So, i tried this too.
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
getRootView=inflater.inflate(R.layout.calci_keyboard,container,false);
return getRootView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
#SuppressLint("InflateParams") View getView=(GridLayout) LayoutInflater.from(getActivity()).inflate(R.layout.calci_keyboard,null,false);
GridLayout gridLayout=(GridLayout) getView.findViewById(R.id.calciKeyboardGrid); // i Logged this obj and it was there
for(int i=0;i<gridLayout.getChildCount();i++){
b=(Button)gridLayout.getChildAt(i);
b.setBackground(getResources().getDrawable(R.drawable.button_dark_gradient));
b.setOnClickListener(this);
}
}
When i do things this way i don't seem to get my clicks working?
How am i supposed to do this problem? Can't find any solution.
Go easy on me,Thanks :)
Below one shows my onClick event:.
public void onClick(View view) {
View focussedChild=getActivity().getCurrentFocus();
switch (view.getId()){
case R.id.calciKeyboardNine:{
if (focussedChild instanceof EditText) {
firstPart=new StringBuilder("");
secondPart=new StringBuilder("");
EditText editText=(EditText)focussedChild;
if(focussedChild.getId()==R.id.lengthConverterFirst){
if(!TextUtils.isEmpty(firstPart.toString()))
firstPart.replace(0,firstPart.length()-1,editText.getText().toString()+"9");
firstPart.append("9");
editText.setText(firstPart.toString());
editText.setSelection(editText.length());
int a=Integer.parseInt(firstPart.toString());
a=a*100;
editText=getActivity().findViewById(R.id.lengthConverterSecond);//second edit text
editText.setText(Integer.toString(a));
editText.setSelection(editText.length());
}else if(focussedChild.getId()==R.id.lengthConverterSecond){
if(!TextUtils.isEmpty(secondPart.toString()))
secondPart.replace(0,secondPart.length()-1,editText.getText().toString()+"9");
secondPart.append("9");
editText.setText(secondPart.toString());
editText.setSelection(editText.length());
double a=Integer.parseInt(firstPart.toString());
a=a/100;
editText=getActivity().findViewById(R.id.lengthConverterFirst);//first edit text
editText.setText(Double.toString(a));
editText.setSelection(editText.length());
}
}
}
}
}
Now, to remove that i thought i am accessing the Activity UI's , so i should do this inside onActivityCreated function ,So, i tried this too - it didn't work because onActivityCreated() is method of fragment not activity.
try this - just make your edittexts static in activity and then you can access them in fragment by the activity's name like MainActivity.editText(). hope this helps

Urbanairship - In-App message customization

I already know that we have a configuration section in UrbanAirship site (Configuration -> In-App Messages) and read http://docs.urbanairship.com/platform/android.html#custom-style. But with this I can't change all the In-App layout.
In Sum:
How I can change the style for button (apply border, changing
background color just for the button, color to the text button ...)?
Base.Widget.UrbanAirship.InAppMessage.Banner.ActionButton
How I can hide the divider between the button and notification description?
Base.Widget.UrbanAirship.InAppMessage.Banner.Divider
Layout adjustments take a little bit more work but can be done. First you will need to create a custom InAppMessageFragment:
public class CustomInAppMessageFragment extends InAppMessageFragment {
#Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
if (getMessage() == null || getMessage().getAlert() == null) {
dismiss(false);
return null;
}
// Bind the in-app message to the layout. The fragment is attached to the content of the activity,
// so it has the full activity width and height to work with.
TextView view = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, container, false);
view.setText(getMessage().getAlert());
return view;
}
}
Then set the fragment factory on the in-app message manager after takeOff:
airship.getInAppMessageManager().setFragmentFactory(new InAppMessageFragmentFactory() {
#Override
public InAppMessageFragment createFragment(InAppMessage message) {
return new CustomInAppMessageFragment();
}
});
Take a look at the source to see how the in-app message fragment's view is normally created.

EditText Values in Android Fragment do not refresh

I'm using the Viewpager to switch between 3 fragments, everything is working fine, except the refreshing of the second tab (or fragment). In this tab, I have a picture, some static Textviews, some dynamic TextViews and some EditText fields.
Everytime the second tab is selected, there will be called setText() on all dynamic fields. TextView components and the spinner are refreshing and updating their contents, but EditText elements do not.
I don’t understand why these fields are not updating. After tab change, I call notifiyDataSetChanged() in TabsAdapter. It calls onViewCreated() everytime I change the tab. In onViewCreated() of the second fragment I am changing the contents of the elements.
That’s the code of my fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
hA = (HelloAndroidActivity)this.getSherlockActivity();
appState = ((TestApplication)this.getSherlockActivity().getApplicationContext());
final PersistenceHelper pH = new PersistenceHelper(appState);
m = pH.readMitarbeiter(toDisplay);
// Inflate the layout for this fragment
v = inflater.inflate(R.layout.detailfragment, container, false);
if(m==null) {
//If Mitarbeiter is empty
pH.closeDB();
return v;
}
//Inflating Elements
employeeName = (TextView)v.findViewById(R.id.employee_name);
cDate = (TextView)v.findViewById(R.id.department);
currentPlace = (TextView)v.findViewById(R.id.place_label);
comment_text = (EditText)v.findViewById(R.id.comment_text);
reachable = (EditText)v.findViewById(R.id.reachable_text);
state = (Spinner)v.findViewById(R.id.spinner_state);
durchwahl = (EditText)v.findViewById(R.id.durchwahl);
department = (EditText)v.findViewById(R.id.department_edit);
email = (EditText)v.findViewById(R.id.email_edit);
img = (ImageView)v.findViewById(R.id.userPic);
changeData = (Button)v.findViewById(R.id.changeButton);
//Setting Elements
employeeName.setText(m.getL_name());
currentPlace.setText(m.getStatus());
comment_text.setText(m.getBemerkung());
reachable.setText(m.getErreichbar());
email.setText(m.getS_name()+"");
durchwahl.setText(m.getDurchwahl()+"",TextView.BufferType.EDITABLE);
department.setText(m.getFunktion(),TextView.BufferType.NORMAL);
//Spinner
String[] values = { "Anwesend", "Mittagspause" , "Ausser Haus" , "Dienstreise", "Krankenstand" ,"Zeitausgleich", "Urlaub","Abwesend" };
ArrayAdapter spinnerArrayAdapter = new ArrayAdapter(this.getSherlockActivity(), android.R.layout.simple_spinner_item,values);
state.setAdapter(spinnerArrayAdapter);
state.setSelection(StateMapper.returnState(m.getStatus()));
//Image
//.......
return v;
}
As I mentioned before, my Image, TextView and Spinner Elements are refreshing their content. I also checked the content of all variables, everything seems to be fine, except these EditText elements. If I cast the EditText elements into TextView, the content is changing (in code but not in the GUI). What also makes me desperate is, that the EditText refreshes the first time I set the value.
Has anybody an idea, how I’m able to refresh the content of my EditText fields?
i am not sure but try onResume() and set your text in resume state.
or try
Intent.FLAG_ACTIVITY_CLEAR_TOP on tab change.
You could also try posting a runnable to the message queue so that the EditText's are updated after rendering (in MonoDroid/C#, see How to run a Runnable thread in Android? for java):
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle)
{
EditText et = FindViewById<EditText>(...);
et.Post(() => { et.Text = "content"; });
}
Also, if you have a TextChanged event handler (say for displaying a save icon/button when the text is changed), post it in the runnable as well, and do it after the et.Text assignment. Otherwise, the TextChanged event will fire when the initial et.Text content is assigned, causing the TextChanged event to fire (ie, and the save button showing) when the USER hasn't changed anything:
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle)
{
EditText et = FindViewById<EditText>(...);
et.Post(() =>
{
et.Text = "content";
et.TextChanged += TextChangedHandler;
});
}
private void TextChangedHandler(object o, EventArgs args)
{
ShowSaveButton();
}
I came across this issue in 2021. I just had to call findViewById again right before setting the text.
myEditText = (EditText)view.findViewById(R.id.myEditText);
myEditText.setText(String.valueOf(newValue));

Categories

Resources