簡體   English   中英

如何從另一個類更新 Activity 的 TextView

[英]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");
       }
    }

這可以通過簡單的步驟輕松管理。

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

1) Activity to Multiple Fragment

下面的行可以通過 FindViewById 在 Fragment 類中寫入

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM