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

我有两门课。第一个是活动,第二个是一个片段,其中有一些EditText。在活动中,我有一个带有async-task的子类,在方法doInBackground中,我得到了一些结果,我保存到变量中。我怎么能把这个变量从子类“我的活动”到这个片段?

581050 次浏览

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

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

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

从Activity中发送数据,意图如下:

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

我在这里@ 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");
...
...
...
}

你也可以从片段访问活动数据:

活动:

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;
}
}
很老的帖子,但我仍然敢补充一点解释,这对我来说是有帮助的 从技术上讲,你可以直接从activity中设置fragment中任何类型的成员 那么为什么是Bundle呢?< br > 原因很简单——Bundle提供了统一的处理方式:
——创建/打开片段
——重新配置(屏幕旋转)-只需在onSaveInstanceState()
中添加初始/更新的bundle到outState ——应用程序在后台垃圾回收后恢复(与重新配置一样) 你可以(如果你喜欢实验的话)在简单的情况下创建一个变通方案,但是bundle方法只是看不到一个片段和备份堆栈上的一千个片段之间的区别——它保持简单和直接。这就是为什么@Elenasys的答案是最优雅和通用的解决方案。这就是为什么@Martin给出的答案有陷阱

使用Fragments (F)的基本想法是在android应用程序中创建可重用的自我维持UI组件。这些片段包含在活动中,有常见的(最好的)方法来创建从A -> F和F-A的通信路径,这是必须通过一个活动在F-F之间进行通信,因为这样只有片段变得解耦和自我维持。

因此,从A -> F传递数据将是相同的ρ σ η η K.除了这个答案,在一个活动内创建Fragments之后,我们还可以将数据传递给Fragments调用Fragments中的方法。

例如:

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

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

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

然后在activity中,使用fragment管理器访问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可以通过调用这个method直接与fragment通信。

将数据从活动类发送到片段的更好方法是通过setter方法传递。像

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

并且很容易从类中获得这些数据。

你可以在fragment中创建公共静态方法,在那里你将获得该fragment的静态引用,然后将数据传递给该函数,并将该数据设置为相同方法的参数,并通过getArgument获取fragment的oncreate方法的数据,并将该数据设置为局部变量。

在片段和活动之间传递数据的最聪明的方法是创建一个变量,例如:

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

然后通过onActivityCreated方法将数据从fragment传递给activity:

//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的值。来自各地的员工。 古德勒克!< / p >

Activity中,你用Bundle发送数据为:

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


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

并在Fragment onCreateView方法中获取数据:

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

这个答案可能太迟了。但它对未来的读者是有用的。

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

在主活动上创建接口。

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

步骤2:在同一个Activity上创建selectebundle引用

   SelectedBundle selectedBundle;

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

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

步骤4:需要初始化selectebundle引用,这些引用都是fragment Need filepicker功能。你把这个代码放在你的fragment onCreateView(..)方法上

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

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

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

你的情况可能不同。你可以从你的HomeActivity的任何地方调用它。

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

这一切。在FragmentClass上实现你需要的每个片段。你很棒。你做到了。哇……

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

public TheFragment setData(TheData data) {
TheFragment tf = new TheFragment();
tf.data = data;
return tf;
}
这样我就可以确保我需要的所有数据在任何其他可能需要使用它的操作之前都在片段中。 而且在我看来,它看起来更干净
最好和方便的方法是调用片段实例并发送数据。 每个片段默认都有实例方法

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

所以你会像这样调用你的fragment from activity:

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

* R.id。container是我的框架布局的id

所以在MyFragment.newInstance(“data1”、“data2”)中,你可以将数据发送到fragment,在你的fragment中,你可以在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;
}

然后在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有数据2

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

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

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

在你片段的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);

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

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

你也可以在onAttach(Context)中将你的上下文转换为GenericConnector

在你的活动中

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();那样使用它。

我想为初学者补充一点,这里被点赞最多的两个答案之间的差异是由不同的片段使用所给出的。

如果你在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传递到这样一个Fragment,你需要在你的Mother activity的onCreate上面创建私有的Strings/Bundles -你可以填充你想传递给Fragment的数据,并通过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片段文件中的context (tools:context)是错误的。每个片段XML都需要指向正确的片段类(或使用分隔符$的子类)。

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

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

请注意,我在最后3段中谈到了视频!我说的主活动XML,就是视频中的主活动XML,也就是MotherActivity XML文件。

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

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

然后在你的片段中像这样做

ActivityName.contactItems.put(Number,contactsModal);

我在使用最新的导航体系结构组件时遇到了类似的问题。通过从我的调用活动传递一个包到Fragment,尝试了上述所有代码。

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

在父Activity中创建并初始化一个ViewModel类,请注意这个ViewModel必须在Activity和fragment之间共享。

现在,在片段的onViewCreated()中,初始化相同的ViewModel并设置观察者来监听ViewModel字段。

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

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

只是偶然发现了这个问题,而上面的大多数方法都是有效的。 我只是想补充一点,你可以使用事件总线库,特别是在组件(Activity或Fragment)还没有创建的情况下,它适用于所有规模的android项目和许多用例。我个人在我在playstore上的几个项目中使用过它

你可以在片段中创建一个setter方法。然后在Activity中,当引用片段时,调用setter方法并将Activity中的数据传递给它

芬兰湾的科特林版本:

Activity:

val bundle = Bundle()
bundle.putBoolean("YourKey1", true)
bundle.putString("YourKey2", "YourString")


val fragment = YourFragment()
fragment.arguments = bundle
val fragmentTransaction = parentFragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.your_container, fragment, fragment.toString())
fragmentTransaction.commit()

Fragment onCreate()中:

var value1 = arguments?.getBoolean("YourKey1", default true/false)
var value2 = arguments?.getString("YourKey2", "Default String")