Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update a TextView of an Activity from another class

Tags:

java

android

I am new to Android/Java programming. I have two classes, one is an Activity and the other is a normal class. My activity class contains a TextView. Can I update the TextView of the activity class from a normal class? I tried with random code, but it fails.

// activity class
public class MainMenu extends Activity {
    public TextView txtView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView txtView = (TextView)findViewById(R.id.text);   
    }
}

// Other class
public class ClassB {
    public ClassB() {
        public void Update() {
            TextView txtView = (TextView)findViewById(R.id.text);
            txtView.setText("Hello");
        }
    }
}
like image 772
Riskhan Avatar asked Jun 12 '12 12:06

Riskhan


People also ask

How do I update TextView?

If you have a new text to set to the TextView , just call textView. setText(newText) , where newText is the updated text. Call this method whenever newText has changed.

How pass TextView value to another activity in android?

Using Static methods Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main. xml. Step 4 − Add the following code to res/layout/activity_second.

How do you create a TextView control in an activity file?

Modify src/MainActivity. java file to add necessary code . Modify the default content of res/layout/activity_main. xml file to include Android UI control.

How can I access TextView activity?

Following is another way to set the text of textview control programmatically in activity file using setText() method. TextView tv = (TextView)findViewById(R. id. textView1);


3 Answers

You have to pass the Context reference via constructor.

public class ClassB {    Context context;    public ClassB(Context context){      this.context=context;    }     public void Update(){         TextView txtView = (TextView) ((Activity)context).findViewById(R.id.text);         txtView.setText("Hello");    } 
like image 181
KV Prajapati Avatar answered Sep 30 '22 10:09

KV Prajapati


The preceding two examples require TextView to be used directly within the other class. However, there are cases where TextView shouldn't be present in the other class, e.g., your ClassB is used to update various Activities, where some activities update TextViews, and others might update EditTexts.

Hence, the below solution can guide you on how you could decouple your TextView from other classes, yet, you could still achieve what you want. It's using the interface approach.

Firstly, declare an interface where you could have ClassB communicate to the Activity, and call it MyCallback:

public interface MyCallback {
    // Declaration of the template function for the interface
    public void updateMyText(String myString);
}

Next in your Activity, implement MyCallback, and hence its function definition. In this function, you will receive the String from ClassB that you could do whatever you like, e.g., update the TextView (or EditText, etc.):

public class MyActivity extends AppCompatActivity implements MyCallback {
    // ... whatever code of your activity

    @Override
    public void updateMyText(String myString) {
        ((TextView)findViewById(R.id.text)).setText(myString);
    }
}

Lastly, you could declare ClassB that takes in MyCallback (i.e., your Activity class object that is also a MyCallback). From there you could use ClassB to communicate back to Activity and get it to update its TextView through the updateMyText function:

public class ClassB {
    MyCallback myCallback = null;

    public ClassB(MyCallback callback) {
        this.myCallback = callback;
    }

    public void doSomething() {
        // Do something to get String
        String myString = str;

        if (myCallback != null) {
            myCallback.updateMyText(myString);
        }
    }
}

Hope this helps better show the architected structure of decoupling the Activity properly from ClassB.

like image 41
Elye Avatar answered Sep 30 '22 09:09

Elye


This is actually a deceptively "simple" question, but in reality a complicated problem in the context of Android development.

Activities are the "process entry point", meaning that any Activity you see can act as the "first point of entry to your application on start-up". People think that only the Activity that has the MAIN/LAUNCHER intent filter can be launched at start-up, but this is false.

Any Activity can act as the "first Activity", because Android can restart it from any point with the current active navigation stack.

Anyways, with that in mind, an Activity can show a View, and people often use the Activity to hold each screen of their app (instead of using it as an entry point, and swapping out view controllers in it ~ fragments).

So if you have multiple Activities, then you need to share data between them in such a way, that you take it into consideration that both activities can be started up at any time as the first Activity of the app.


For this, what you need to do is not "set the text view's text directly from another class", but you need to modify observable shared data.

The newly released official Android Architecture Components provide the LiveData<T> class, which has a subclass called MutableLiveData<T>.

To update the data from one class to another Activity, what you must do is have a global data exposed as a LiveData

public class MyApplication extends Application {
    private static MyApplication INSTANCE;

    DataRepository dataRepository; // this is YOUR class

    @Override
    public void onCreate() {
        super.onCreate();
        INSTANCE = this;
        dataRepository = new DataRepository();
    }

    public static MyApplication get() {
        return INSTANCE;
    }
}

The DataRepository should expose LiveData:

public class DataRepository {
    private final MutableLiveData<MyData> data = new MutableLiveData<>();

    public LiveData<MyData> getMyData() {
        return data;
    }

    public void updateText(String text) {
        MyData newData = data.getValue()
                             .toBuilder() // immutable new copy
                             .setText(text)
                             .build();
        data.setValue(newData);
    }
}

Where the Activity subscribes to this:

public class MyActivity extends BaseActivity {
    DataRepository dataRepository;

    TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyApplication app = (MyApplication)getApplicationContext();
        dataRepository = app.getDataRepository();

        setContentView(R.layout.main_activity);
        textView = findViewById(R.id.textview);

        dataRepository.getMyData().observe(this, new Observer() {
            @Override
            public void onChange(MyObject myObject) {
                textView.setText(myObject.getText());
            }
        }
    }

So to update this text, you need to get the DataRepository class, and call updateText on it:

DataRepository dataRepository = MyApplication.get().dataRepository();
dataRepository.updateText("my new text");

And this will properly update your Activity text view.

Beware that you should also persist the data to onSaveInstanceState(Bundle so that it is not lost (assuming the data is not from disk).

To do that, you need to do the following:

public class BaseActivity extends AppCompatActivity {
    DataRepository dataRepository;

    private static boolean didRestoreGlobals = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        MyApplication app = (MyApplication)getApplicationContext();
        dataRepository = app.getDataRepository();

        super.onCreate(savedInstanceState);
        if(!didRestoreGlobals) {
            didRestoreGlobals = true;
            if(savedInstanceState != null) {
                dataRepository.restoreState(savedInstanceState.getBundle("dataRepository"));
            }
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle bundle) {
        super.onSaveInstanceState(bundle);
        bundle.putBundle("dataRepository", dataRepository.saveState());
    }
}

And then add saveState/restoreState methods to DataRepository accordingly.

like image 23
EpicPandaForce Avatar answered Sep 30 '22 10:09

EpicPandaForce