[英]how to find button id of host activity in the fragment and send data to the host activity in the fragment
Edit: I changed my code as per the suggestion, but my app still crashes.编辑:我根据建议更改了我的代码,但我的应用程序仍然崩溃。 I posted the error to the bottom of the question
我将错误发布到问题的底部
I have been trying for 2 days to send an edittext data from a fragment to the main activity with a click of a button that is not in the fragment (it is in the host activity), and having trouble doing this even though I feel like the answer is probably simple!我已经尝试了 2 天,通过单击不在片段中的按钮(它在主机活动中)将编辑文本数据从片段发送到主要活动,即使我觉得这样做也遇到了麻烦答案可能很简单!
There are answers on here that suggest an interface but I can not find any examples that don't use a button from in the fragment.这里有建议界面的答案,但我在片段中找不到任何不使用按钮的示例。 When I attempt to find a button outside of the fragment and then send the data I get a runtime error.
当我尝试在片段之外找到一个按钮然后发送数据时,我得到一个运行时错误。
My code我的代码
FormActivity.java, the part of the code that is supposed to receive the string is at the bottom in submitFormEntries FormActivity.java,应该接收字符串的代码部分在submitFormEntries的底部
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.google.android.material.tabs.TabLayout;
public class FormActivity extends AppCompatActivity{
private static final String TAG = "PROCESS";
TabLayout tabLayout;
ViewPager viewPager;
oneFragment fragA = new oneFragment(); // this line can cause crashes
//or set to 0 and change it dynamically in the onPageSelected method
private int numFrags = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_formactivity);
viewPager = findViewById(R.id.viewPager);
tabLayout = findViewById(R.id.tabLayout);
getTabs();
//Add onPageChangeListener to get the position of the current tab and change the button text based on the position
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Button back = findViewById(R.id.backButton);
Button next = findViewById(R.id.nextButton);
Button mainReturn = findViewById(R.id.mainReturn);
Button submit = findViewById(R.id.submitButton);
PagerAdapter adapter = viewPager.getAdapter();
//numFrags = viewPager.getAdapter().getCoBunt() -1; - dynamically get new frags
if (position == 0) {
back.setVisibility(View.GONE);
next.setVisibility(View.VISIBLE);
mainReturn.setVisibility(View.VISIBLE);
}
else if (adapter != null && position == numFrags) {
back.setVisibility(View.VISIBLE);
next.setVisibility(View.GONE);
submit.setVisibility(View.VISIBLE);
}
else {
back.setVisibility(View.VISIBLE);
next.setVisibility(View.VISIBLE);
mainReturn.setVisibility(View.GONE);
submit.setVisibility(View.GONE);
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
//Add fragments to viewPager using the object ViewPagerAdapter
public void getTabs(){
final ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
new Handler().post(new Runnable() {
@Override
public void run() {
viewPagerAdapter.addFragment(oneFragment.getInstance(),null); // `oneFragment.getInstance()` should be inside `FragmentPagerAdapter.getItem()`
viewPagerAdapter.addFragment(twoFragment.getInstance(),null); // `twoFragment.getInstance()` should be inside `FragmentPagerAdapter.getItem()`
viewPagerAdapter.addFragment(threeFragment.getInstance(),null); // `threeFragment.getInstance()` should be inside `FragmentPagerAdapter.getItem()`
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
});
}
//METHODS FOR THE BUTTON LISTENERS
public void goBack(View view) {
viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
}
public void goNext(View view) {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
}
public void submitFormEntries(View view) {
Intent intent = getIntent();
String message = intent.getStringExtra("Answer One");
Log.d(TAG, message);
}
public void returnToMainMenu(View view) {
Log.d(TAG, "returnToMainMenu: ");
}
}
My fragment code oneFragment.java:我的片段代码 oneFragment.java:
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class oneFragment extends Fragment{
private EditText answer_One;
public static oneFragment getInstance() {
oneFragment oneFragment = new oneFragment();
return oneFragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.page_one, container, false);
final Button submit = (Button) getActivity().findViewById(R.id.submitButton);
answer_One = (EditText) view.findViewById(R.id.answerOne);
if(answer_One != null){
submit.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent intent = new Intent(requireActivity().getBaseContext(),
FormActivity.class);
intent.putExtra("Answer One", answer_One.toString());
getActivity().startActivity(intent);
}
});
}
return view;
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
}
@Override
public void onDetach() {
super.onDetach();
}
}
ViewPagerAdaper.java查看PagerAdaper.java
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragmentList = new ArrayList<>(); // this line can cause crashes
private List<String> stringList = new ArrayList<>();
public ViewPagerAdapter(@NonNull FragmentManager fm) {
super(fm);
}
@NonNull
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return stringList.get(position);
}
public void addFragment(Fragment fragment, String title){
fragmentList.add(fragment); // this line can cause crashes
stringList.add(title);
}
}
My error messages, edited to reflect answer我的错误消息,已编辑以反映答案
2021-01-07 19:08:07.767 8786-8786/net.larntech.tablayout E/AndroidRuntime: FATAL EXCEPTION: main
Process: net.larntech.tablayout, PID: 8786
java.lang.IllegalStateException: Fragment oneFragment{9ca3c26} (7a20c5f2-8918-4de4-98a6-bed63353b415)} not attached to an activity.
at androidx.fragment.app.Fragment.requireActivity(Fragment.java:833)
at net.larntech.tablayout.oneFragment$1.onClick(oneFragment.java:37)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
EDIT: Here are the xmls编辑:这里是xml
The main activity: activity_formctivity.xml主要活动: activity_formctivity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context=".FormActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<Button
android:id="@+id/backButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="goBack"
android:visibility="gone"/>
<Button
android:id="@+id/mainReturn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/mainReturn"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="returnToMainMenu"
android:visibility="visible"/>
<Button
android:id="@+id/nextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="goNext"/>
<Button
android:id="@+id/submitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/submit"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="submitFormEntries"
android:visibility="gone"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tabBackground="@drawable/tab_selector"
app:tabIndicatorHeight="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>
fragment xml file page_one.xml片段 xml 文件 page_one.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/titleOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/title_one"
android:textColor="@color/colorPrimaryDark"
android:textSize="32sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/questionOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/questionOne"
android:textColor="@color/colorPrimaryDark"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/descriptionOne"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/descriptionOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/descriptionOne"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/answerOne"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<EditText
android:id="@+id/answerOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/answerHintOne"
android:inputType="textMultiLine"
android:maxLines="4"
android:minLines="4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
I need to do this with quite a few fragments by the way, so solutions like bundles and sharedprefs are not ideal.顺便说一句,我需要用相当多的片段来做到这一点,所以像 bundles 和 sharedprefs 这样的解决方案并不理想。 If the answer is to set up an interface, how do I go about doing this?
如果答案是设置一个接口,我该怎么做呢?
In your fragmentOne, you can't call getView()
in onCreateView
as the fragment view is not created yet;在您的 fragmentOne 中,您不能在
onCreateView
中调用getView()
,因为尚未创建片段视图; actually onCreateView()
creates the fragment View and returns it.实际上
onCreateView()
创建片段视图并返回它。
So to solve this, you need to use the inflated view itself instead.所以要解决这个问题,你需要使用膨胀的视图本身。
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.page_one, container, false);
// answer_One = (EditText) getView().findViewById(R.id.answerOne); // returns NPE
answer_One = (EditText) view.findViewById(R.id.answerOne); // << Use this
...
UPDATE更新
You need to access activity's button in onResume
of the fragment as below您需要访问片段的
onResume
中的活动按钮,如下所示
@Override
public void onResume() {
super.onResume();
final Button submit = (Button) (FormActivity getActivity()).findViewById(R.id.submitButton);
submit.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent intent = new Intent(requireActivity().getBaseContext(),
FormActivity.class);
intent.putExtra("Answer One", answer_One.toString());
getActivity().startActivity(intent);
}
});
}
And remove the button and its listener from onCreateView()
method并从
onCreateView()
方法中删除按钮及其侦听器
The correct way to implement a regular FragmentPagerAdapter is:实现常规 FragmentPagerAdapter 的正确方法是:
public class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public Fragment getItem(int position) {
if(position == 0) return new OneFragment();
if(position == 1) return new TwoFragment();
if(position == 2) return new ThreeFragment();
throw new IllegalStateException("Unexpected position " + position);
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
if(position == 0) return "ONE";
if(position == 1) return "TWO";
if(position == 2) return "THREE";
throw new IllegalStateException("Unexpected position " + position);
}
}
Then, to communicate from Fragment to Activity, the current Google-recommended approach is to use an Activity-scoped ViewModel that hosts a MutableLiveData.然后,为了从 Fragment 到 Activity 进行通信,当前 Google 推荐的方法是使用托管 MutableLiveData 的 Activity 范围的 ViewModel。
public class MyViewModel extends ViewModel {
private final SavedStateHandle handle;
public MyViewModel(SavedStateHandle handle) {
this.handle = handle;
}
public final MutableLiveData<String> data = handle.getLiveData("data", "");
}
Then然后
public class MyActivity extends AppCompatActivity {
private MyViewModel myViewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
}
}
And和
public class MyFragment extends Fragment {
private MyViewModel myViewModel;
@Override
protected void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
myViewModel = new ViewModelProvider(requireActivity()).get(MyViewModel.class);
}
}
Then you can mutate the LiveData and observe it for changes.然后你可以改变 LiveData 并观察它的变化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.