【问题标题】:Passing Data Between Fragments to Activity将 Fragment 之间的数据传递给 Activity
【发布时间】:2013-01-04 14:01:47
【问题描述】:

我需要在 5 个 fragments 到一个 Activity 之间传递数据,当我到达第 5 个 fragment 时,那些 fragments 一个接一个地发送数据,然后我需要存储所有 5 个 fragments 数据如何我们可以这样做吗?任何想法都很棒。

【问题讨论】:

    标签: android android-activity fragment


    【解决方案1】:

    将数据从每个片段传递给活动,当活动获取所有数据然后处理它。 您可以使用接口传递数据。

    片段:

    public class Fragment2 extends Fragment {
    
      public interface onSomeEventListener {
        public void someEvent(String s);
      }
    
      onSomeEventListener someEventListener;
    
      @Override
      public void onAttach(Activity activity) {
        super.onAttach(activity);
            try {
              someEventListener = (onSomeEventListener) activity;
            } catch (ClassCastException e) {
                throw new ClassCastException(activity.toString() + " must implement onSomeEventListener");
            }
      }
    
      final String LOG_TAG = "myLogs";
    
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
          Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment2, null);
    
        Button button = (Button) v.findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
          public void onClick(View v) {
            someEventListener.someEvent("Test text to Fragment1");
          }
        });
    
        return v;
      }
    }
    

    活动:

    public class MainActivity extends Activity implements onSomeEventListener{
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            Fragment frag2 = new Fragment2();
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.add(R.id.fragment2, frag2);
            ft.commit();
        }
    
      @Override
      public void someEvent(String s) {
          Fragment frag1 = getFragmentManager().findFragmentById(R.id.fragment1);
          ((TextView)frag1.getView().findViewById(R.id.textView)).setText("Text from Fragment 2:" + s);
      }
    }
    

    【讨论】:

    【解决方案2】:

    以下链接解释了片段之间的通信设计。

    Communicating with Other Fragments

    要允许 Fragment 与其 Activity 进行通信,您可以在 Fragment 类中定义一个接口并在 Activity 中实现它。 Fragment 在其 onAttach() 生命周期方法期间捕获接口实现,然后可以调用接口方法以与 Activity 通信。

    以下是 Fragment 到 Activity 通信的示例:

    public class HeadlinesFragment extends ListFragment {
    
    OnHeadlineSelectedListener mCallback;
    
    // Container Activity must implement this interface
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }
    
    ...
    }
    

    现在片段可以通过使用 OnHeadlineSelectedListener 接口的 mCallback 实例调用 onArticleSelected() 方法(或接口中的其他方法)将消息传递给 Activity。

    例如,当用户单击列表项时,会调用片段中的以下方法。 Fragment 使用回调接口将事件传递给父 Activity。

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Send the event to the host activity
        mCallback.onArticleSelected(position);
    }
    

    实现接口

    为了从片段接收​​事件回调,承载它的活动必须实现片段类中定义的接口。

    例如,以下活动实现了上例中的接口。

    public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...
    
    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment
        // Do something here to display that article
    }
    }
    

    向片段传递消息

    宿主Activity可以通过findFragmentById()捕获Fragment实例,将消息传递给Fragment,然后直接调用Fragment的公共方法。

    例如,假设上面显示的活动可能包含另一个片段,用于显示上述回调方法中返回的数据指定的项目。在这种情况下,Activity 可以将回调方法中接收到的信息传递给将显示该项目的另一个 Fragment:

    public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...
    
    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment
        // Do something here to display that article
    
        ArticleFragment articleFrag = (ArticleFragment)
                getSupportFragmentManager().findFragmentById(R.id.article_fragment);
    
        if (articleFrag != null) {
            // If article frag is available, we're in two-pane layout...
    
            // Call a method in the ArticleFragment to update its content
            articleFrag.updateArticleView(position);
        } else {
            // Otherwise, we're in the one-pane layout and must swap frags...
    
            // Create fragment and give it an argument for the selected article
            ArticleFragment newFragment = new ArticleFragment();
            Bundle args = new Bundle();
            args.putInt(ArticleFragment.ARG_POSITION, position);
            newFragment.setArguments(args);
    
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    
            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack so the user can navigate back
            transaction.replace(R.id.fragment_container, newFragment);
            transaction.addToBackStack(null);
    
            // Commit the transaction
            transaction.commit();
        }
       }
     }
    

    【讨论】:

    • 我确实喜欢这样,当我点击时,iPhone 在那个片段中我有一些按钮并编辑文本,然后当我提交时我正在进入主屏幕。当我再次单击列表项的其余部分时,我在最后执行相同的操作时单击所有信息然后我需要将 iPhone、BlackBerry、Android、诺基亚数据发送到不同的活动。我不知道该怎么做。(stackoverflow.com/questions/14439941/…)
    • 您能否详细说明您面临的问题?你想达到什么目的?
    【解决方案3】:

    我尝试了以上所有方法,但对我没有用。这就是我让它工作的方式。我使用接口作为将数据从片段发送到活动的手段。

    FragmentToActivity.java

    public interface FragmentToActivity {
    void communicate(String comm);
    
    }
    

    FragmentOne

    public class FragmentOne extends Fragment {
    
    private FragmentToActivity mCallback;
    
    
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            mCallback = (FragmentToActivity) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString()
                    + " must implement FragmentToActivity");
        }
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
    Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_login, container, 
    false);
    sendData("Andrews");
    
    return v;
    }
    @Override
    public void onDetach() {
        mCallback = null;
        super.onDetach();
    }
    
    public void onRefresh() {
        Toast.makeText(getActivity(), "Fragment : Refresh called.",
                Toast.LENGTH_SHORT).show();
      }
    private void sendData(String comm)
        {
        mCallback.communicate(comm);
    
        }
    
     }
    
    
    }
    

    活动一

    public class Account extends AppCompatActivity implements 
      FragmentToActivity{
    
      @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
     }
    
    @Override
    public void communicate(String s) {
    
    
        Log.d("received", s);
          }
    
    
    }
    

    【讨论】:

    • 我尝试了很多方法,但都没有奏效。你的方法奏效了。非常感谢:)
    • 在 sendData() 处出现空指针异常。顺便说一句,您正在将数据发送回使该片段膨胀的活动。对吗?
    【解决方案4】:

    您必须将信息返回到片段的活动。并且您的 Activity 将信息调度到其片段:

    // In fragment A
    ((ParentActivity)getActivity()).dispatchInformations("test");
    
    // In ParentActivity
    public void dispatchInformations(String mesg){
        fragmentB.sendMessage(mesg);
    }
    

    这是一个基本的例子

    【讨论】:

      【解决方案5】:

      您可以使用上述答案中解释的 Communicator 模式。 另外,您可以使用RxJava2. 以获得更好的解耦和效率。

      1- 创建总线:

      public final class RxBus {
      
          private static final BehaviorSubject<Object> behaviorSubject
              = BehaviorSubject.create();
      
      
          public static BehaviorSubject<Object> getSubject() {
              return behaviorSubject;
          }
      
      }
      

      2- 发送者活动或片段

      //the data to be passed
      MyData  data =getMyData();
      RxBus.getSubject().onNext(data) ;
      

      3-接收者活动或片段

      private Subscription subscription;
      
      public onCreate(Bundle savedInstanceState){
          subscription = RxBus.getSubject()
                          .subscribe(new Subscriber<Object>() {
      
                  @Override
                  public void onNext(Object o) {
                      if (o instanceof MyData) {
                          Log.d("tag", (MyData)o.getData();
                      }
                  }
      
                  @Override
                  public void onError(Throwable e) {
      
                  }
      
                  @Override
                  public void onComplete() {
      
                  }
              });
      }
      

      4-取消订阅以避免内存泄漏:

      @Override
      protected void onDestroy() {
          super.onDestroy();
       if(subscription!=null){
           subscription.unsubscribe();
         }
      
      }
      

      【讨论】:

      • 我已经尝试过您的解决方案。基本上它可以工作,但需要一些修改
      【解决方案6】:

      有一种非常简单的方法可以将数据从 Fragment 传递到另一个不是其容器的 Activity。

      1) 在 Fragment 中:当您启动 Activity 时,例如 onButtonClick,将您想要传递的数据作为额外的数据传递到您的意图中,如下所示:

           Intent intent = new Intent(getActivity(), MapsActivity.class);
           intent.putExtra("data", dataString);
           startActivity(intent);
      

      2)在接收Activity中:在你的onCreate方法中,创建一个Bundle来获取传递过来的信息,如下:

      Bundle extras = getIntent().getExtras();
          if (extras != null) {
              receivingString = extras.getString("data");
          } else {
              // handle case
          }
      

      希望它有所帮助:)

      【讨论】:

        【解决方案7】:

        我一直在寻找将数据从片段传递到活动的解决方案。我就是这样做的,我发现它最适合我的需要。

        我发现最好使用全局 shared ViewModel 共享和更新数据

        在共享 ViewModel 中,我使用可变实时数据存储和更新数据,并将其范围限定为 MainActivity。 ViewModel 是一个单例,在活动生命周期结束之前一直保留在内存中。

        class SharedViewModel: ViewModel() {
        
            private val selectedItems: MutableLiveData<List<Product>> =
                MutableLiveData<List<Product>>(listOf())
        
            fun getItems(): LiveData<List<Product>> {
                return selectedItems
            }
        
            fun sendSelectedItems(items: MutableList<Product>) {
                selectedItems.postValue(items)
            }
        }
        
        MainActivity: AppCompactActivity() {
            override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
            // scope shared view model to MainActivity
            // I can access and update data from here
                val model = ViewModelProvider(this).get(SharedViewModel::class.java)
            }
        }
        
        class MyFragment1: Fragment() {
            // I'm able to get and update data in the SharedViewModel in fragment
            // to activity
            private val sharedModel: SharedViewModel by activityViewModels()
        }
        

        此外,您可以向主活动添加回调。您可以使用接口。

        interface IAddListener {
            fun sendItems(items: MutableList<Product>?)
        }
        
        class MyFragment: Fragment() {
           
           override fun onAttach(context: Context) {
                super.onAttach(context)
        
                if (context is IAddListener)
                    mCallback = context
            }
        
            private var mCallback: IAddListener? = null
        } 
        
        class MainActivity: AppCompactActivity(), IAddToPrintQueueListener {
            
            override fun sendItems(items: MutableList<Product>?) {
                // update something
            }
        }
        

        这是关于共享数据的文档的链接documentation

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多