如何在片段之间传递值

Vam*_*lla 102 android android-fragments

我很擅长使用Fragments.

我只是想构建一个使用Fragments的简单示例应用程序.我的方案是,我有两个活动,每个活动中有一个片段.第一个片段有一个edittext和一个按钮.第二个片段有一个textview.当我在edittext中输入名称并单击按钮时,第二个片段中的textview应显示在第一个片段的edittext中输入的名称.

我能够将第一个片段的值发送到它的活动,然后从该活动发送到第二个活动.现在我如何在第二个片段中使用此值.

这是Java代码:::

package com.example.fragmentexample;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class Fragment_1 extends Fragment{

    OnFragmentChangedListener mCallback;

    // Container Activity must implement this interface
    public interface OnFragmentChangedListener {
        public void onButtonClicked(String name);
    }

    @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 = (OnFragmentChangedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub      

        View view = inflater.inflate(R.layout.fragment_fragment_1, container, false);

        final EditText edtxtPersonName_Fragment = (EditText) view.findViewById(R.id.edtxtPersonName);
        Button btnSayHi_Fragment = (Button) view.findViewById(R.id.btnSayHi);

        btnSayHi_Fragment.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                String name = edtxtPersonName_Fragment.getText().toString();

                FragmentManager fm = getFragmentManager();
                Fragment_2 f2 = (Fragment_2) fm.findFragmentById(R.id.fragment_content_2);

                Activity activity = getActivity();

                if(activity != null)
                {
                    Toast.makeText(activity, "Say&ing Hi in Progress...", Toast.LENGTH_LONG).show();
                }


                if(f2 != null && f2.isInLayout())
                {
                    f2.setName(name);
                }
                else
                {
                    mCallback.onButtonClicked(name);
                }
            }
        });

        return view;


    }

}
Run Code Online (Sandbox Code Playgroud)

MainActivity.Java

package com.example.fragmentexample;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;

import android.view.Choreographer.FrameCallback;
import android.view.Menu;

public class MainActivity extends Activity implements Fragment_1.OnFragmentChangedListener {

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

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    @Override
    public void onButtonClicked(String name) {
        // TODO Auto-generated method stub

        Intent i = new Intent(this, SecondActivity.class);
        i.putExtra("", name);
        startActivity(i);
    }

}
Run Code Online (Sandbox Code Playgroud)

SecondActivity.Java

package com.example.fragmentexample;

import android.app.Activity;
import android.os.Bundle;

public class SecondActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_second);

        Bundle b = getIntent().getExtras();

        Fragment_2 f2 = new Fragment_2();
        f2.setArguments(b);
    }
}
Run Code Online (Sandbox Code Playgroud)

Fragment_2.Java

package com.example.fragmentexample;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class Fragment_2 extends Fragment{

    View view;
    TextView txtName;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub

        view = inflater.inflate(R.layout.fragment_fragment_2, container, false);

            // Exception at this line
        String name = getArguments().getString("message");
        txtName = (TextView) view.findViewById(R.id.txtViewResult);
        txtName.setText(name);

        return view;
    }

    @Override
    public void onAttach(Activity activity) {
        // TODO Auto-generated method stub
        super.onAttach(activity);       
    }

    public void setName(String name)
    {   
        txtName.setText("Hi " + name);
    }

}
Run Code Online (Sandbox Code Playgroud)

我得到以下异常:::

04-16 18:10:24.573: E/AndroidRuntime(713): FATAL EXCEPTION: main
04-16 18:10:24.573: E/AndroidRuntime(713): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.fragmentexample/com.example.fragmentexample.SecondActivity}: android.view.InflateException: Binary XML file line #8: Error inflating class fragment
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1815)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1831)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.access$500(ActivityThread.java:122)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1024)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.os.Handler.dispatchMessage(Handler.java:99)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.os.Looper.loop(Looper.java:132)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.main(ActivityThread.java:4123)
04-16 18:10:24.573: E/AndroidRuntime(713):  at java.lang.reflect.Method.invokeNative(Native Method)
04-16 18:10:24.573: E/AndroidRuntime(713):  at java.lang.reflect.Method.invoke(Method.java:491)
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
04-16 18:10:24.573: E/AndroidRuntime(713):  at dalvik.system.NativeStart.main(Native Method)
04-16 18:10:24.573: E/AndroidRuntime(713): Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class fragment
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:688)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:724)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.inflate(LayoutInflater.java:479)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.inflate(LayoutInflater.java:391)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.inflate(LayoutInflater.java:347)
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:223)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.Activity.setContentView(Activity.java:1786)
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.example.fragmentexample.SecondActivity.onCreate(SecondActivity.java:13)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.Activity.performCreate(Activity.java:4397)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1048)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1779)
04-16 18:10:24.573: E/AndroidRuntime(713):  ... 11 more
04-16 18:10:24.573: E/AndroidRuntime(713): Caused by: java.lang.NullPointerException
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.example.fragmentexample.Fragment_2.onCreateView(Fragment_2.java:24)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:754)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:956)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1035)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.Activity.onCreateView(Activity.java:4177)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:664)
04-16 18:10:24.573: E/AndroidRuntime(713):  ... 21 more
Run Code Online (Sandbox Code Playgroud)

如何从SecondActivity.java中的bundle获取Fragment_2.Java的值?

Shi*_*hiv 190

步骤1.将数据从片段发送到活动

Intent intent = new Intent(getActivity().getBaseContext(),
                        TargetActivity.class);
                intent.putExtra("message", message);
                getActivity().startActivity(intent);
Run Code Online (Sandbox Code Playgroud)

步骤2.在活动中接收此数据:

Intent intent = getIntent();
String message = intent.getStringExtra("message");
Run Code Online (Sandbox Code Playgroud)

第3步.将数据从活动发送到另一个活动遵循正常方法

Intent intent = new Intent(MainActivity.this,
                        TargetActivity.class);
                intent.putExtra("message", message);
                startActivity(intent);
Run Code Online (Sandbox Code Playgroud)

步骤4在活动中接收此数据

     Intent intent = getIntent();
  String message = intent.getStringExtra("message");
Run Code Online (Sandbox Code Playgroud)

步骤5.从活动中,您可以将数据发送到Fragment,意图如下:

Bundle bundle=new Bundle();
bundle.putString("message", "From Activity");
  //set Fragmentclass Arguments
Fragmentclass fragobj=new Fragmentclass();
fragobj.setArguments(bundle);
Run Code Online (Sandbox Code Playgroud)

并在Fragment onCreateView方法中接收片段:

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
          String strtext=getArguments().getString("message");

    return inflater.inflate(R.layout.fragment, container, false);
    }
Run Code Online (Sandbox Code Playgroud)

  • 是否有人厌恶做这样的事情是多么复杂 (20认同)
  • 我尝试了第 5 步,我从片段中调用 listactivity,在从该活动中选择项目后,我想以选定的文件名返回片段。但它不起作用,它在 onCreateView 给了我 Nullpointer 异常。请问有什么解决办法吗?这是我的问题 http://stackoverflow.com/questions/18208771/nullpointer-exception-while-returning-string-to-fragment-from-activity/18209614?noredirect=1#18209614 (2认同)

小智 45

如开发者网站所述

通常,您会希望一个片段与另一个片段进行通信,例如根据用户事件更改内容.所有Fragment-to-Fragment通信都是通过相关的Activity完成的.两个碎片永远不应该直接通信.

片段之间的通信应该通过相关的Activity来完成.

我们有以下组件:

活动托管片段并允许片段通信

FragmentA将发送数据的第一个片段

FragmentB第二个片段,它将从FragmentA接收数据

FragmentA的实现是:

public class FragmentA extends Fragment 
{
    DataPassListener mCallback;

    public interface DataPassListener{
        public void passData(String data);
    }

    @Override
    public void onAttach(Context context) 
    {
        super.onAttach(context);
        // This makes sure that the host activity has implemented the callback interface
        // If not, it throws an exception
        try 
        {
            mCallback = (OnImageClickListener) context;
        }
        catch (ClassCastException e) 
        {
            throw new ClassCastException(context.toString()+ " must implement OnImageClickListener");
        }
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) 
    {
        // Suppose that when a button clicked second FragmentB will be inflated
        // some data on FragmentA will pass FragmentB
        // Button passDataButton = (Button).........

        passDataButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (view.getId() == R.id.passDataButton) {
                    mCallback.passData("Text to pass FragmentB");
                }
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

MainActivity实现是:

public class MainActivity extends ActionBarActivity implements DataPassListener{

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

        if (findViewById(R.id.container) != null) {
            if (savedInstanceState != null) {
                return;
            }
            getFragmentManager().beginTransaction()
                    .add(R.id.container, new FragmentA()).commit();
        }
    }

    @Override
    public void passData(String data) {
        FragmentB fragmentB = new FragmentB ();
        Bundle args = new Bundle();
        args.putString(FragmentB.DATA_RECEIVE, data);
        fragmentB .setArguments(args);
        getFragmentManager().beginTransaction()
            .replace(R.id.container, fragmentB )
            .commit();
    }
}
Run Code Online (Sandbox Code Playgroud)

FragmentB的实现是:

public class FragmentB extends Fragment{
    final static String DATA_RECEIVE = "data_receive";
    TextView showReceivedData;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_B, container, false);
        showReceivedData = (TextView) view.findViewById(R.id.showReceivedData);
    }

    @Override
    public void onStart() {
        super.onStart();
        Bundle args = getArguments();
        if (args != null) {
            showReceivedData.setText(args.getString(DATA_RECEIVE));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望这个能帮上忙..

  • 什么是OnImageClickListener?以及如何转换为DataPassListener变量? (4认同)

ngu*_*cse 35

//在Fragment_1.java中

Bundle bundle = new Bundle();
bundle.putString("key","abc"); // Put anything what you want

Fragment_2 fragment2 = new Fragment_2();
fragment2.setArguments(bundle);

getFragmentManager()
      .beginTransaction()
      .replace(R.id.content, fragment2)
      .commit();
Run Code Online (Sandbox Code Playgroud)

//在Fragment_2.java中

Bundle bundle = this.getArguments();

if(bundle != null){
     // handle your code here.
}
Run Code Online (Sandbox Code Playgroud)

希望这对你有所帮助.


Jai*_*dra 22

来自开发者网站:

通常,您会希望一个片段与另一个片段进行通信,例如根据用户事件更改内容.所有Fragment-to-Fragment通信都是通过相关的Activity完成的.两个碎片永远不应该直接通信.

您可以借助其活动在片段之间进行通信.您可以使用方法在活动和片段之间进行通信.

请检查链接.


Gas*_*lén 6

科特林方式

使用官方 ViewModel 文档SharedViewModel中建议的

活动中的两个或多个片段需要相互通信是很常见的。想象一下主从片段的常见情况,其中有一个片段,用户从列表中选择一个项目,另一个片段显示所选项目的内容。这种情况绝不是微不足道的,因为两个片段都需要定义一些接口描述,并且所有者活动必须将两者绑定在一起。此外,两个片段都必须处理另一个片段尚未创建或可见的情况。

这个常见的痛点可以通过使用 ViewModel 对象来解决。这些片段可以使用其活动范围共享 ViewModel 来处理此通信

首先实现fragment-ktx以更轻松地实例化您的视图模型

dependencies {
    implementation "androidx.fragment:fragment-ktx:1.2.2"
}
Run Code Online (Sandbox Code Playgroud)

然后,您只需将要与其他片段共享的数据放入视图模型中:

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,要完成,只需在每个片段中实例化您的 viewModel,并selected从要设置数据的片段中设置 的值

片段A

class MasterFragment : Fragment() {

    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        itemSelector.setOnClickListener { item ->
        model.select(item)
      }

    }
}
Run Code Online (Sandbox Code Playgroud)

然后,只需在 Fragment 目的地监听这个值

片段B

 class DetailFragment : Fragment() {

        private val model: SharedViewModel by activityViewModels()

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
                // Update the UI
            })
        }
    }
Run Code Online (Sandbox Code Playgroud)

你也可以用相反的方式来做


kim*_*vin 5

首先,所有答案都是正确的。您可以使用 传递除自定义对象之外的数据Intent

如果要传递自定义对象,则必须实现SerialazableParcelable到您的自定义对象类。我觉得太复杂了...

因此,如果您的项目很简单,请尝试使用DataCache. 这为传递数据提供了一种超级简单的方法。 参考: GitHub 项目 CachePot

1-将此设置为将发送数据的视图或活动或片段

DataCache.getInstance().push(obj);
Run Code Online (Sandbox Code Playgroud)

2-在任何地方获取数据,如下所示

public class MainFragment extends Fragment
{
    private YourObject obj;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        obj = DataCache.getInstance().pop(YourObject.class);

    } //end onCreate()
} //end class MainFragment
Run Code Online (Sandbox Code Playgroud)


Arn*_*Rao 5

最新的fragment间数据传递方案可以通过使用ViewModel、LiveData等Android架构组件来实现。使用此解决方案,您无需定义用于通信的接口,并且可以获得使用视图模型的优势,例如由于配置更改而导致的数据生存。

在此解决方案中,通信中涉及的片段共享与其活动生命周期相关联的相同视图模型对象。视图模型对象包含 livedata 对象。第一个片段设置要在 livedata 对象上传递的数据,第二个片段观察者 livedata 更改并接收数据。

这是完整的示例:使用 ViewModel 在 Android 片段之间传递数据


Kni*_*ked 5

特别是现在 Android 团队越来越倾向于坚持单一活动模型,片段之间的通信变得更加重要。LiveData 和 Interfaces 是解决这个问题的完美方法。但现在谷歌终于解决了这个问题,并尝试使用 FragmentManager 带来一个更简单的解决方案。这是在 Kotlin 中如何完成的。

在接收器片段中,添加一个侦听器:

setFragmentResultListener(
    "data_request_key",
    lifecycleOwner,
    FragmentResultListener { requestKey: String, bundle: Bundle ->
        // Unpack the bundle and use data
        val frag1Str = bundle.getString("frag1_data_key")

    })
Run Code Online (Sandbox Code Playgroud)

在发件人片段 (frag1) 中:

setFragmentResult(
    "data_request_key",
    bundleOf("frag1_data_key" to value)
)
Run Code Online (Sandbox Code Playgroud)

请记住,此功能仅在 fragment-ktx 版本 1.3.0-alpha04 及更高版本中可用。

学分和进一步阅读:

一种在片段之间传递数据的新方法

Android 片段:片段结果