我有两节课。首先是活动,其次是我有一些EditText
. 在活动中,我有一个带有异步任务的子类,在方法中doInBackground
我得到了一些结果,我将其保存到变量中。如何将这个变量从子类“我的活动”发送到这个片段?
22 回答
从 Activity 你发送数据的意图是:
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
并在片段 onCreateView 方法中:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String strtext = getArguments().getString("edttext");
return inflater.inflate(R.layout.fragment, container, false);
}
您还可以从片段访问活动数据:
活动:
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;
}
}
我在这里@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");
...
...
...
}
这个答案可能为时已晚。但它对未来的读者很有用。
我有一些标准。我已经编码从意图中选择文件。并将选定的文件传递给特定片段以进行进一步处理。我有许多具有文件选择功能的片段。当时,每次检查条件并获取片段并传递值是非常恶心的。所以,我决定使用接口传递值。
步骤 1:在 Main Activity 上创建界面。
public interface SelectedBundle {
void onBundleSelect(Bundle bundle);
}
第 2 步:在同一 Activity 上创建 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 上实现您需要的每个片段。你很棒。你已经完成了。哇...
最好和方便的方法是调用片段实例并在那时发送数据。 默认情况下,每个片段都有实例方法
例如:如果您的片段名称是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 有 data1而mParam2 有 data2
现在您可以在片段中使用这个mParam1和mParam2 。
使用 Fragments (F) 的基本思想是在 android 应用程序中创建可重用的自维持 UI 组件。这些片段包含在活动中,并且有从 A -> F 和 FA 创建通信路径方式的常见(最佳)方式,必须通过活动在 FF 之间进行通信,因为只有片段才会解耦和自我维持。
因此,从 A -> F 传递数据将与 ρяσѕρєя K 所解释的相同。除了那个答案之外,在 Activity 中创建 Fragments 之后,我们还可以将数据传递给 Fragments 中调用方法的 Fragment。
例如:
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
articleFrag.updateArticleView(position);
我想为初学者补充一点,这里两个最受好评的答案之间的区别是由片段的不同使用给出的。
如果您在具有要传递数据的 java 类中使用片段,则可以应用第一个答案来传递数据:
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
但是,如果您使用例如 Android Studio 为选项卡式片段提供的默认代码,则此代码将不起作用。
即使您将默认 PlaceholderFragment 替换为 FragmentClasses,它也不起作用,即使您将 FragmentPagerAdapter 更正为新情况,为 getItem() 添加一个开关,为 getPageTitle() 添加另一个开关(如此处所示)
警告:上面提到的剪辑有代码错误,我稍后会在这里解释,但有助于了解如何从默认代码变为选项卡式片段的可编辑代码)!如果您考虑该剪辑中的 java 类和 xml 文件(代表初学者场景首次使用选项卡式片段),我的其余答案会更有意义。
此页面上最受好评的答案不起作用的主要原因是,在选项卡式片段的默认代码中,片段在另一个 java 类中使用:FragmentPagerAdapter!
因此,为了发送数据,您很想在 MotherActivity 中创建一个包并将其传递给 FragmentPagerAdapter,使用答案 2。
只是那又错了。(也许你可以这样做,但这只是一个并不真正需要的并发症)。
我认为,正确/更简单的方法是使用答案 2 将数据直接传递给相关片段。是的,Activity 和 Fragment 之间会有紧密的耦合,但是对于选项卡式 Fragment,这是意料之中的。我什至建议您在 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 活动的 onCreate 上方创建私有字符串/捆绑包 - 您可以填充要传递给 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;
}
}
然后在片段类中,使用 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 = (TabLayout) findViewById(R.id.tabs); 行之后 没有这一行,您的视图实际上并没有链接到片段的 XML 文件,但它只显示主要活动的 xml 文件。
除了主活动java 类中的行之外,在主活动XML 文件中,您需要更改选项卡以适合您的情况(例如添加或删除TabItems)。如果您在主活动 XML 中没有选项卡,那么您可能在最初创建它时没有选择正确的活动类型(新活动 - 选项卡式活动)。
请注意,在最后 3 段中,我谈到了视频!所以当我说主要活动 XML 时,它是视频中的主要活动 XML,在您的情况下是 MotherActivity XML 文件。
如果您将片段(的具体子类)的引用传递给异步任务,则可以直接访问片段。
将片段引用传递到异步任务的一些方法:
- 如果您的异步任务是一个成熟的类 (
class FooTask extends AsyncTask
),则将您的片段传递给构造函数。 - 如果你的异步任务是一个内部类,只需在定义异步任务的范围内声明一个最终的 Fragment 变量,或者作为外部类的一个字段。您将能够从内部类访问它。
从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);
}
有时您可以在活动中收到 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);
很老的帖子,我仍然敢于添加一些对我有帮助的解释。
从技术上讲,您可以直接在活动的片段中设置任何类型的成员。
那么为什么要捆绑呢?
原因很简单 - Bundle 提供了统一的处理方式:
-- 创建/打开片段
-- 重新配置(屏幕旋转) - 只需在 onSaveInstanceState() 中将初始/更新的 bundle 添加到 outState
-- 后台垃圾收集后的应用程序恢复(与重新配置一样)。
您可以(如果您喜欢实验)在简单的情况下创建一个解决方法,但 Bundle-approach 只是看不出一个片段和一千个片段之间的区别 - 它保持简单明了。
这就是为什么@Elenasys的答案是最优雅和通用的解决方案。
这就是为什么@Martin给出的答案有陷阱
如果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");
}
}
然后可以通过调用 thisactivity
直接与 通信。fragment
method
将数据从活动类发送到片段的更好方法是通过 setter 方法传递。像
FragmentClass fragmentClass = new FragmentClass();
fragmentClass.setMyList(mylist);
fragmentClass.setMyString(myString);
fragmentClass.setMyMap(myMap);
并轻松地从课堂上获取这些数据。
使用以下接口在活动和片段之间进行通信
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");
}
你也可以将你的上下文投射GenericConnector
到onAttach(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();
这样使用它。
只是偶然发现了这个问题,而上面的大多数方法都可以。我只想补充一点,您可以使用Event Bus Library,尤其是在尚未创建组件(Activity 或 Fragment)的情况下,它适用于各种规模的 android 项目和许多用例。我个人在 Playstore 上的几个项目中使用过它。
您可以在片段中创建公共静态方法,您将在其中获取该片段的静态引用,然后将数据传递给该函数并将该数据设置为同一方法中的参数,并通过片段的 oncreate 方法上的 getArgument 获取数据,并将该数据设置为本地变量。
我在使用最新的导航架构组件时遇到了类似的问题。通过将包从我的调用活动传递到片段来尝试所有上述代码。
遵循 Android 最新发展趋势的最佳解决方案是使用 View Model(Android Jetpack 的一部分)。
在父 Activity 中创建并初始化一个 ViewModel 类,请注意这个 ViewModel 必须在 Activity 和 Fragment 之间共享。
现在,在片段的 onViewCreated() 中,初始化相同的 ViewModel 并设置观察者来监听 ViewModel 字段。
如果您需要,这是一个有用的、深入的教程。
在片段和活动之间传递数据的最聪明的尝试和测试方法是创建一个变量,例如:
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 的值。祝你好运!
我的解决方案是在片段中编写一个静态方法:
public TheFragment setData(TheData data) {
TheFragment tf = new TheFragment();
tf.data = data;
return tf;
}
这样,我确信我需要的所有数据都在 Fragment 中,然后再进行任何其他可能需要使用它的操作。在我看来,它看起来更干净。
您可以在片段中创建一个 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")
在您的活动中声明静态变量
public static HashMap<String,ContactsModal> contactItems=new HashMap<String, ContactsModal>();
然后在你的片段中做如下
ActivityName.contactItems.put(Number,contactsModal);