如何将参数从 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的文件。

我考虑过的事情:

有更好的方法吗?


长版

我有一个主从模式,但细节已更改,因此 "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.javaonCreate 方法,并像这样提取捆绑参数:

mSongId = getIntent().getStringExtra(SongDetailFragment.ARG_ITEM_ID);

然后我不得不在 SongDetailActivity.javaonNavigationDrawerItemSelected 方法中编辑它并让它实际实例化正确的片段,并在包中传递 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.javaNavigationDrawerFragment.java),我不得不将其作为额外内容放在意图中从 master 到 detail,并修改 detail 的导航抽屉回调以使用参数。我不需要将片段中的任何内容传递给它的父级 activity,就像我想的那样。