【问题标题】:How to send fragment edittext data to activity without buttons in the fragment如何将片段edittext数据发送到片段中没有按钮的活动
【发布时间】:2021-04-12 20:29:54
【问题描述】:

我正在使用片段和 viewpager 制作一个应用程序,它将用户数据发送到主要活动。数据将从多个片段中收集,并在提交按钮(包含在主活动中)被按下时发送到活动。 示例截图:

我不确定如何获取片段编辑文本数据。我尝试使用 R.findViewById 在 onClick 侦听器中获取提交按钮,但似乎我错过了一个重要步骤。我尝试查看视频/教程,但我只能找到在片段中按下按钮时获取数据的适用视频/教程,或者相反的视频/教程(片段从活动中获取数据)。

这是我的代码: formActivity.java

import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
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;

    //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); // this line can cause crashes
                viewPagerAdapter.addFragment(twoFragment.getInstance(),null); // this line can cause crashes
                viewPagerAdapter.addFragment(threeFragment.getInstance(),null); // this line can cause crashes

                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) {
        Log.d(TAG, "returnToMainMenu: ");
    }

    public void returnToMainMenu(View view) {
        Log.d(TAG, "returnToMainMenu: ");
    }
}

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

}

oneFragment.java

import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

public class oneFragment extends Fragment {

    public static oneFragment getInstance(){
        oneFragment oneFragment = new oneFragment();
        return oneFragment;
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
    }


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.page_one, container,false);

        return view;
    }
}

activity_formactivity.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>

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>

我很新,所以任何替代建议以及答案也将不胜感激。

【问题讨论】:

  • 如果您正在使用片段并且希望您的数据在父活动中而不是使用接口,这是最好的方法
  • 感谢您的评论,您是否有任何链接指向如何使用多个片段到主要活动来执行此操作的示例?
  • 这对你有帮助,Callback from fragment to Activity

标签: java android android-studio android-fragments android-viewpager


【解决方案1】:

实现常规 FragmentPagerAdapter 的正确方法是:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    public ViewPagerAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    @Override
    public Fragment getItem(int position) {
        if(position == 0) return new RulesFragment();
        if(position == 1) return new TreeFragment();
        if(position == 2) return new PredictionFragment();

        throw new IllegalStateException("Unexpected position " + position);
    }

    @Override
    public int getCount() {
        return 3;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        if(position == 0) return "TREE RULES";
        if(position == 1) return "REGRESSION TREE";
        if(position == 2) return "PREDICTION";
      
        throw new IllegalStateException("Unexpected position " + position);
    }
}

要获得对由 ViewPager 创建的 Fragment 的引用,请使用以下 findFragmentByTag 方案:

Fragment fragment = supportFragmentManager.findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + fragmentPosition)

在多个片段之间进行通信的正确方法是使用作用域为共享作用域的 ViewModel(在这种情况下,可能是 Activity)。

详情请参考https://developer.android.com/codelabs/kotlin-android-training-view-model#0

【讨论】:

    【解决方案2】:

    使用捆绑包。这是一个例子:

    Fragment fragment = new Fragment();
    Bundle bundle = new Bundle();
    bundle.putInt(key, value);
    fragment.setArguments(bundle);
    

    Bundle 为许多数据类型提供了 put 方法。看到这个

    然后在您的 Fragment 中,使用以下命令检索数据(例如在 onCreate() 方法中):

    Bundle bundle = this.getArguments();
    if (bundle != null) {
            int myInt = bundle.getInt(key, defaultValue);
    }
    

    在 bundle.setArguments 中设置第一个片段的值,第二个片段的 onCreate() 使用 bundle.getInt() 获取值 在第二个片段中放入与 bundle.setArguemnts 相同的第一个片段和第二个片段的值,因此在第三个片段中,您将获得第一个片段和第二个片段的值。


    片段 1:

     Bundle bundle = new Bundle();
            bundle.putString("FRAGEMNT1", "VALUE FRAGEMENT 1");
            fragment.setArguments(bundle);
    

    在片段 2 的 onCrete() 中

    Bundle bundle = this.getArguments();
    if (bundle != null) {
        String frag1Value = bundle.getString("FRAGEMNT1");
    }
    

    现在将两个值都放在片段 2 中

    Bundle bundle = new Bundle();
            bundle.putString("FRAGEMNT1", "VALUE FRAGEMENT 1");
            bundle.putString("FRAGEMNT2, "VALUE FRAGEMENT 2);
            fragment.setArguments(bundle);
    

    在片段 3 onCrete()

    Bundle bundle = this.getArguments();
    if (bundle != null) {
        String frag1Value = bundle.getString("FRAGEMNT1");
         String frag2Value = bundle.getString("FRAGEMNT2");
    }
    

    现在将两个值都放在片段 3 中

    Bundle bundle = new Bundle();
            bundle.putString("FRAGEMNT1", "VALUE FRAGEMENT 1");
            bundle.putString("FRAGEMNT2, "VALUE FRAGEMENT 2);
            bundle.putString("FRAGEMNT3, "VALUE FRAGEMENT 3");
            fragment.setArguments(bundle);
    

    现在活跃在克里特岛

    Bundle bundle = this.getArguments();
    if (bundle != null) {
        String frag1Value=bundle.getString("FRAGEMNT1");
        String frag2Value=bundle.getString("FRAGEMNT2");
        String frag3Value=bundle.getString("FRAGEMNT3");
    }
    

    【讨论】:

    • 我有点迷茫,你是说在第三个片段中获取 2 个片段的值?我想访问 mainactivity/formactivity 中所有 3 个片段的 edittext 字段
    • 我们将数据从第一个片段传递到第二个,第二个到第三个,最后在活动中合并所有三个片段数据
    【解决方案3】:

    如何使用与FormActivity 绑定的ViewModel 并将编辑文本值保存在那里 https://developer.android.com/topic/libraries/architecture/viewmodel?gclid=Cj0KCQiA3NX_BRDQARIsALA3fIJFaBMomx-KDhghEHZghVGwGaafvDwMpGzFxQFGm3M3_e0lv9Bzt1UaAoq7EALw_wcB&gclsrc=aw.ds

    class FormViewModel : ViewModel() {
       val answers: Map<String, String> = mutableMapOf()
    }
    

    来自片段

    editText.addTextChangedListener(object : TextWatcher {
          override fun afterTextChanged(s: Editable?) {
             val viewmodel = ViewModelProviders.of(requireActivity()).get(FormViewModel::class.java) 
             viewModel.answer["SOME_KEY_HERE"] = s.toString()
          }
          
        
          override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
          }
        
          override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
          }
        })
    

    从活动中你可以访问这样的值

    ViewModelProvider.of(this).get(FormViewModel::class.java).answer
    

    对不起,我是用 kotlin 写的,但你应该能够理解这个想法

    【讨论】:

    • 对不起,我很新,这是一个新概念,所以我只能用Java理解。我喜欢使用视图模型的想法,但我发现很少有关于如何对活动的多个片段(不是片段>片段或活动>片段)执行此操作的示例
    【解决方案4】:

    您可以使用 SharedPreferences 来存储数据并在需要时检索数据。 示例:

    在 Preference 中设置值:

    SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
     editor.putString("key", "your answer");
     editor.apply();
    

    从偏好中检索数据:

    SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); 
    String answer= prefs.getString("key", "");
    

    【讨论】:

    • 感谢您的回答,但我能找到的所有示例都使用片段中的 onclick 侦听器执行此操作。在我的情况下,我需要通过单击 mainactivity/formactivity 中的按钮来访问片段中的 edittext 数据
    • 您可以在将数据保存到 SharedPreferences 后轻松访问。只需将其检索到 Activity 中
    • 我明白了,我只是在询问如何在片段外部单击按钮时在片段中执行此操作。如果片段中没有 onclick 侦听器,我找不到任何示例。你知道我在哪里可以找到吗?
    猜你喜欢
    • 2014-05-04
    • 2021-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多