将数据从活动发送到 Android 中的片段

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12739909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:38:19  来源:igfitidea点击:

Send data from activity to fragment in Android

androidandroid-fragments

提问by user1302569

I have two classes. First is activity, second is a fragment where I have some EditText. In activity I have a subclass with async-task and in method doInBackgroundI get some result, which I save to variable. How can I send this variable from subclass "my activity" to this fragment?

我有两节课。第一个是活动,第二个是我有一些EditText. 在活动中,我有一个带有异步任务的子类,在方法中doInBackground我得到了一些结果,我将其保存到变量中。如何将此变量从子类“我的活动”发送到此片段?

回答by ρяσ?ρ?я K

From Activity you send data with intent as:

从 Activity 发送数据的目的是:

Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);

and in Fragment onCreateView method:

并在 Fragment onCreateView 方法中:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    String strtext = getArguments().getString("edttext");    
    return inflater.inflate(R.layout.fragment, container, false);
}

回答by Ricardas

Also You can access activity data from fragment:

您还可以从片段访问活动数据:

Activity:

活动:

public class MyActivity extends Activity {

    private String myString = "hello";

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

    public String getMyData() {
        return myString;
    }
}

Fragment:

分段:

public class MyFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        MyActivity activity = (MyActivity) getActivity();
        String myDataFromActivity = activity.getMyData();
        return view;
    }
}

回答by Jorgesys

I′ve found a lot of answers here @ stackoverflow.com but definitely this is the correct answer of:

我在这里@stackoverflow.com 找到了很多答案,但这绝对是以下正确答案:

"Sending data from activity to fragment in android".

“将数据从活动发送到 android 中的片段”。

Activity:

活动:

        Bundle bundle = new Bundle();
        String myMessage = "Stackoverflow is cool!";
        bundle.putString("message", myMessage );
        FragmentClass fragInfo = new FragmentClass();
        fragInfo.setArguments(bundle);
        transaction.replace(R.id.fragment_single, fragInfo);
        transaction.commit();

Fragment:

分段:

Reading the value in the fragment

读取片段中的值

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

or just

要不就

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

回答by Noorul

This answer may be too late. but it will be useful for future readers.

这个答案可能为时已晚。但它对未来的读者很有用。

I have some criteria. I have coded for pick the file from intent. and selected file to be passed to particular fragment for further process. i have many fragments having the functionality of File picking. at the time , every time checking the condition and get the fragment and pass the value is quite disgusting. so , i have decided to pass the value using interface.

我有一些标准。我已经编码用于从意图中选择文件。和选定的文件要传递给特定片段以供进一步处理。我有许多具有文件选择功能的片段。当时,每次检查条件,获取片段并传递值都非常令人作呕。所以,我决定使用接口传递值。

Step 1:Create the interface on Main Activity.

步骤 1:在 Main Activity 上创建界面。

   public interface SelectedBundle {
    void onBundleSelect(Bundle bundle);
   }

Step 2:Create the SelectedBundle reference on the Same Activity

步骤 2:在同一活动上创建 SelectedBundle 引用

   SelectedBundle selectedBundle;

Step 3:create the Method in the Same Activity

第 3 步:在同一活动中创建方法

   public void setOnBundleSelected(SelectedBundle selectedBundle) {
       this.selectedBundle = selectedBundle;
   }

Step 4:Need to initialise the SelectedBundle reference which are all fragment need filepicker functionality.You place this code on your fragment onCreateView(..)method

第 4 步:需要初始化 SelectedBundle 引用,所有片段都需要文件选择器功能。您将此代码放在片段onCreateView(..)方法上

    ((MainActivity)getActivity()).setOnBundleSelected(new MainActivity.SelectedBundle() {
          @Override
         public void onBundleSelect(Bundle bundle) {
            updateList(bundle);
        }
     });

Step 5:My case, i need to pass the image Uri from HomeActivity to fragment. So, i used this functionality on onActivityResult method.

第 5 步:我的情况,我需要将图像 Uri 从 HomeActivity 传递到片段。所以,我在 onActivityResult 方法上使用了这个功能。

onActivityResult from the MainActivity, pass the values to the fragments using interface.

来自 MainActivity 的 onActivityResult,使用接口将值传递给片段。

Note:Your case may be different. you can call it from any where from your HomeActivity.

注意:您的情况可能有所不同。您可以从 HomeActivity 的任何位置调用它。

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent  data) {
       selectedBundle.onBundleSelect(bundle);
  }

Thats all. Implement every fragment you needed on the FragmentClass. You are great. you have done. WOW...

就这样。在 FragmentClass 上实现您需要的每个片段。你很棒。你已经完成了。哇...

回答by Pre_hacker

The best and convenient approach is calling fragment instance and send data at that time. every fragment by default have instance method

最好和方便的方法是调用片段实例并在那时发送数据。 默认情况下,每个片段都有实例方法

For example : if your fragment name is MyFragment

例如:如果您的片段名称是MyFragment

so you will call your fragment from activity like this :

所以你会从这样的活动中调用你的片段:

getSupportFragmentManager().beginTransaction().add(R.id.container, MyFragment.newInstance("data1","data2"),"MyFragment").commit();

*R.id.container is a id of my FrameLayout

*R.id.container 是我的 FrameLayout 的 id

so in MyFragment.newInstance("data1","data2")you can send data to fragment and in your fragment you get this data in MyFragment newInstance(String param1, String param2)

所以在MyFragment.newInstance("data1","data2")你可以将数据发送到片段,在你的片段中你可以在MyFragment newInstance(String param1, String param2) 中获得这些数据

public static MyFragment newInstance(String param1, String param2) {
        MyFragment fragment = new MyFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

and then in onCreatemethod of fragment you'll get the data:

然后在片段的onCreate方法中,您将获得数据:

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

so now mParam1 have data1and mParam2 have data2

now you can use this mParam1and mParam2in your fragment.

所以现在mParam1 有 data1mParam2 有 data2

现在你可以 在你的片段中使用这个mParam1mParam2

回答by diyoda_

Basic Idea of using Fragments (F) is to create reusable self sustaining UI components in android applications. These Fragments are contained in activities and there are common(best) way of creating communication path ways from A -> F and F-A, It is a must to Communicate between F-F through a Activity because then only the Fragments become decoupled and self sustaining.

使用 Fragments (F) 的基本思想是在 android 应用程序中创建可重用的自我维持的 UI 组件。这些片段包含在活动中,并且有从 A -> F 和 FA 创建通信路径方式的通用(最佳)方式,必须通过活动在 FF 之间进行通信,因为只有片段才会解耦并自我维持。

So passing data from A -> F is going to be the same as explained by ρяσ?ρ?я K. In addition to that answer, After creation of the Fragments inside an Activity, we can also pass data to the fragments calling methods in Fragments.

因此,从 A -> F 传递数据将与 ρяσ?ρ?я K 所解释的相同。除了那个答案,在 Activity 中创建 Fragments 之后,我们还可以将数据传递给调用方法的片段碎片。

For example:

例如:

    ArticleFragment articleFrag = (ArticleFragment)
                    getSupportFragmentManager().findFragmentById(R.id.article_fragment);
    articleFrag.updateArticleView(position);

回答by Adrian Stoica

I would like to add for the beginners that the difference between the 2 most upvoted answers here is given by the different use of a fragment.

我想为初学者补充一点,这里 2 个最受好评的答案之间的区别是由片段的不同使用引起的。

If you use the fragment within the java class where you have the data you want to pass, you can apply the first answer to pass data:

如果您在具有要传递的数据的 java 类中使用片段,则可以应用第一个答案来传递数据:

Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);

If however you use for example the default code given by Android Studio for tabbed fragments, this code will not work.

但是,如果您使用 Android Studio 为选项卡片段提供的默认代码,则此代码将不起作用。

It will not work even if you replace the default PlaceholderFragment with your FragmentClasses, and even if you correct the FragmentPagerAdapter to the new situation adding a switch for getItem() and another switch for getPageTitle() (as shown here)

如果你与你FragmentClasses替换默认PlaceholderFragment它甚至不会工作,即使你纠正FragmentPagerAdapter到)新形势下增加了对的getItem(开关和另一个开关getPageTitle()(如图所示这里

Warning: the clip mentioned above has code errors, which I explain later here, but is useful to see how you go from default code to editable code for tabbed fragments)! The rest of my answer makes much more sense if you consider the java classes and xml files from that clip (representative for a first use of tabbed fragments by a beginner scenario).

警告:上面提到的剪辑有代码错误,我稍后会在这里解释,但对于了解如何从默认代码变为选项卡片段的可编辑代码很有用)!如果您考虑该剪辑中的 java 类和 xml 文件(代表初学者场景首次使用选项卡片段),我的其余答案会更有意义。

The main reason the most upvoted answer from this page will not work is that in that default code for tabbed fragments, the fragments are used in another java class: FragmentPagerAdapter!

此页面上最受好评的答案不起作用的主要原因是,在选项卡式片段的默认代码中,这些片段用于另一个 Java 类:FragmentPagerAdapter!

So, in order to send the data, you are tempted to create a bundle in the MotherActivity and pass it in the FragmentPagerAdapter, using answer no.2.

因此,为了发送数据,您很想使用答案 2 在 MotherActivity 中创建一个包并将其传递到 FragmentPagerAdapter 中。

Only that is wrong again. (Probably you could do it like that, but it is just a complication which is not really needed).

只是那又错了。(也许你可以这样做,但这只是一个并不真正需要的并发症)。

The correct/easier way to do it, I think, is to pass the data directly to the fragment in question, using answer no.2. Yes, there will be tight coupling between the Activity and the Fragment, BUT, for tabbed fragments, that is kind of expected. I would even advice you to create the tabbed fragments inside the MotherActivity java class (as subclasses, as they will never be used outside the MotherActivity) - it is easy, just add inside the MotherActivity java class as many Fragments as you need like this:

我认为,正确/更简单的方法是使用答案 2 将数据直接传递给有问题的片段。是的,Activity 和 Fragment 之间会存在紧密耦合,但是,对于选项卡式片段,这是意料之中的。我什至建议您在 MotherActivity java 类中创建选项卡式片段(作为子类,因为它们永远不会在 MotherActivity 之外使用) - 这很容易,只需在 MotherActivity java 类中添加尽可能多的 Fragment,如下所示:

 public static class Tab1 extends Fragment {

    public Tab1() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
        return rootView;
    }
}.

So, to pass data from the MotherActivity to such a Fragment you will need to create private Strings/Bundles above the onCreate of your Mother activity - which you can fill with the data you want to pass to the fragments, and pass them on via a method created after the onCreate (here called getMyData()).

因此,要将数据从 MotherActivity 传递到这样的 Fragment,您需要在 Mother 活动的 onCreate 上方创建私有字符串/捆绑包 - 您可以填充要传递给片段的数据,并通过在 onCreate 之后创建的方法(此处称为 getMyData())。

public class MotherActivity extends Activity {

    private String out;
    private Bundle results;

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

       // for example get a value from the previous activity
        Intent intent = getIntent();
        out = intent.getExtras().getString("Key");

    }

    public Bundle getMyData() {
        Bundle hm = new Bundle();
        hm.putString("val1",out);
        return hm;
    }
}

And then in the fragment class, you use getMyData:

然后在片段类中,使用 getMyData:

public static class Tab1 extends Fragment {
        /**
         * The fragment argument representing the section number for this
         * fragment.
         */
        public Tab1() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
            TextView output = (TextView)rootView.findViewById(R.id.your_id_for_a_text_view_within_the_layout);

            MotherActivity activity = (MotherActivity)getActivity();

            Bundle results = activity.getMyData();
            String value1 = results.getString("val1");

            output.setText(value1);
            return rootView;
        }
    }

If you have database queries I advice you to do them in the MotherActivity (and pass their results as Strings/Integers attached to keys inside a bundle as shown above), as inside the tabbed fragments, your syntax will become more complex (this becomes getActivity() for example, and getIntent becomes getActivity().getIntent), but you have also the option to do as you wish.

如果您有数据库查询,我建议您在 MotherActivity 中执行它们(并将它们的结果作为字符串/整数附加到捆绑包内的键上,如上所示),因为在选项卡式片段中,您的语法将变得更加复杂(这变成了 getActivity () 例如,getIntent 变为 getActivity().getIntent),但您也可以选择随心所欲。

My advice for beginners is to focus on small steps. First, get your intent to open a very simple tabbed activity, without passing ANY data. Does it work? Does it open the tabs you expect? If not, why?

我对初学者的建议是专注于小步骤。首先,让您的意图打开一个非常简单的选项卡式活动,而不传递任何数据。它有效吗?它会打开您期望的标签吗?如果不是,为什么?

Start from that, and by applying solutions such as those presented in this clip, see what is missing. For that particular clip, the mainactivity.xml is never shown. That will surely confuse you. But if you pay attention, you will see that for example the context (tools:context) is wrong in the xml fragment files. Each fragment XML needs to point to the correct fragment class (or subclass using the separator $).

从那开始,通过应用本剪辑中介绍的解决方案,看看缺少什么。对于该特定剪辑,从未显示 mainactivity.xml。那肯定会让你感到困惑。但是如果你注意的话,你会发现例如xml片段文件中的上下文(工具:上下文)是错误的。每个片段 XML 都需要指向正确的片段类(或使用分隔符 $ 的子类)。

You will also see that in the main activity java class you need to add tabLayout.setupWithViewPager(mViewPager) - right after the line TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); without this line, your view is actually not linked to the XML files of the fragments, but it shows ONLY the xml file of the main activity.

您还将看到,在主活动 java 类中,您需要在 TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); 行之后添加 tabLayout.setupWithViewPager(mViewPager); 如果没有这一行,您的视图实际上不会链接到片段的 XML 文件,但它仅显示主要活动的 xml 文件。

In addition to the line in the main activity java class, in the main activity XML file you need to change the tabs to fit your situation (e.g. add or remove TabItems). If you do not have tabs in the main activity XML, then possibly you did not choose the correct activity type when you created it in the first place (new activity - tabbed activity).

除了主活动 java 类中的行之外,在主活动 XML 文件中,您需要更改选项卡以适合您的情况(例如添加或删除 TabItems)。如果您在主活动 XML 中没有选项卡,那么您可能在最初创建时没有选择正确的活动类型(新活动 - 选项卡式活动)。

Please note that in the last 3 paragraphs I talk about the video! So when I say main activity XML, it is the main activity XML in the video, which in your situation is the MotherActivity XML file.

请注意,在最后 3 段中我谈到了视频!所以当我说主要活动 XML 时,它是视频中的主要活动 XML,在您的情况下是 MotherActivity XML 文件。

回答by Martin

If you pass a reference to the (concrete subclass of) fragment into the async task, you can then access the fragment directly.

如果您将对片段(的具体子类)的引用传递到异步任务中,则可以直接访问该片段。

Some ways of passing the fragment reference into the async task:

将片段引用传递到异步任务的一些方法:

  • If your async task is a fully fledged class (class FooTask extends AsyncTask), then pass your fragment into the constructor.
  • If your async task is an inner class, just declare a final Fragment variable in the scope the async task is defined, or as a field of the outer class. You'll be able to access that from the inner class.
  • 如果您的异步任务是一个完全成熟的类 ( class FooTask extends AsyncTask),则将您的片段传递给构造函数。
  • 如果你的异步任务是一个内部类,只需在异步任务定义的范围内声明一个最终的 Fragment 变量,或者作为外部类的一个字段。您将能够从内部类访问它。

回答by sberezin

Very old post, still I dare to add a little explanation that would had been helpful for me.

很老的帖子,我仍然敢于添加一些对我有帮助的解释。

Technically you can directly set members of any type in a fragment from activity.
So why Bundle?
The reason is very simple - Bundle provides uniform way to handle:
-- creating/opening fragment
-- reconfiguration (screen rotation) - just add initial/updated bundle to outState in onSaveInstanceState()
-- app restoration after being garbage collected in background (as with reconfiguration).

从技术上讲,您可以直接在活动的片段中设置任何类型的成员。
那么为什么要捆绑呢?
原因很简单——Bundle 提供了统一的处理方式:
-- 创建/打开片段
-- 重新配置(屏幕旋转) -- 只需在 onSaveInstanceState() 中将初始/更新的 bundle 添加到 outState
-- 后台垃圾回收后的应用程序恢复(与重新配置一样)。

You can (if you like experiments) create a workaround in simple situations but Bundle-approach just doesn't see difference between one fragment and one thousand on a backstack - it stays simple and straightforward.
That's why the answer by @Elenasysis the most elegant and universal solution.
And that's why the answer given by @Martinhas pitfalls

你可以(如果你喜欢实验)在简单的情况下创建一个解决方法,但捆绑方法只是看不到一个片段和一个 backstack 上的一千个片段之间的区别 - 它保持简单明了。
这就是为什么@Elenasys的答案是最优雅和通用的解决方案。
这就是@Martin给出的答案存在缺陷的原因

回答by fralbo

Sometimes you can receive Intent in your activity and you need to pass the info to your working fragment.
Given answers are OK if you need to start the fragment but if it's still working, setArguments()is not very useful.
Another problem occurs if the passed information will cause to interact with your UI. In that case you cannot call something like myfragment.passData()because android will quickly tells that only the thread which created the view can interact with.

有时您可以在您的活动中接收 Intent,您需要将信息传递给您的工作片段。
如果您需要启动片段,给出的答案是可以的,但如果它仍在工作,setArguments()则不是很有用。
如果传递的信息会导致与您的 UI 交互,则会出现另一个问题。在这种情况下,你不能调用类似的东西,myfragment.passData()因为 android 会很快告诉只有创建视图的线程才能与之交互。

So my proposal is to use a receiver. That way, you can send data from anywhere, including the activity, but the job will be done within the fragment's context.

所以我的建议是使用接收器。这样,您可以从任何地方发送数据,包括活动,但工作将在片段的上下文中完成。

In you fragment's onCreate():

在你的片段中onCreate()

protected DataReceiver dataReceiver;
public static final String REC_DATA = "REC_DATA";

@Override
public void onCreate(Bundle savedInstanceState) {


    data Receiver = new DataReceiver();
    intentFilter = new IntentFilter(REC_DATA);

    getActivity().registerReceiver(dataReceiver, intentFilter);
}

private class DataReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        int data= intent.getIntExtra("data", -1);

        // Do anything including interact with your UI
    }
}

In you activity:

在你的活动中:

// somewhere
Intent retIntent = new Intent(RE_DATA);
retIntent.putExtra("data", myData);
sendBroadcast(retIntent);