![](/img/trans.png)
[英]Two options to update a TextView of an Activity from another class via TimerTask
[英]How to update a TextView of an Activity from another class
我是 Android/Java 编程的新手。 我有两个类,一个是Activity
,另一个是普通类。 我的活动类包含一个TextView
。 我可以从普通类更新活动类的TextView
吗? 我尝试使用随机代码,但失败了。
// 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");
}
}
}
您必须通过构造函数传递 Context 引用。
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");
}
前两个示例要求直接在另一个类中使用TextView
。 但是,在某些情况下TextView
不应该出现在另一个类中,例如,您的ClassB
用于更新各种活动,其中一些活动更新TextView
,而其他活动可能更新EditText
。
因此,下面的解决方案可以指导您如何将TextView
与其他类分离,但您仍然可以实现您想要的。 它使用接口方法。
首先,声明一个可以让ClassB
与 Activity 通信的接口,并将其命名为MyCallback
:
public interface MyCallback {
// Declaration of the template function for the interface
public void updateMyText(String myString);
}
接下来在您的 Activity 中,实现MyCallback
,从而实现其函数定义。 在此函数中,您将收到来自ClassB
的字符串,您可以ClassB
地做任何事情,例如,更新TextView
(或EditText
等):
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);
}
}
最后,您可以声明接受MyCallback
ClassB
(即,您的 Activity 类对象也是MyCallback
)。 从那里你可以使用ClassB
与 Activity 通信并让它通过updateMyText
函数更新它的TextView
:
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);
}
}
}
希望这有助于更好地展示将 Activity 与ClassB
正确解耦的架构结构。
这实际上是一个看似“简单”的问题,但实际上是 Android 开发环境中的一个复杂问题。
活动是“流程入口点”,这意味着您看到的任何活动都可以充当“启动时应用程序的第一个入口点”。 人们认为只有具有MAIN/LAUNCHER
Intent 过滤器的 Activity 才能在启动时启动,但这是错误的。
任何Activity 都可以充当“第一个 Activity”,因为 Android 可以从任何点使用当前活动导航堆栈重新启动它。
无论如何,考虑到这一点,一个 Activity 可以显示一个View
,人们经常使用 Activity 来保存他们应用程序的每个屏幕(而不是将其用作入口点,并在其中交换视图控制器〜片段)。
因此,如果您有多个 Activity,那么您需要以这样的方式在它们之间共享数据,即考虑到这两个Activity 都可以作为应用程序的第一个Activity随时启动。
为此,您需要做的不是“直接从另一个类设置文本视图的文本”,而是需要修改 observable 共享数据。
新发布的官方Android 架构组件提供了LiveData<T>
类,该类有一个名为MutableLiveData<T>
的子类。
要将数据从一个类更新到另一个 Activity,您必须做的是将全局数据公开为 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;
}
}
DataRepository
应该公开 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);
}
}
活动订阅此内容的地方:
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());
}
}
}
因此,要更新此文本,您需要获取DataRepository
类,并对其调用updateText
:
DataRepository dataRepository = MyApplication.get().dataRepository();
dataRepository.updateText("my new text");
这将正确更新您的活动文本视图。
请注意,您还应该将数据持久化到onSaveInstanceState(Bundle
以便它不会丢失(假设数据不是来自磁盘)。
为此,您需要执行以下操作:
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());
}
}
然后相应地将saveState/restoreState
方法添加到DataRepository
。
您可以在Activity
创建一个getter
方法。
在您的Activity
类中:
public TextView getTextView()
{
TextView txtView = (TextView)findViewById(R.id.text);
return txtView;
}
在您的ClassB
类中:
public void Update()
{
MainMenu obj = new MainMenu();
TextView tv = obj.getTextView();
tv.setText("hello");
}
如果您在活动类中创建其他类( ClassB
)的对象,最简单的解决方案是通过构造函数传递TextView
(如果您没有在活动类中创建对象,则此答案将无济于事)。 所以你的例子应该如下所示:
// activity class
public class MainMenu extends Activity {
public TextView txtView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
txtView = (TextView)findViewById(R.id.text);
//instantiating a object of the ClassB and passing tv
ClassB obj = new ClassB(txtView);
}
}
// other class
public class ClassB {
//declarre tv
TextView txtView;
//get the tv as arg
public ClassB(TextView tv){
txtView = tv;
}
public void Update(){
txtView.setText("Hello");
}
}
这是访问另一个布局中的视图的 kotlin 代码:
//inflate layout
val view = inflate(this, R.layout.ly_custom_menu_item, null)
//access view inside the inflated
val tv = view.findViewById<AppCompatTextView>(R.id.txtV_WalletBalance_SideMenu)
//set value to view
tv.text = "Value"
//Add inflated Layout to something
我有一个 XML 页面 (Bert.XML),其中包含四个带有 ID 的 TextView1id、TextView2id、TextView3id 和 TextView4id 的 TextView
<GridLayout
android:id = "@+id/gridLayout"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:paddingTop="10dp">
<TextView
android:id = "@+id/TextView1id"
android:layout_gravity="end"
android:hint = "@+id/Risico"
android:textSize="@dimen/edit_size"
android:layout_height = "wrap_content"
android:layout_width = "fill_parent"
android:layout_column = "0"
android:layout_row = "1"
android:layout_columnSpan = "3"
/>
<TextView
android:id = "@+id/TextView2id"
android:layout_gravity="end"
android:hint = "@+id/Risico"
android:textSize="@dimen/edit_size"
android:layout_height = "wrap_content"
android:layout_width = "fill_parent"
android:layout_column = "0"
android:layout_row = "2"
android:layout_columnSpan = "3"
/>
<TextView
android:id = "@+id/TextView3id"
android:layout_gravity="end"
android:hint = "@+id/Risico"
android:textSize="@dimen/edit_size"
android:layout_height = "wrap_content"
android:layout_width = "fill_parent"
android:layout_column = "0"
android:layout_row = "3"
android:layout_columnSpan = "3"
/>
<TextView
android:id = "@+id/TextView4id"
android:layout_gravity="end"
android:hint = "@+id/Risico"
android:textSize="@dimen/edit_size"
android:layout_height = "wrap_content"
android:layout_width = "fill_parent"
android:layout_column = "0"
android:layout_row = "4"
android:layout_columnSpan = "3"
/>
</GridLayout>
此视图的代码如下所示。 在这里,我通过邮件类更改 TextViews 的文本。 Activity 已作为邮件类的参数给出
package nl.yentel.finekinney;
import android.app.Activity;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.TextView;
public class Bert extends AppCompatActivity {
private TextView theObject;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bert);
//both findViewByID work
theObject = this.findViewById(R.id.TextView2id);
theObject = findViewById(R.id.TextView2id);
Mail theMail=new Mail();
theMail.activity=this;
theMail.NameOfObject="TextView2id";
theMail.KindOfObject="TextView";
theMail.Mail();
CalculateFromClass(this);
Calculate(this);
}
//Calculate(dezeActiviteit);
public void Calculate(Activity dezeActiviteit) {
//here you should include dezeActiviteit which can be called from the Class
theObject = dezeActiviteit.findViewById(R.id.TextView1id);
theObject.setText("text from method");
}
public void CalculateFromClass(Activity dezeActiviteit) {
//here you should include dezeActiviteit which can be called from the Class
theObject = dezeActiviteit.findViewById(R.id.TextView4id);
theObject.setText("text from Class");
}
}
我的邮件类看起来像这样
package nl.yentel.finekinney;
import android.app.Activity;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class Mail extends AppCompatActivity {
public String NameOfObject;
public String KindOfObject;
public Activity activity;
void Mail() {
//if the name and kind has been given as an input parameter
int ressourceId = activity.getResources().getIdentifier(NameOfObject, "id", activity.getPackageName());
if (KindOfObject.equals("TextView")) {
TextView TextViewObject = activity.findViewById(ressourceId); //VISArB 14
TextViewObject.setText("this is a TextView");
}
if (KindOfObject.equals("EditText")) {
EditText EditTextObject = activity.findViewById(ressourceId); //VISArB 14
EditTextObject.setText("this is an EditText");
}
//if the name is hard coded
TextView TextViewObject;
TextViewObject = activity.findViewById(R.id.TextView3id);
TextViewObject.setText("Hard coded ID");
//if I want to run a method from my main Class
Bert dezeBert = new Bert();
dezeBert.CalculateFromClass(activity);
}
}
你可以做以下事情。 我试过了,它奏效了。 只需在从另一个类调用方法时传入对 TextView 的引用。 您的版本中的问题是 TextView 之间存在冲突,因为您要声明它两次。 而是只声明一次并在调用另一个类中的方法时将其作为参数传递。 干杯!!
// 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);
ClassB.update(txtView);
}
}
// other class
public class ClassB {
public ClassB(){
}
public void update(TextView tv){
tv.setText("Hello");
}
}
这可以通过简单的步骤轻松管理。
================================
下面的行可以通过 FindViewById 在 Fragment 类中写入
((TextView) ((Activity) getActivity()).findViewById(R.id.textview)).setText("");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.