我怎样能在一个碎片和它的容器活动(activity)之间传递数据?有没有类似于通过意图(intents) 在活动(activity)之间传递数据的方法?
我阅读了这篇文章,但没有帮助:
http://developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity
我怎样能在一个碎片和它的容器活动(activity)之间传递数据?有没有类似于通过意图(intents) 在活动(activity)之间传递数据的方法?
我阅读了这篇文章,但没有帮助:
http://developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity
尝试使用接口。
任何需要将数据传递回其包含的活动的片段都应声明一个接口来处理和传递数据。然后确保您的包含的活动实现这些接口。例如:
JAVA
在您的片段中,声明接口...
public interface OnDataPass {
public void onDataPass(String data);
}
然后,在 containing class 的 onAttach 方法中将其对接口的实现与片段相连接,如下所示:
OnDataPass dataPasser;
@Override
public void onAttach(Context context) {
super.onAttach(context);
dataPasser = (OnDataPass) context;
}
在你的片段中,当你需要处理数据传递时,只需在dataPasser对象上调用它:
public void passData(String data) {
dataPasser.onDataPass(data);
}
最后,在实现了 OnDataPass
接口的包含活动中...
@Override
public void onDataPass(String data) {
Log.d("LOG","hello " + data);
}
KOTLIN
第一步:创建接口
interface OnDataPass {
fun onDataPass(data: String)
}
第二步,然后在onAttach方法(YourFragment)中将包含类的接口实现与片段连接起来,如下所示:
lateinit var dataPasser: OnDataPass
override fun onAttach(context: Context) {
super.onAttach(context)
dataPasser = context as OnDataPass
}
第三步。在您的片段内,当您需要处理数据传递时,只需在 dataPasser 对象上调用它:
fun passData(data: String){
dataPasser.onDataPass(data)
}
第四步。最后,在您的活动中实现OnDataPass。
class MyActivity : AppCompatActivity(), OnDataPass {}
override fun onDataPass(data: String) {
Log.d("LOG","hello " + data)
}
在你的片段中,你可以调用getActivity()
。
这将让你访问创建该片段的活动。从那里,你可以显然地调用任何在活动中的访问方法。
例如,对于在你的活动中称为getResult()
的方法:
((MyActivity) getActivity()).getResult();
最简单但不推荐的方法
您可以从片段中访问活动数据:
活动:
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;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle b = getActivity().getIntent().getExtras();
wid = b.getString("wid");
rid = b.getString("rid");
View view = inflater.inflate(R.layout.categoryfragment, container, false);
return view;
}
在片段和其宿主活动之间传递数据
活动:
Bundle bundle = new Bundle();
bundle.putString("message", "Alo Elena!");
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) {
String myValue = this.getArguments().getString("message");
...
...
...
}
Bundle gameData = new Bundle();
gameData.putStringArrayList(Constant.KEY_PLAYERS_ARR,players);
gameData.putString(Constant.KEY_TEAM_NAME,custom_team_name);
gameData.putInt(Constant.KEY_REQUESTED_OVER,requestedOver);
Intent intent = getActivity().getIntent();
intent.putExtras(gameData);
// 从容器活动中的捆绑包获取数据。
Bundle gameData = getIntent().getExtras();
if (gameData != null)
{
int over = gameData.getInt(Constant.KEY_REQUESTED_OVER);
ArrayList<String> players = gameData.getStringArrayList(Constant.KEY_PLAYERS_ARR);
String team = gameData.getString(Constant.KEY_TEAM_NAME);
}
else if (gameData == null)
{
Toast.makeText(this, "Bundle is null", Toast.LENGTH_SHORT).show();
}
接口是最好的解决方案之一:
Glue 接口:
public interface DataProviderFromActivity {
public String getName();
public String getId);
}
我的活动:
public class MyActivity implements DataProviderFromActivity{
String name = "Makarov";
String id = "sys533";
... ... ... ... ... .... ....
... ... ... ... ... .... ....
public String getName(){
return name;
};
public String getId(){
return id;
};
}
我的碎片:
public class MyFragment extends Fragment{
String fragName = "";
String fragId = "";
... ... ... ... ... .... ....
... ... ... ... ... .... ....
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
DataProviderFromActivity myActivity= (DataProviderFromActivity) getActivity();
fragName = myActivity.getName();
fragId = myActivity.getId();
... ... ... ... ... .... ....
... ... ... ... ... .... ....
updateFragmentView();
}
}
你可以简单地使用EventBus,它易于使用且效果很好。
使用EventBus只需3步
定义事件:
public static class MessageEvent { /* 如果需要,可以添加其他字段 */ }
准备订阅者:声明并注释您的订阅方法, 可选择指定线程模式:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* 执行某些操作 */};
注册和取消注册您的订阅者。例如,在Android上, 活动和片段通常应根据其生命周期进行注册:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
发布事件:
EventBus.getDefault().post(new MessageEvent());
我使用了一个实现了日期监听器的AppCompatActivity。由于我需要编写一个日期范围选择器,所以必须使用Fragment。我还需要容器来接收选定的日期并将它们返回给父活动。
对于容器活动,这是类声明:
public class AppCompatDateRange extends AppCompatActivity implements
DateIniRangeFragment.OnDateIniSelectedListener, DateFimRangeFragment.OnDateFimSelectedListener
回调函数的接口:
@Override
public void onDateIniSelected(String dataIni) {
Log.i("data inicial:", dataIni);
}
@Override
public void onDateFimSelected(String dataFim) {
Log.i("data final:", dataFim);
}
public class DateIniRangeFragment extends Fragment {
OnDateIniSelectedListener callbackIni;
private DatePicker startDatePicker;
public DateIniRangeFragment() {
///required empty constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
///through this interface the fragment sends data to the container activity
public interface OnDateIniSelectedListener {
void onDateIniSelected(String dataIni);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
///layout for the fragment
View v = inflater.inflate(R.layout.date_ini_fragment, container, false);
///initial date for the picker, in this case, current date
startDatePicker = (DatePicker) v.findViewById(R.id.start_date_picker_appcompat);
Calendar c = Calendar.getInstance();
int ano = c.get(Calendar.YEAR);
int mes = c.get(Calendar.MONTH);
int dia = c.get(Calendar.DAY_OF_MONTH);
startDatePicker.setSpinnersShown(false);
startDatePicker.init(ano, mes, dia, dateSetListener);
return v;
}
///listener that receives the selected date
private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() {
public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
if (view.isShown()) { ///if the datepicker is on the screen
String sDataIni = year + "-" + (monthOfYear + 1) + "-" + dayOfMonth;
callbackIni.onDateIniSelected(sDataIni); //apply date to callback, string format
}
}
};
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
/*
* this function guarantees that the container activity implemented the callback interface
* */
try {
callbackIni = (OnDateIniSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " deve implementar OnDateIniSelectedListener");
}
}
为了组合容器和片段,我使用了一个扩展了FragmentPagerAdapter的自定义类配合ViewPager(AppCompat)来实现,没有使用对话框。
来自谷歌官方指南:
从Fragment 1.3.0-alpha04开始,每个FragmentManager都实现了FragmentResultOwner。这意味着一个FragmentManager可以作为fragment结果的中央存储库。这个变化允许组件通过设置fragment结果并监听这些结果来相互通信,而不需要这些组件直接引用彼此。
在Fragment中: 子fragment在其FragmentManager上设置结果。一旦fragment启动,父fragment就会收到结果:
button.setOnClickListener {
val result = "result"
// Use the Kotlin extension in the fragment-ktx artifact
setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportFragmentManager
.setFragmentResultListener("requestKey", this) { requestKey, bundle ->
// We use a String here, but any type that can be put in a Bundle is supported
val result = bundle.getString("bundleKey")
// Do something with the result
}
}
}