Change TextView String Resource in multiple activities - android

I have a bunch of TextViews within different activities in my app that show some string.
I wanted to add an option somewhere, where if you check it (or press it, whatever) those textviews will use some other string.
I though I could do it with having a second res value strings, and the app will switch between the two. But I see those are for localizing and do not use any user input.

Your requirement seems like you need DataBinding. You can create a Model call lets say StringManager
public class StringManager {
private final String str;
private final String str2;
private final String str3;
public StringManager(String str1,String str2, String str3){
//Initialize all class variables here
}
//Create getter methods for all
}
In your main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="stringManager " type="com.example.StringManager "/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{stringManager.str1}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{stringManager.str2}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{stringManager.str3}"/>
<Button
android:id="#+id/btnClickMe"
android:text="Click me"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="clicked"/>
</LinearLayout>
</layout>
In your MainActivity.java
public class MainActivity extends AppCompatActivity{
private MainActivityBinding binding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
StringManager stringManager = new StringManager("strA", "StrB", "StrC");
binding.setStringManager(stringManager);
}
public void clicked(View v){
StringManager stringManager = new StringManager("strD", "StrE", "StrF");
binding.setStringManager(stringManager);
}
}
You can find the official tutorial here.

Due to there is no specific piece of code in the answer I will just sketch out my solution as pseudo code.
This solution is based on the onResume callback which is getting called as soon as an activity is getting active and the SharedPreferences class. As well it is important to know that only one activity will be active at once.
Initialize a variable as SharedPreference with the default string resource
User input changes that exact variable which is stored as
SharedPreference instead of the TextView's text itself. The nature of a SharedPreference will make it so that every button in every activity references the same variable. The second string resource can be used as source here.
The TextView's text is getting updated by using the SharedReference variable only.
In case of a new activity becoming active onCreate can be used to update the TextView's text by using the SharedReference variable.
In case of an other already initialized activity becoming active onResume can be used to update the TextView's text by using the SharedPreference variable

Related

How to setText to a TextView in a different Activity [duplicate]

This question already has answers here:
What's the best way to share data between activities?
(14 answers)
Closed 4 years ago.
So what I am trying to make happen is when you check this checkBoxA, some text will appear in a different TextView in a different Activity that the user will reach later on. The app is kind of like a quiz app so this off the text being displaid like the final score or something.
At first I tried this:
if (checkBoxA.isChecked()){
systemView.setText("Business");
}
But then I got a nullPointerException cause the "systemView" is not in the same activity. The activity is extended to the other activity that the "systemView" is located. So I am not really sure whats wrong anyone know what I should do?
Your issue is that even though you can get the ID of the systemView TextView by using R.id.systemView when you try to find that view using findViewById(R.id.systemView) the view cannot be found as it is not in the current activity's list of ViewGroup. As such null is returned.
Note systemView as the id given to the TextView has been assumed.
That is, You can only successfully use findViewById to find views within the current ViewGroup (e.g. for this.FindyViewById the layout as set by setContentView).
Instead you need to make the value available to the other activity and then retrieve the value in the other activity.
There are various ways that you can make the value available, some options are :-
To pass it to the activity via the Intent that starts the other activity as an intent extra, you could store the value in shared preferences and then retrieve it in the other activity or you could store the value in a database, e.g. SQLite and retrieve it.
Using an IntentExtra is ideal if you are directly starting the other activity with a limited number of values.
using chained Intent Extras is also feasible (that is passing to one activity, then to another and so on).
Shared preferences could suit a situation where there are a limited number of values to be passed and the other activity isn't directly started from the activity.
A database would suit a situation where there is a fair amount of structured data and/or related data (or if you are using a database for other aspects).
An example of using an Intent could be :-
In the Activity that is passing the value
Intent i = new Intent(this, yourOtherActivity.class);
i.putExtra("YOURINTENTEXTRAKEY","Business"); //<<<< 1st parameter is a Key for identification, the 2nd parameter is the value to be passed
startActivity(i);
In the other Activity's onCreate (after you've set the contentView)
TextView mSystemView = this.find(R.id.systemView);
if (this.getIntent().getStringExtra("YOURINTENTEXTRAKEY") != null) {
mSystemView.setText(this.getItent().getStringExtra("YOURINTENTEXTRAKEY"));
} else {
mSystemView.setText("NO VALUE PASSED");
}
You set pass and return multiple IntentExtras see Intent for various options and types of values that can be passed/retrieved.
Simple Working Example
The following is code for a working example. The first activity (MainActivity) has a CheckBox and a Button.
The Button can be clicked or longClicked. If the latter then nothing is passed to the second activity. If the former then depedning upon whether or not the CheckBox is ticked will either pass "Not Checked" or "Business".
The second activity, if passed a value (either "Not Checked" or "Business") will display the passed value, if nothing is passed then it will display "NOTHING PASSED". The button on the second activity will return to the first activity (alternately using the back button will return to the first activity).
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String INTENTKEY_CHECKBOXA = "checkboxa";
CheckBox checkBoxA;
Button nextActivity;
String valueToPass = "Not Checked";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkBoxA = this.findViewById(R.id.checkBoxA);
checkBoxA.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (checkBoxA.isChecked()) {
valueToPass = "Business";
} else {
valueToPass = "Not Checked";
}
}
});
nextActivity = this.findViewById(R.id.nextActivity);
//Set onlick listener (pass value via intent)
nextActivity.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
callNextActivity(true);
}
});
// Set onlongclick listener (doesn't pass value via intent)
nextActivity.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
callNextActivity(false);
return true;
}
});
}
private void callNextActivity(boolean passvalue) {
Intent i = new Intent(this,NextActivity.class);
if (passvalue) {
i.putExtra(INTENTKEY_CHECKBOXA, valueToPass);
}
startActivity(i);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<Button
android:id="#+id/nextActivity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="NEXT ACTIVITY"/>
<CheckBox
android:id="#+id/checkBoxA"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
NextActivity.java
public class NextActivity extends AppCompatActivity {
Button doneButton;
TextView systemView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
systemView = this.findViewById(R.id.sysstemView);
doneButton = this.findViewById(R.id.done);
if (this.getIntent().getStringExtra(MainActivity.INTENTKEY_CHECKBOXA) != null) {
systemView.setText(this.getIntent().getStringExtra(MainActivity.INTENTKEY_CHECKBOXA));
} else {
systemView.setText("NOTHING PASSED");
}
doneButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
doneWithActivity();
}
});
}
// Return from this activity
private void doneWithActivity() {
this.finish();
}
}
activity_next.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NextActivity">
<Button
android:id="#+id/done"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DONE"/>
<TextView
android:id="#+id/sysstemView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
you can pass your text in the intents of navigations between the activities .. otherwise if you want to save your text to recover it later, even if you close and restart your application, you can save it in a shared preferences file, to retrieve it from this file when you want to display it later.. but you can not set a text to a textview of an activity that is not in foreground.
There are many ways to do this depending on your exact use case one may be better suited than the others.
You can wrap the data in a bundle and pass it to your other activity through an intent if you are opening a second activity
Or you could store the values (in shared prefs or sqlite) and then retrieve them in the next activity.
You could use RxJava to create a stream via a subject (bevahior subject most likely in this case) and write to the stream in the first activity, then subscribe on the stream in the next to get the values.
If you are using an intent to go to the next activity you could put the value in a string and pass the string as an extra to the intent. Take the value in the next activity and set the text view.
//First Activty
String valueToPass = "";
if (checkBoxA.isChecked()){
valueToPass = "Business";
}
startActivity(new Intent(CurrentActivity.this, NextActivity.class).putExtra("value", valueToPass));
//Second Activity
if(getIntent().getString("value") != null)){
systemView.setText(getIntent().getString("value"));
}
Just use SharedPreferences to save the TextView value and then when go to the Activity that contain the TextView get the saved value and set it to the TextView in the onCreate method

Remove the duplicate in modal and view

I am writing an app involve a class.
class User {
private String name;
private String school;
private String sex;
//other attributes
}
and need an Activity to show the User info.
class ShowActivity {
public void onCreate() {
setContentView(R.layout.activity_show);
}
}
the activity_show layout like this
<LinearLayout>
<Text
android:id="#+id/tx_name"
/>
<Text
android:id="#+id/tx_school"
/>
<Text
android:id="#+id/tx_sex"
/>
I also have another activity to modify the user.
class EditActivity {
public void onCreate() {
setContentView(R.layout.activity_edit);
}
}
and the layout file
<LinearLayout>
<EditText
android:id="#+id/et_name"
/>
<EditText
android:id="#+id/et_school"
/>
<EditText
android:id="#+id/et_sex"
/>
You can see that. For every attribute of User, there are three places about it
1. one field of the User class
2. one view that have the meaningful id in activity_show layout
3. one view that have the meaningful id in activity_edit layout
If i want to modify the name of one field in User, for example
String name -> String nickname;
In order to keep consistent, I have to modify the id in layout
et_name -> et_nickname;
This is annoying. Everytime I change one place, I have to change another two place.
How can I avoid that?

RoboBinding how does ViewModel know variable to return

Lets examine a simple example from here:
Here is a simple layout file with a textview binding:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:bind="http://robobinding.org/android">
<TextView
bind:text="{hello}" />
...
<Button
android:text="Say Hello"
bind:onClick="sayHello"/>
and here is the view model for this layout:
#org.robobinding.annotation.PresentationModel
public class PresentationModel implements HasPresentationModelChangeSupport {
private String name;//how does framework now what to set name to ?
public String getHello() {
return name + ": hello Android MVVM(Presentation Model)!";
}
...
public void sayHello() {
firePropertyChange("hello");
}
}
my question is how does the viewModel know what name is ? it has not been set anywhere ? What if i had many variables like name2,name3 etc. how would it know what to bind ?
You should take a look to the entire source code
MVVM example
There is a getter and a setter in the presentation model class that manage the value of the name field with the two ways binding specified in the layout
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
bind:text="${name}"/>
If you have more variables you must provide a getter and setter for each one if you want to use two way binding.

Where to save checkbox selected contacts in ListActivity?

I am using a custom List adapter to display a list of all contacts, and the user will then select contacts by clicking a checkbox. What is a good method of saving the selected contacts to preferences, so that I may test against them elsewhere? I was thinking of using SharedPreferences, but so far I have been unable to find a way to save an array to SharedPrefs. I could go the sqlite route, but that seems a bit excessive considering they are already contained in a db, and why couldn't I just reference them there. Just not sure how to even begin to do that...
Also, I was thinking of calling this method onDestroy, though that could have some issues as well, so a recommendation on that could help as well. Here is some code (let me know if you need more,,,there's always more)
thanks for your supreme knowledge.
ListItemLayout.xml:
<?xml version="1.0" encoding="utf-8"?>
<TwoLineListItem
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:id="#+id/relativelayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="#android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:id="#android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#android:id/text1"
android:includeFontPadding="false"
android:paddingBottom="4dip"
android:textSize="15sp"
android:textStyle="normal" />
<CheckBox
android:id="#+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:focusable="false"
/>
</RelativeLayout>
</TwoLineListItem>
ContactPicker Activity (some code redacted for brevity's sake):
public class ContactPicker extends ListActivity implements Runnable{
private List<Contact> contacts = null;
private Contact con;
private ContactArrayAdapter cAdapter;
private ProgressDialog prog = null;
private Context thisContext = this;
private CheckBox c1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prog = ProgressDialog.show(this, "Contact List", "Getting Contacts", true, false);
Thread thread = new Thread(this);
thread.start();
final CheckBox c1 = (CheckBox)findViewById(R.id.checkbox);
}
public void run() {...
}
private List<Contact> fillContactsList() {...
}
private Handler handler = new Handler() {...
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
TextView label = ((TwoLineListItem) v).getText2();
String phoneNumber = label.getText().toString();
}
}
If all you need is to store a list of objects (users) I would skip the DB and just create a JSON object and store that as a String in a shared preference. It obviously depends on how many users you expect to store, but if it's a few hundred or less, you're not going to see any sort of performance loss, and you can avoid dealing with all the db setup.
Yea, you're best route is to use a sql database. You only really have two options for persistent data storage in android: sqlite and shared preferences*. Since you want to actually store something more complicated a single key value pair, your best bet is to go with a sqlite database. As far as when to store the data, I would just trigger a store each time an item is checked or unchecked individually using an OnCheckChangedListener.
*Yes, there are other options, but those are the only semi-easy ones to use.

Common buttons onClick for every activity in android

My layout contain one header in which i inculded in each Activity, in this header there is a image button. Is it possible to write a common onClick event for this imageButton??
You can write a class that extends OnClickListener and the onClick method. Then in each activity's onCreate method, find the ImageButton and set its onClickListener to that class:
MyOnclickListener implements OnClickListener {
private Context context;
public MyOnclickListener(Context context) {
this.context = context;
}
#Override
public void onClick(View arg0) {
Intent intent = new Intent(context, MyActivity.class);
context.startActivity(intent);
}
}
In your activities:
protected void onCreate(...) {
setContentView(...);
((ImageButton) findViewById(R.id.mybutton)).setOnClickListener(new MyOnclickListener(this));
}
EDIT: Sorry, of course implements.
EDIT2: See updated code for Context reference.
Yes. Create a singleton class that implements the required listener and add that instance to the button on each screen.
The answers provided by cant0na and Juhani are most likely the answers you are looking for (with a small note on cant0na's answer). If you need a more self-maintained and fault tolerant solution you can define your very own "widget" which handles its own events. For this you'll need:
A xml-layout file which will describe your header.
A custom class which will (automatically) inflate the above XML layout and manage any "common events".
The benefit of this solution is that you don't have to add a new instance of your common OnClickListener in each and every activity which will show your header. You simply add your header to your activitys layout-XML (see example code below) and nothing else. Foolproof. You also get a more "decoupled" code this way (your header doesn't depend on any implementation specifics of your application and its activities).
The drawback is that it's a more complex solution and it might seem a bit over-kill for small projects. It's also a bit tricky to keep this solution "decoupled" if you want to do any activity specific actions on the button click. You might want to consider "default behaviour" in combination with "code injection" in the MyHeader class. The code injection would then require further manipulation on the header class (inject the onClick implementation) in the activities which deviates from the default behaviour.
Example header.xml
<com.dbm.widget.MyHeader
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:layout_width="60dp"
android:layout_height="20dp"
android:src="#drawable/myIcon"
android:id="#+id/myButton" />
</com.dbm.widget.MyHeader>
Example MyHeader.java
package com.dbm.widget;
public class MyHeader extends LinearLayout implements OnClickListener {
// Constructor.
public MyButton() {
((ImageButton) findViewById(R.id.myButton)).setOnClickListener(this);
}
// OnClick event callback.
public void onClick(View view) {
// Do whatever you need to do here.
}
}
Example activity.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.dbm.MyHeader
android:layout_width="match_parent"
android:layout_height="20dp" />
<!-- Your other content goes here -->
</LinearLayout>

Categories

Resources