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

Ris*_*han 26 java android

我是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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ada*_*ost 54

您必须通过构造函数传递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");
   }
Run Code Online (Sandbox Code Playgroud)

  • 这是一个令人惊讶的不洁净的解决方案.我很惊讶地看到它有这么多的赞成和接受. (13认同)
  • `txtView`是**null**. (4认同)
  • 更好地使用/sf/answers/1955743751/中描述的界面 (2认同)

Ely*_*lye 22

前两个示例需要TextView直接在另一个类中使用.但是,有些情况下TextView不应该存在于其他类中,例如,您ClassB用于更新各种活动,其中一些活动更新TextViews,而其他活动可能更新EditTexts.

因此,以下解决方案可以指导您如何将您TextView与其他课程分离,但是,您仍然可以实现您想要的.它正在使用接口方法.

首先,声明一个可以ClassB与Activity通信的接口,并调用它MyCallback:

public interface MyCallback {
    // Declaration of the template function for the interface
    public void updateMyText(String myString);
}
Run Code Online (Sandbox Code Playgroud)

接下来在您的Activity中,实现MyCallback它的函数定义.在这个函数中,你将收到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);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,您可以声明ClassB接收MyCallback(即,您的Activity类对象也是a MyCallback).从那里你可以用来ClassB与Activity通信并让它TextView通过updateMyText函数更新它:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这有助于更好地显示正确解耦Activity的架构结构ClassB.

  • 您可以将其作为顶级界面放置,也可以放在ClassB中 (3认同)

Epi*_*rce 10

这实际上是一个看似"简单"的问题,但实际上是Android开发环境中的一个复杂问题.

活动是"流程入口点",这意味着您看到的任何活动都可以作为"启动时应用程序的第一个入口点".人们认为只有具有MAIN/LAUNCHERintent过滤器的Activity 才能在启动时启动,但这是错误的.

任何 Activity都可以充当"第一个Activity",因为Android可以从具有当前活动导航堆栈的任何点重新启动它.

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

因此,如果您有多个活动,那么您需要以这样的方式在它们之间共享数据,您需要考虑这两个活动可以随时作为 应用程序第一个 活动启动.


为此,您需要做的不是"直接从另一个类设置文本视图的文本",但您需要修改可观察的共享数据.

新发布的官方Android架构组件提供了这个LiveData<T>类,它有一个名为的子类MutableLiveData<T>.

要将数据从一个类更新到另一个类,您必须做的是将全局数据公开为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

活动订阅的地方:

public class MyActivity extends AppCompatActivity {
    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());
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

因此,要更新此文本,您需要获取DataRepository该类,并调用updateText它:

DataRepository dataRepository = MyApplication.get().dataRepository();
dataRepository.updateText("my new text");
Run Code Online (Sandbox Code Playgroud)

这将正确更新您的活动文本视图.

请注意,您还应该保留数据以onSaveInstanceState(Bundle使其不会丢失(假设数据不是来自磁盘)

  • @XO。我认为 LocalBroadcastManager 在发送事件时没有人订阅时可能会丢失事件,不是吗?LiveData 保留最新的。我已经很久没有使用 LocalBroadcastManager 了,因为你需要一个 Intent,而你可以只使用一个 EventBus(虽然我不能告诉你 LBM 是否跨进程工作,事件总线肯定不会) (2认同)