简体   繁体   English

如何从另一个类更新 Activity 的 TextView

[英]How to update a TextView of an Activity from another class

I am new to Android/Java programming.我是 Android/Java 编程的新手。 I have two classes, one is an Activity and the other is a normal class.我有两个类,一个是Activity ,另一个是普通类。 My activity class contains a TextView .我的活动类包含一个TextView Can I update the TextView of the activity class from a normal class?我可以从普通类更新活动类的TextView吗? 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");
        }
    }
}

You have to pass the Context reference via constructor.您必须通过构造函数传递 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");
   }

The preceding two examples require TextView to be used directly within the other class.前两个示例要求直接在另一个类中使用TextView However, there are cases where TextView shouldn't be present in the other class, eg, your ClassB is used to update various Activities, where some activities update TextView s, and others might update EditText s.但是,在某些情况下TextView不应该出现在另一个类中,例如,您的ClassB用于更新各种活动,其中一些活动更新TextView ,而其他活动可能更新EditText

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.因此,下面的解决方案可以指导您如何将TextView与其他类分离,但您仍然可以实现您想要的。 It's using the interface approach.它使用接口方法。

Firstly, declare an interface where you could have ClassB communicate to the Activity, and call it MyCallback :首先,声明一个可以让ClassB与 Activity 通信的接口,并将其命名为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.接下来在您的 Activity 中,实现MyCallback ,从而实现其函数定义。 In this function, you will receive the String from ClassB that you could do whatever you like, eg, update the TextView (or EditText , etc.):在此函数中,您将收到来自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);
    }
}

Lastly, you could declare ClassB that takes in MyCallback (ie, your Activity class object that is also a MyCallback ).最后,您可以声明接受MyCallback ClassB (即,您的 Activity 类对象也是MyCallback )。 From there you could use ClassB to communicate back to Activity and get it to update its TextView through the updateMyText function:从那里你可以使用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);
        }
    }
}

Hope this helps better show the architected structure of decoupling the Activity properly from ClassB .希望这有助于更好地展示将 Activity 与ClassB正确解耦的架构结构。

This is actually a deceptively "simple" question, but in reality a complicated problem in the context of Android development.这实际上是一个看似“简单”的问题,但实际上是 Android 开发环境中的一个复杂问题。

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.人们认为只有具有MAIN/LAUNCHER Intent 过滤器的 Activity 才能在启动时启动,但这是错误的。

Any Activity can act as the "first Activity", because Android can restart it from any point with the current active navigation stack.任何Activity 都可以充当“第一个 Activity”,因为 Android 可以从任何点使用当前活动导航堆栈重新启动它。

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).无论如何,考虑到这一点,一个 Activity 可以显示一个View ,人们经常使用 Activity 来保存他们应用程序的每个屏幕(而不是将其用作入口点,并在其中交换视图控制器〜片段)。

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 .因此,如果您有多个 Activity,那么您需要以这样的方式在它们之间共享数据,即考虑到这两个Activity 都可以作为应用程序第一个Activity随时启动


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 .为此,您需要做的不是“直接从另一个类设置文本视图的文本”,而是需要修改 observable 共享数据

The newly released official Android Architecture Components provide the LiveData<T> class, which has a subclass called MutableLiveData<T> .新发布的官方Android 架构组件提供了LiveData<T>类,该类有一个名为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要将数据从一个类更新到另一个 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;
    }
}

The DataRepository should expose LiveData: 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);
    }
}

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类,并对其调用updateText

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).请注意,您还应该将数据持久化到onSaveInstanceState(Bundle以便它不会丢失(假设数据不是来自磁盘)。

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.然后相应地将saveState/restoreState方法添加到DataRepository

You can make a getter method in your Activity .您可以在Activity创建一个getter方法。

In your Activity class:在您的Activity类中:

public TextView getTextView()
{

TextView txtView = (TextView)findViewById(R.id.text);
return txtView;
}

In your ClassB class:在您的ClassB类中:

public void Update()
{
          MainMenu obj = new MainMenu();
          TextView tv = obj.getTextView();
          tv.setText("hello");

}

If you are creating an object of your other class( ClassB )inside activity class, the simplest solution is to pass the TextView through constructor ( if you aren't create an object in the activity class this answer will not be helpful ).如果您在活动类中创建其他类( ClassB )的对象,最简单的解决方案是通过构造函数传递TextView如果您没有在活动类中创建对象,则此答案将无济于事)。 So your example should be like below:所以你的例子应该如下所示:

// 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");
   }
}

This is kotlin code to access the view inside another layout :这是访问另一个布局中的视图的 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

I have a XML page (Bert.XML) with four TextViews with ID's TextView1id, TextView2id, TextView3id and TextView4id我有一个 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>

The code for this view is shown below.此视图的代码如下所示。 In here I change the text of the TextViews through the Mail Class.在这里,我通过邮件类更改 TextViews 的文本。 The Activity has been given as a parameter for the Mail Class 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");
    }
}

My Mail Class looks like this我的邮件类看起来像这样

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);
    }
}

you can do the following thing.你可以做以下事情。 I tried it and it worked.我试过了,它奏效了。 Just pass in the reference to the TextView while calling the method from another class.只需在从另一个类调用方法时传入对 TextView 的引用。 The problem in your version, is that there is conflict between TextView because you are declaring it twice.您的版本中的问题是 TextView 之间存在冲突,因为您要声明它两次。 Instead declare it only once and pass it as an argument while calling the method in another class.而是只声明一次并在调用另一个类中的方法时将其作为参数传递。 Cheers!!干杯!!

    // 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");
       }
    }

This can be manage easily in simple to steps.这可以通过简单的步骤轻松管理。

================================ ================================

1) Activity to Multiple Fragment 1) Activity to Multiple Fragment

below line can write in Fragment class Via FindViewById下面的行可以通过 FindViewById 在 Fragment 类中写入

((TextView) ((Activity) getActivity()).findViewById(R.id.textview)).setText(""); ((TextView) ((Activity) getActivity()).findViewById(R.id.textview)).setText("");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM