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


316

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

Answers:


662

从“活动”中,您发送数据的意图是:

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

并在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);
}

15
您可以将对象传递给片段吗?
yeahman 2013年

63
嗯,我在致电时收到NullPointerExceptiongetArguments().getString(key)
Nima G

9
NullPointerException“字符串strtext setArguments()。getString(” edttext“);”
Jorgesys

4
在读取片段中的捆绑包内容时,始终总是先使用getArguments方法将该捆绑包接收到Bundle对象中,并检查其是否为null。否则,将在null上应用getString方法,因此将在没有传递捆绑的情况下将其应用于NPE。当不传递捆绑包时,这将避免空指针异常。
balachandarkm 2014年

3
@Aznix。不建议为片段创建构造函数。
Azam

108

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

活动:

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;
    }
}

分段:

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;
    }
}

78
该解决方案集成了您的活动和Fragment之间的紧密耦合,更好地使用Bundle类传递信息。或者,您可以使该getMyData()方法从接口继承并实现,并Fragment检查getActivity是否instanceof在中返回接口onAttach()
Rudi Kershaw

1
此解决方案最适合我。此外,如果MyString的是公开的,你没有申报getMyData()方法
布拉克Öztürk的

1
当前接受的答案返回空指针异常。这应该是公认的答案
列治文

9
这应该不会是公认的答案。紧密的连接很容易避免。这通常是一个坏主意,并且会使片段无用,如果您仅将其与活动绑定使用,那么片段也可能没有。该片段不能在其他活动中重用。
Martin Marconcini

51

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

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

活动:

        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();

分段:

读取片段中的值

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

要不就

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

我猜这不是更新嵌套在Fragment中的ListView中的onQueryTextSubmit-search-results的最佳方法(如果sommbody快速键入,他将每秒发送args两次)?
Martin Pfeffer 2015年

1
插入字符串或整数的对象呢?
达里奥

2
@Jorgesys这个解决方案如何?developer.android.com/training/basics/fragments/...
yozhik

23

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

我有一些标准。我已经编码为从意图中选择文件。并将选定的文件传递到特定片段以进行进一步处理。我有许多具有文件选取功能的片段。当时,每次检查条件并获取片段通过值都是相当恶心的。因此,我决定使用接口传递值。

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

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

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

   SelectedBundle selectedBundle;

步骤3:在相同活动中创建方法

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

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

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

步骤5:我的情况是,我需要将图像Uri从HomeActivity传递到片段。因此,我在onActivityResult方法上使用了此功能。

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

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

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

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


15

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

因此,从A-> F传递数据将与ρяσsρєяK解释的相同。除了该答案外,在Activity内部创建了Fragments之后,我们还可以将数据传递给Fragments中的Fragments调用方法。

例如:

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


15

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

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

因此您将通过以下活动调用片段:

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

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

因此,在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;
    }

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

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

所以现在mParam1具有data1mParam2具有data2

现在您可以 在片段中使用此mParam1mParam2了。


R.id.container在这里是什么?你的意思是R.id.container_current这是一个int值。
shaurya uppal

@s * R.id.container是我的FrameLayout的ID
Pre_hacker

到目前为止,我发现的最好的解释是使用“片段管理器”在添加/替换片段上传递数据。像宝石一样工作!谢谢!
sam,

使用了R.id.nav_host_fragment而不是R.id.container
Hany

10

我想为初学者补充一点,此处两个最受好评的答案之间的差异是由片段的不同用法引起的。

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

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

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

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

警告:上面提到的剪辑存在代码错误,我将在后面在此处进行解释,但是对于查看如何从默认代码转到选项卡式片段的可编辑代码很有用)!如果您考虑该剪辑中的java类和xml文件,则剩下的答案将更有意义(代表初学者场景中首次使用选项卡式片段)。

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

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

只是那又是错的。(也许您可以那样做,但这只是一个复杂的操作,实际上并不需要)。

我认为,正确/简便的方法是使用2号答案将数据直接传递给相关片段。是的,对于选项卡式片段,活动与片段之间会紧密结合,这是预料之中的。我什至建议您在MotherActivity java类内创建选项卡式片段(作为子类,因为它们永远不会在MotherActivity外使用)-很简单,只需在MotherActivity java类内添加所需的多个片段,如下所示:

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

因此,要将数据从MotherActivity传递到这样的片段,您将需要在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;
    }
}

然后在fragment类中,使用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;
        }
    }

如果您有数据库查询,我建议您在MotherActivity中进行查询(并将它们的结果作为附加到捆绑包内键的字符串/整数传递,如上所示),就像在选项卡式片段中一样,您的语法将变得更加复杂(这将成为getActivity (),而getIntent变为getActivity()。getIntent),但您也可以选择执行自己的操作。

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

从此开始,并通过应用解决方案(如本剪辑中介绍的解决方案),了解缺少的内容。对于该特定剪辑,永远不会显示mainactivity.xml。那肯定会让您感到困惑。但是如果您注意的话,您会看到例如xml片段文件中的上下文(tools:context)错误。每个片段XML需要指向正确的片段类(或使用分隔符$的子类)。

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

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

请注意,在最后三段中,我将介绍视频!因此,当我说主要活动XML时,它就是视频中的主要活动XML,在您的情况下,它就是MotherActivity XML文件。


8

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

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

  • 如果您的异步任务是完全成熟的类(class FooTask extends AsyncTask),则将您的片段传递到构造函数中。
  • 如果您的异步任务是一个内部类,只需在定义异步任务的范围内声明一个最终的Fragment变量,或者将其声明为外部类的字段。您将可以从内部类访问它。

您的回答对我来说似乎很合法,您可以通过提供一些示例代码来扩展更多内容吗?
莱昂·阿姆斯特朗

6

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

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

在您的片段中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
    }
}

在您的活动中:

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

5

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

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

您可以(如果喜欢实验的话)在简单的情况下创建解决方法,但Bundle-approach只是看不到一个片段和一千个片段在后退堆栈上的区别-它保持简单明了。
这就是@Elenasys给出的答案是最优雅,最通用的解决方案的原因。
这就是@Martin给出的答案存在陷阱的原因


4

从活动类向片段发送数据的更好方法是通过setter方法传递。喜欢

FragmentClass fragmentClass = new FragmentClass();
fragmentClass.setMyList(mylist);
fragmentClass.setMyString(myString);
fragmentClass.setMyMap(myMap);

并从课堂上轻松获取这些数据。


如何将数据从一个片段传递到
另一个

这不,当你也沿等,以前设置额外的传球非常方便
杰拉德

如果您需要将数据设置为片段中的某个字段,并且尚不可见(初始化),则会得到NPE。
yozhik '18


我大概3年前就停止使用Android,这些天可能已经过时了。
ssi-anik

4

Activity您使用Bundle将数据发送为:

Bundle bundle = new Bundle();
bundle.putString("data", "Data you want to send");

// Your fragment
MyFragment obj = new MyFragment();
obj.setArguments(bundle);

并在FragmentonCreateView方法中获取数据:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
{
    String data = getArguments().getString("data");// data which sent from activity  
    return inflater.inflate(R.layout.myfragment, container, false);
}

3

如果activity需要fragment在初始化后执行一个动作,最简单的方法是activityfragment实例上调用一个方法。在中fragment,添加方法:

public class DemoFragment extends Fragment {
  public void doSomething(String param) {
      // do something in fragment
  }
}

然后在中activityfragment使用fragment管理器访问并调用method

public class MainActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DemoFragment fragmentDemo = (DemoFragment) 
            getSupportFragmentManager().findFragmentById(R.id.fragmentDemo);
        fragmentDemo.doSomething("some param");
    }
}

然后activity可以fragment通过调用this 与进行直接通信method


1
在您不想onCreateView在片段中输入方法的意义上,这真的很好。真的很有帮助
Young Emil

2

使用以下接口在活动和片段之间进行通信

public interface BundleListener {
    void update(Bundle bundle);
    Bundle getBundle();
}

或者使用以下通用侦听器进行使用接口的双向通信

 /**
 * Created by Qamar4P on 10/11/2017.
 */
public interface GenericConnector<T,E> {
    T getData();
    void updateData(E data);
    void connect(GenericConnector<T,E> connector);
}

片段显示方法

public static void show(AppCompatActivity activity) {
        CustomValueDialogFragment dialog = new CustomValueDialogFragment();
        dialog.connector = (GenericConnector) activity;
        dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
    }

你可以投你的上下文GenericConnectoronAttach(Context)

在你的活动中

CustomValueDialogFragment.show(this);

在你的片段中

...
@Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        connector.connect(new GenericConnector() {
            @Override
            public Object getData() {
                return null;
            }

            @Override
            public void updateData(Object data) {

            }

            @Override
            public void connect(GenericConnector connector) {

            }
        });
    }
...
    public static void show(AppCompatActivity activity, GenericConnector connector) {
            CustomValueDialogFragment dialog = new CustomValueDialogFragment();
            dialog.connector = connector;
            dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
        }

注意:切勿使用它"".toString().toString().toString();


2

只是偶然发现了这个问题,而上面的大多数方法都可以使用。我只想补充一下,您可以使用事件总线库,尤其是在尚未创建组件(活动性或片段)的情况下,它适用于所有大小的android项目和许多用例。我曾在Playstore的多个项目中亲自使用过它。


1

您可以在片段中创建公共静态方法,在该片段中,您将获取该片段的静态引用,然后将数据传递给该函数,并将该数据设置为同一方法中的参数,并通过片段的oncreate方法上的getArgument获取数据,并将该数据设置为local变量。


1

在片段和活动之间传递数据的最明智的尝试和测试方法是创建变量,例如:

class StorageUtil {
  public static ArrayList<Employee> employees;
}

然后,将数据从片段传递到活动,我们在onActivityCreated方法中进行操作:

//a field created in the sending fragment
ArrayList<Employee> employees;

@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
         employees=new ArrayList();

       //java 7 and above syntax for arraylist else use employees=new ArrayList<Employee>() for java 6 and below

     //Adding first employee
        Employee employee=new Employee("1","Andrew","Sam","1984-04-10","Male","Ghanaian");
        employees.add(employee);

      //Adding second employee
       Employee employee=new Employee("1","Akuah","Morrison","1984-02-04","Female","Ghanaian");
         employees.add(employee);

        StorageUtil.employees=employees;
    }

现在,您可以从任何地方获得StorageUtil.employees的价值。祝好运!


0

我的解决方案是在片段中编写一个静态方法:

public TheFragment setData(TheData data) {
    TheFragment tf = new TheFragment();
    tf.data = data;
    return tf;
}

这样,我可以确定所需的所有数据都在Fragment中,然后再执行其他可能需要使用的操作。我认为它也看起来更干净。


1
好吧,如果TheData不是线程安全的,将其设置为静态不一定会保护您免受线程问题的影响。小心点。静态本质上不是线程安全的。
Martin Marconcini'2

0

在使用最新的导航架构组件时,我遇到了类似的问题。通过将捆绑包从我的调用活动传递到Fragment来试用所有上述代码。

遵循Android最新发展趋势的最佳解决方案是使用View Model(Android Jetpack的一部分)。

在父Activity中创建和初始化ViewModel类,请注意,该ViewModel必须在Activity和片段之间共享。

现在,在片段的onViewCreated()内部,初始化相同的ViewModel并设置观察者以侦听ViewModel字段。

如果需要,这是一个有用的深入教程。

https://medium.com/mindorks/how-to-communicate-between-fragments-and-activity-using-viewmodel-ca733233a51c


-4

在您的活动中声明静态变量

public static HashMap<String,ContactsModal> contactItems=new HashMap<String, ContactsModal>();

然后在您的片段中执行以下操作

ActivityName.contactItems.put(Number,contactsModal);

它可以工作,但不推荐。由于静态成员将保留在内存中,除非从最近使用的应用程序强行关闭了该应用程序。因此,在这种情况下,您仅应在整个应用程序的许多活动中需要静态成员时才使用它。
M Shaban Ali
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.