如何将参数从 MasterActivity 传递到 DetailActivity 的 NavigationDrawerFragment?
How to pass Argument from MasterActivity to DetailActivity's NavigationDrawerFragment?
TL;DR 版本:
在Android master-detail 模式中,如何让MasterActivity 传递一个值给DetailFragment 的parent activity (DetailActivity)?因为DetailActivity是存放NavigationDrawerFragment的文件。
我考虑过的事情:
- 回调(我不知道它是如何工作的)
- 使用 getActivity() 并调用父 activity 上的函数来传递参数。似乎较少 "clean" 的解决方案并且高度耦合。
有更好的方法吗?
长版
我有一个主从模式,但细节已更改,因此 "up" 按钮不再返回到主列表,而是打开一个导航抽屉。
现在,我有 "dummy" 代码,所以我的导航抽屉有 3 个项目,当您第一次单击主列表中的项目时,它们都会打开同一个页面。
我的主要问题是:主列表可以将 SongDetailFragment.ARG_ITEM_ID
参数传递给详细信息,但导航抽屉无法访问 SongDetailFragment.ARG_ITEM_ID
参数 SongDetailFragment.java,因为抽屉导航是在SongDetailActivity.java.
中实现的
主列表通过 detailIntent.putExtra(SongDetailFragment.ARG_ITEM_ID, id);
行将参数传递给详细信息 片段
:
SongListActivity.java
/**
* Callback method from {@link SongListFragment.Callbacks}
* indicating that the item with the given ID was selected.
*/
@Override
public void onItemSelected(String id) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(SongDetailFragment.ARG_ITEM_ID, id);
SongDetailFragment fragment = new SongDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.songlist_detail_container, fragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, SongDetailActivity.class);
detailIntent.putExtra(SongDetailFragment.ARG_ITEM_ID, id); //<-------- Argument
startActivity(detailIntent);
}
}
但是当我单击导航抽屉中的 3 个虚拟选项之一时,我无法传递该参数,因为导航抽屉位于 SongDetailActivity.java。
SongDetailActivity.java
//---------- NAVIGATION DRAWER -------------
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.songlist_detail_container, PlaceholderFragment.newInstance(position + 1))
.commit();
}
我尝试将此代码从 SongDetailFragment.java 的 onCreate 方法复制并粘贴到 SongDetailActivity.java 的 onCreate 方法中,希望我可以从 SongDetail[ 访问相同的 SongDetailFragment.ARG_ITEM_ID
变量Activity,但有Cannot resolve getArguments()
等编译错误。后来才知道Master在Fragment里只有"putting an extra",而不是Activity.
SongDetailFragment.java
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
if (getArguments().containsKey(ARG_ITEM_ID)) {
// Load the dummy title specified by the fragment
// arguments. In a real-world scenario, use a Loader
// to load title from a title provider.
mItem = SongItem.ITEM_MAP.get(getArguments().getString(ARG_ITEM_ID));
}
}
所以,我需要一些方法让导航抽屉 存储来自 Master 的 SongDetailFragment.ARG_ITEM_ID
变量,这样它就可以从模型中为每个视图获取正确的数据。 我该怎么做?
Shared Preferences? 我考虑过使用共享首选项,但我认为这是个坏主意,因为离开 [=] 的所有用例都很难擦除数据91=]。我想我需要比这更不全球化的东西。最好是,如果我能让 Master 将参数传递给 SongDetailActivity(并最终传递给 Navigation Drawer),那就完美了!
Callbacks? 我正在查看我的代码文件以考虑一些事情,我发现了这个 "callback" 由 Android Studio's Master 生成的东西- 细节向导。当它说 "This mechanism allows activities to be notified of item selections," 时听起来很适用,但我不确定。感谢您对回调的适用性提出任何见解或反馈!
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(String id);
}
/**
* A dummy implementation of the {@link Callbacks} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
@Override
public void onItemSelected(String id) {
}
};
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
@Override
public void onDetach() {
super.onDetach();
// Reset the active callbacks interface to the dummy implementation.
mCallbacks = sDummyCallbacks;
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(SongItem.ITEMS.get(position).id);
}
getActivity() and Setter Method? 我发现了这个问题 Passing data between a fragment and its container activity 。我会试一试,但它似乎是强耦合的,而且是一个糟糕的解决方案。它只是使用父 activity 的方法(例如 setter)通过片段将数据直接传递给父 activity。
我误以为 SongListActivity.java
只是为 SongDetailFragment.java
创建了一个 intent,但它是为 SongDetailActivity.java
创建了一个 intent。当我看到 SongDetailFragment.ARG_ITEM_ID
时,我很困惑。
我误解的代码:
Intent detailIntent = new Intent(this, SongDetailActivity.class);
detailIntent.putExtra(SongDetailFragment.ARG_ITEM_ID, id); //<-------- Argument
startActivity(detailIntent);
我的解决方案:
为了得到这个解决方案,我不得不改变很多东西,我不记得我做了什么,但这是最终的结果:
所以,我实际上只需要进入 SongDetailActivity.java
的 onCreate
方法,并像这样提取捆绑参数:
mSongId = getIntent().getStringExtra(SongDetailFragment.ARG_ITEM_ID);
然后我不得不在 SongDetailActivity.java
的 onNavigationDrawerItemSelected
方法中编辑它并让它实际实例化正确的片段,并在包中传递 mSongId
:
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
//------------ THE DEFAULT CODE THAT WASN'T PASSING THE DATA TO THE FRAGMENT----------
if(position == 1) {
fragmentManager.beginTransaction()
.replace(R.id.songlist_detail_container, PlaceholderFragment.newInstance(position + 1, mSongId)) //<------ I actually do not want a placeholder fragment. I want my SongDetailFragment.
.commit();
}
// ------------THE CODE I ADDED THAT WORKS-------------:
else {
SongDetailFragment sdf = new SongDetailFragment(); //<--------- Correct fragment class that I actually needed.
Bundle args = new Bundle();
args.putString(SongDetailFragment.ARG_ITEM_ID, mSongId); //<-------- PASS ALONG THE PARAMETER
sdf.setArguments(args);
fragmentManager.beginTransaction()
.replace(R.id.songlist_detail_container,sdf)
.commit();
}
}
现在可以使用了!我希望这对某人有所帮助。
结论
为了将主控 (SongListActivity.java
) 的参数传递给细节的导航抽屉 (SongDetailActivity.java
的 NavigationDrawerFragment.java
),我不得不将其作为额外内容放在意图中从 master 到 detail,并修改 detail 的导航抽屉回调以使用参数。我不需要将片段中的任何内容传递给它的父级 activity,就像我想的那样。
TL;DR 版本:
在Android master-detail 模式中,如何让MasterActivity 传递一个值给DetailFragment 的parent activity (DetailActivity)?因为DetailActivity是存放NavigationDrawerFragment的文件。
我考虑过的事情:
- 回调(我不知道它是如何工作的)
- 使用 getActivity() 并调用父 activity 上的函数来传递参数。似乎较少 "clean" 的解决方案并且高度耦合。
有更好的方法吗?
长版
我有一个主从模式,但细节已更改,因此 "up" 按钮不再返回到主列表,而是打开一个导航抽屉。
现在,我有 "dummy" 代码,所以我的导航抽屉有 3 个项目,当您第一次单击主列表中的项目时,它们都会打开同一个页面。
我的主要问题是:主列表可以将 SongDetailFragment.ARG_ITEM_ID
参数传递给详细信息,但导航抽屉无法访问 SongDetailFragment.ARG_ITEM_ID
参数 SongDetailFragment.java,因为抽屉导航是在SongDetailActivity.java.
主列表通过 detailIntent.putExtra(SongDetailFragment.ARG_ITEM_ID, id);
行将参数传递给详细信息 片段
:
SongListActivity.java
/**
* Callback method from {@link SongListFragment.Callbacks}
* indicating that the item with the given ID was selected.
*/
@Override
public void onItemSelected(String id) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(SongDetailFragment.ARG_ITEM_ID, id);
SongDetailFragment fragment = new SongDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.songlist_detail_container, fragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, SongDetailActivity.class);
detailIntent.putExtra(SongDetailFragment.ARG_ITEM_ID, id); //<-------- Argument
startActivity(detailIntent);
}
}
但是当我单击导航抽屉中的 3 个虚拟选项之一时,我无法传递该参数,因为导航抽屉位于 SongDetailActivity.java。
SongDetailActivity.java
//---------- NAVIGATION DRAWER -------------
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.songlist_detail_container, PlaceholderFragment.newInstance(position + 1))
.commit();
}
我尝试将此代码从 SongDetailFragment.java 的 onCreate 方法复制并粘贴到 SongDetailActivity.java 的 onCreate 方法中,希望我可以从 SongDetail[ 访问相同的 SongDetailFragment.ARG_ITEM_ID
变量Activity,但有Cannot resolve getArguments()
等编译错误。后来才知道Master在Fragment里只有"putting an extra",而不是Activity.
SongDetailFragment.java
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
if (getArguments().containsKey(ARG_ITEM_ID)) {
// Load the dummy title specified by the fragment
// arguments. In a real-world scenario, use a Loader
// to load title from a title provider.
mItem = SongItem.ITEM_MAP.get(getArguments().getString(ARG_ITEM_ID));
}
}
所以,我需要一些方法让导航抽屉 存储来自 Master 的 SongDetailFragment.ARG_ITEM_ID
变量,这样它就可以从模型中为每个视图获取正确的数据。 我该怎么做?
Shared Preferences? 我考虑过使用共享首选项,但我认为这是个坏主意,因为离开 [=] 的所有用例都很难擦除数据91=]。我想我需要比这更不全球化的东西。最好是,如果我能让 Master 将参数传递给 SongDetailActivity(并最终传递给 Navigation Drawer),那就完美了!
Callbacks? 我正在查看我的代码文件以考虑一些事情,我发现了这个 "callback" 由 Android Studio's Master 生成的东西- 细节向导。当它说 "This mechanism allows activities to be notified of item selections," 时听起来很适用,但我不确定。感谢您对回调的适用性提出任何见解或反馈!
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(String id);
}
/**
* A dummy implementation of the {@link Callbacks} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
@Override
public void onItemSelected(String id) {
}
};
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
@Override
public void onDetach() {
super.onDetach();
// Reset the active callbacks interface to the dummy implementation.
mCallbacks = sDummyCallbacks;
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(SongItem.ITEMS.get(position).id);
}
getActivity() and Setter Method? 我发现了这个问题 Passing data between a fragment and its container activity 。我会试一试,但它似乎是强耦合的,而且是一个糟糕的解决方案。它只是使用父 activity 的方法(例如 setter)通过片段将数据直接传递给父 activity。
我误以为 SongListActivity.java
只是为 SongDetailFragment.java
创建了一个 intent,但它是为 SongDetailActivity.java
创建了一个 intent。当我看到 SongDetailFragment.ARG_ITEM_ID
时,我很困惑。
我误解的代码:
Intent detailIntent = new Intent(this, SongDetailActivity.class);
detailIntent.putExtra(SongDetailFragment.ARG_ITEM_ID, id); //<-------- Argument
startActivity(detailIntent);
我的解决方案:
为了得到这个解决方案,我不得不改变很多东西,我不记得我做了什么,但这是最终的结果:
所以,我实际上只需要进入 SongDetailActivity.java
的 onCreate
方法,并像这样提取捆绑参数:
mSongId = getIntent().getStringExtra(SongDetailFragment.ARG_ITEM_ID);
然后我不得不在 SongDetailActivity.java
的 onNavigationDrawerItemSelected
方法中编辑它并让它实际实例化正确的片段,并在包中传递 mSongId
:
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
//------------ THE DEFAULT CODE THAT WASN'T PASSING THE DATA TO THE FRAGMENT----------
if(position == 1) {
fragmentManager.beginTransaction()
.replace(R.id.songlist_detail_container, PlaceholderFragment.newInstance(position + 1, mSongId)) //<------ I actually do not want a placeholder fragment. I want my SongDetailFragment.
.commit();
}
// ------------THE CODE I ADDED THAT WORKS-------------:
else {
SongDetailFragment sdf = new SongDetailFragment(); //<--------- Correct fragment class that I actually needed.
Bundle args = new Bundle();
args.putString(SongDetailFragment.ARG_ITEM_ID, mSongId); //<-------- PASS ALONG THE PARAMETER
sdf.setArguments(args);
fragmentManager.beginTransaction()
.replace(R.id.songlist_detail_container,sdf)
.commit();
}
}
现在可以使用了!我希望这对某人有所帮助。
结论
为了将主控 (SongListActivity.java
) 的参数传递给细节的导航抽屉 (SongDetailActivity.java
的 NavigationDrawerFragment.java
),我不得不将其作为额外内容放在意图中从 master 到 detail,并修改 detail 的导航抽屉回调以使用参数。我不需要将片段中的任何内容传递给它的父级 activity,就像我想的那样。