当前位置: 首页 > 知识库问答 >
问题:

如何从我的活动中调用片段的文本视图和按钮?

景承教
2023-03-14

首先,我仍然是Android开发的新手,我以前在这里问过类似的问题,如何让我的片段利用我的活动数据?以及如何将数据从活动发送到片段?(Android)但似乎大多数人都不太明白我的意思,所以让我来解释一下。假设我有一个文本视图:

<TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="@string/current"
            android:textColor="#FF3D19"
            android:textSize="24sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.498"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

和一个按钮:

<Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="14dp"
            android:layout_marginTop="92dp"
            android:shadowColor="#FFFFFF"
            android:text="Click"
            android:textColor="#FF5722"
            app:layout_constraintStart_toStartOf="@+id/imageView3"
            app:layout_constraintTop_toTopOf="@+id/imageView3" /> 

在我的第一个片段layout.xml中,然后我想从我的主活动中调用它们,即current_temp=findViewById(R.id.textView10);以获取数据,即current_temp.set文本(getString(R.string.blank,response.body(). get电流(). getTemp() " ℃"));从天气API和findViewById(R.id.button2). setOnClickListener(new View. OnClickListener(){。Android Studio不允许您这样使用它们,所以我收到了这个错误:

java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法 'void android.view.View.setOnClickListener(android.view.View$OnClickListener)'

每当我运行该应用程序时。我在运行之前没有收到任何其他错误,所以原因是我没有实例化任何方法或回调或接口来告诉活动使用我的片段的 TextViews 和按钮。这就是我几天来一直试图解决的问题,但大多数人只是误解了我,并开始建议我应该学习ViewModel或LiveData。我在ViewModel上看了几个教程,包括Codinginflow,他们从未谈论过将活动链接到片段TextViews,他们只是让一个片段将数据发送到另一个片段,这不是我想要的。我的请求与此类似 Android:无法从活动片段更新文本视图。NullPointerException尝试并失败了,所以我需要逐步了解如何应用它的过程。

完整代码:家庭活动

public class HomeActivity extends AppCompatActivity {
    public static String BaseUrl = "http://api.openweathermap.org/";
    public static String AppId = "";
    public static String lat = "9.0574";
    public static String lon = "7.4898";
    // User Timezone name, current time, current temperature, current condition, sunrise, sunset, temperature, pressure, humidity, wind_speed, visibility, UV Index
    TextView time_zone, time_field, current_temp, current_output, rise_time, set_time, temp_out, Press_out, Humid_out, Ws_out, Visi_out, UV_out;
    ConstraintLayout constraintLayout;
    public static int count = 0;
    int[] drawable = new int[]{R.drawable.dubai, R.drawable.central_bank_of_nigeria, R.drawable.eiffel_tower, R.drawable.hong_kong, R.drawable.statue_of_liberty};
    Timer _t;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        time_zone = findViewById(R.id.textView9);
        time_field = findViewById(R.id.textView4);
        current_temp = findViewById(R.id.textView10);
        current_output = findViewById(R.id.textView11);
        rise_time = findViewById(R.id.textView25);
        set_time = findViewById(R.id.textView26);
        temp_out = findViewById(R.id.textView28);
        Press_out = findViewById(R.id.textView29);
        Humid_out = findViewById(R.id.textView30);
        Ws_out = findViewById(R.id.textView33);
        Visi_out = findViewById(R.id.textView34);
        UV_out = findViewById(R.id.textView35);

        BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
        NavController navController = Navigation.findNavController(this, R.id.fragment);
        NavigationUI.setupWithNavController(bottomNavigationView, navController);

        findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getCurrentData();
                constraintLayout = findViewById(R.id.layout);
                constraintLayout.setBackgroundResource(R.drawable.dubai);
                _t = new Timer();
                _t.scheduleAtFixedRate(new TimerTask() {
                    @Override
                    public void run() {
                        runOnUiThread(new Runnable() { // run on ui thread
                            @Override
                            public void run() {
                                if (count < drawable.length) {

                                    constraintLayout.setBackgroundResource(drawable[count]);
                                    count = (count + 1) % drawable.length;
                                }
                            }
                        });
                    }
                }, 5000, 5000);
            }

            void getCurrentData() {
                Retrofit retrofit = new Retrofit.Builder().baseUrl(BaseUrl).addConverterFactory(GsonConverterFactory.create()).build();
                WeatherService service = retrofit.create(WeatherService.class);
                Call<WeatherResponse> call = service.getCurrentWeatherData(lat, lon, AppId);
                call.enqueue(new Callback<WeatherResponse>() {
                    @Override
                    public void onResponse(@NonNull Call<WeatherResponse> call, @NonNull Response<WeatherResponse> response) {
                        if (response.code() == 200) {
                            WeatherResponse weatherResponse = response.body();
                            assert weatherResponse != null;

                            assert response.body() != null;
                            time_zone.setText(response.body().getTimezone());
                            time_field.setText(response.body().getCurrent().getDt());
                            current_temp.setText(getString(R.string.blank, response.body().getCurrent().getTemp() + " ℃"));
                            current_output.setText(response.body().getCurrent().getWeather().get(0).getDescription());
                            rise_time.setText(getString(R.string.blank, response.body().getCurrent().getSunrise() + " AM"));
                            set_time.setText(getString(R.string.blank, response.body().getCurrent().getSunset() + " PM"));
                            temp_out.setText(getString(R.string.blank, response.body().getCurrent().getTemp() + " ℃"));
                            Press_out.setText(getString(R.string.blank, response.body().getCurrent().getPressure() + " hpa"));
                            Humid_out.setText(getString(R.string.blank, response.body().getCurrent().getHumidity() + " %"));
                            Ws_out.setText(getString(R.string.blank, response.body().getCurrent().getWindSpeed() + " Km/h"));
                            Visi_out.setText(getString(R.string.blank, response.body().getCurrent().getVisibility() + " m"));
                        }
                    }

                    @Override
                    public void onFailure(@NonNull Call<WeatherResponse> call, @NonNull Throwable t) {
                    }
                });
            }
        });
    }
}

第一个片段

public class FirstFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";

// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;

public FirstFragment() {
    // Required empty public constructor
}

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment SecondFragment.
 */
// TODO: Rename and change types and number of parameters
public static FirstFragment newInstance(String param1, String param2) {
    FirstFragment fragment = new FirstFragment();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_first, container, false);
}
}

将整个功能带到 Fragment 也不起作用,因为只能从 Activity 调用改造。但是,如果您有任何可靠的建议,我将不胜感激。

共有3个答案

须志新
2023-03-14
匿名用户

你得到一个 NullPointerException,因为 findViewById(R.id.button2) 返回 null。

    < li >您需要使用片段的视图作为根。< code>activity.findViewById(...)调用使用活动的视图作为根——它正在搜索< code>activity_home.xml,它没有button2。您可以使用< code>fragment.getView()来访问片段的版本。findViewById(R.id._),但是: < li >您需要确保该片段已经完成其生命周期中的< code>onCreateView()步骤。所以必须发射并充气。否则,同样,按钮不存在。

您可以通过在片段生命周期中将其设置为回调来确保在正确的时间和视图上调用您的设置。

//This class can be anywhere - it can be global, private inner, anonymous
class SetupCallback extends FragmentLifeCycleCallback {
    @Override
    void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) {
        ButtonView button = v.findViewById(R.id.button2);
        if(button != null) {    //This gets called for all fragments so check for null
            button.setOnClickListener(new OnClickListener {...});

        }

        //Repeat for any other elements in the view e.g.
        TextView someText = v.findViewById(R.id.someTextView);
        someText.setText(R.string.message);
    }
}

//In the activity setup - I usually put in onCreate()
SupportFragmentManager.supportFragmentManager = getSupportFragmentManager();
supportFragmentManager.registerFragmentLifecycleCallbacks(new SetupCallback());
//anonymous version:
//supportFragmentManager.registerFragmentLifecycleCallbacks(new FragmentLifecycleCallback() { /*contents of class*/ });

或者,您可以在“活动”中初始化Retrofit和Weather服务,使用构造函数或捆绑包将它们传递给片段,然后使用它们在onCreateView()中设置onClickListener

RxJava和SharedView方法是让侦听器卡在所有片段生命周期调用上的替代方案,而不是让片段更具反应性的替代架构。

这需要< code > androidx . life cycle . common 依赖项。如果你用的是gradle,那就是:

dependencies {
    implementation 'androidx.lifecycle:lifecycle-common:2.3.0-rc1'
}

白浩荡
2023-03-14

有很多方法可以实现您的目标,我将使用RxJava。

  1. 在项目中添加RxJava

实现'io.reactivex.rxjava3: rxandroid: 3.0.0'

public class WeatherReport {

    private String time_zone;
    private String time_field;
    private String current_temp;
    private String current_output;
    private String rise_time;
    private String set_time;
    private String temp_out;
    private String Press_out;
    private String Humid_out;
    private String Ws_out;
    private String Visi_out;

    public String getCurrent_output() {
        return current_output;
    }

    public String getCurrent_temp() {
        return current_temp;
    }

    public String getHumid_out() {
        return Humid_out;
    }

    public String getPress_out() {
        return Press_out;
    }

    public String getRise_time() {
        return rise_time;
    }

    public String getSet_time() {
        return set_time;
    }

    public String getTemp_out() {
        return temp_out;
    }

    public String getTime_field() {
        return time_field;
    }

    public String getTime_zone() {
        return time_zone;
    }

    public String getVisi_out() {
        return Visi_out;
    }

    public String getWs_out() {
        return Ws_out;
    }

    public void setCurrent_output(String current_output) {
        this.current_output = current_output;
    }

    public void setCurrent_temp(String current_temp) {
        this.current_temp = current_temp;
    }

    public void setHumid_out(String humid_out) {
        Humid_out = humid_out;
    }

    public void setPress_out(String press_out) {
        Press_out = press_out;
    }

    public void setRise_time(String rise_time) {
        this.rise_time = rise_time;
    }

    public void setSet_time(String set_time) {
        this.set_time = set_time;
    }

    public void setTemp_out(String temp_out) {
        this.temp_out = temp_out;
    }

    public void setTime_field(String time_field) {
        this.time_field = time_field;
    }

    public void setTime_zone(String time_zone) {
        this.time_zone = time_zone;
    }

    public void setVisi_out(String visi_out) {
        Visi_out = visi_out;
    }

    public void setWs_out(String ws_out) {
        Ws_out = ws_out;
    }
}
import io.reactivex.rxjava3.subjects.BehaviorSubject;

public class RxJavaBus {

    private static final BehaviorSubject<WeatherReport> behaviorSubject
            = BehaviorSubject.create();


    public static BehaviorSubject<WeatherReport> getSubject() {
        return behaviorSubject;
    }

}
WeatherReport weatherReport = new WeatherReport();
        
weatherReport.setCurrent_output("Some DATA");
weatherReport.setCurrent_temp("Some DATA");
weatherReport.setHumid_out("Some DATA");
weatherReport.setPress_out("Some DATA");
weatherReport.setRise_time("Some DATA");
weatherReport.setSet_time("Some DATA");
weatherReport.setTime_field("Some DATA");
weatherReport.setVisi_out("Some DATA");
weatherReport.setTemp_out("Some DATA");
weatherReport.setWs_out("Some DATA");
weatherReport.setTime_zone("some DATA");

RxJavaBus.getSubject().onNext(weatherReport);
RxJavaBus.getSubject().subscribe(weatherReportFromActivity -> {

            weatherReportFromActivity.getCurrent_output();
            weatherReportFromActivity.getCurrent_temp();
            weatherReportFromActivity.getHumid_out();
            weatherReportFromActivity.getPress_out();
            weatherReportFromActivity.getRise_time();
            weatherReportFromActivity.getSet_time();
            weatherReportFromActivity.getWs_out();
            weatherReportFromActivity.getTime_zone();
            weatherReportFromActivity.getVisi_out();
            weatherReportFromActivity.getTime_field();
            weatherReportFromActivity.getTemp_out();
});
袁安志
2023-03-14

我建议您有两种方法可以将数据更新为活动片段的文本视图。

1.调用方法更新活动片段的文本视图(简单方式)

  • 在片段类中创建一个方法 updateData() 以将数据更新到文本视图。
  • 在活动类中声明片段参数,并在将片段添加到活动时分配给此参数。
  • 当您在活动中从 api 接收数据时,调用 fragment.updateData()

fragment_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/temp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="TextView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/hud"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="TextView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/temp" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

home_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

第一段.kt

class FirstFragment : Fragment(R.layout.fragment_layout) {

    private lateinit var temp: TextView
    private lateinit var hud: TextView

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        temp = view.findViewById(R.id.temp)
        hud = view.findViewById(R.id.hud)
    }

    fun setDataToView(data: WeatherResponse) {
        temp.text = data.temp
        hud.text = data.hud
    }
}

HomeActivity.kt

class HomeActivity: AppCompatActivity() {

    private val fragment = FirstFragment()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.home_activity)

        addFragment()

        fragment.view?.findViewById<Button>(R.id.button2)?.setOnClickListener {
            getCurrentData()
        }


    }

    private fun addFragment(){
        val fm = supportFragmentManager
        fm.beginTransaction().replace(R.id.container, fragment, "FirstFragment").commit()
    }

    private fun getCurrentData(){
        //Your retrofit code in here. I only show code in onResponse()
        //.....
        @Override
        public void onResponse(@NonNull Call<WeatherResponse> call, @NonNull Response<WeatherResponse> response) {
            if (response.code() == 200) {
                fragment.setDataToView(response)
            }
        }

        //....
    }
}

2. 使用视图模型

>

  • 使用livedata参数创建SharedViewModel类。

    在活动中,在onCreate()上创建SharedViewModel参数,如下所示:

    SharedViewModel viewModel=新的SharedView模型(此)。get(SharedViewModel.class)

    在片段中,在onActivityCreated()上创建SharedViewModel参数,如下所示:

    SharedViewModel view Model=新的SharedViewModel(要求活动()). get(SharedViewModel. class);

    最后,您在活动和片段中有相同的ViewModel实例,因为两者都使用活动上下文。当您从api接收数据时,更新您在活动中的livedata参数,片段还接收livedata参数onChanged事件,然后您可以更新文本视图。

  •  类似资料:
    • 我找不到如何从< code>Activity更改fragment的< code>textview。我有4个文件: frag_class.xml有textView,我想更改MainActivity.java的文本。FragmentClass扩展了片段,此片段显示在MainActivity中,FragmentClass具有: 在MainActivity中,我尝试了这个: 但可悲的是,这段代码给了我Nu

    • 我刚开始学Android。我有一个活动类,我想把它重定向到导航栏的ViewPage中的一个片段?我尝试了很多方法,但都不奏效。我希望能帮上忙!!!我的代码:有一个mainactivity.java有一个ViewPager和BottomNavigationView ViewPageApdater类 和Activity类,但我遇到一个问题:java.lang.IllegalArgumentExcept

    • 我在中有一组选项卡,每个选项卡都包含自己的片段。当我尝试通过从该片段中启动一个新活动并使用方法时,我的应用程序强制关闭。 在四处寻找了一段时间后,我找到了一个名为startActivityFromFragment的方法的一两个引用,但在搜索了大约一个小时后,我找不到任何关于如何使用它或这是否是我应该使用的方法的解释或示例。 我想我要问的是,从一个活动启动一个新活动和从一个片段启动一个新活动之间是否

    • fragment类主活动/主活动如何限制我的主活动在从片段的最后一页返回到主活动时不返回到片段的最后一页,就像我有一个主活动,单击按钮该主活动会导致另外3个活动,其中一个活动有片段。片段的最后一页指向home activity,但当我在home activity上后退时,它再次将我引导到片段的最后一页,然后我再次按下back按钮,然后我的应用程序关闭

    • 我刚接触Android,有一个带有片段的选项卡布局,我有一个编辑文本字段,它是在我的父活动中声明的,我想检查编辑文本字段是否为空,是否来自片段。我该怎么做呢?这是我做的,但它显示了错误。这是我的主要活动编辑文本字段: 这是我的片段活动: 这是我的日志:

    • 我在片段类中有方法。我想从主活动中调用该方法,但不想使用FragmentById(或)FragmentByTag。 我的碎片方法: 如何在不使用FragmentById(或)FragmentByTag的情况下从主活动调用上述方法?