在主/从片段使用动作条向上导航片段、动作

2023-09-12 02:28:29 作者:擒屎皇

我有一个主/详细布局(1活动,1 ListView的片段和1个细节片段)的应用程序。当用户单击ListView的一个项目,一个片段的交易实例在右窗格中包含对应于该项目的信息的细节片段。当细节片段见我躲在初始动作栏按钮/项目和显示3个新的AB项目(完成/删除/取消)。用户可以清除右窗格中,并且由pressing后退按钮或pressing的3 AB项目之一返回到初始UI状态。

I have an app with master/detail layout (1 activity, 1 ListView fragment and 1 detail fragment). When the user clicks an item in the ListView, a fragment transaction instantiates a detail fragment on the right-pane that includes the information corresponding to that item. When the detail fragment is shown I hide the initial action bar buttons/items and show 3 new AB items (done/delete/cancel). The user can clean the right-pane and return to the initial UI state by either pressing the back button or by pressing one of the 3 AB items.

我遇到的问题是,当用户选择,指示该活动开始可以被看作是两个动作的应用程序的首页图标(即向上导航)的活性被重新加载(即动画栏和用户界面被重新绘制)。该问题仅发生在家庭的应用程序图标为pressed。如果用户presses后退按钮或取消/完成/删除操作栏按钮,该片段只是从右窗格中删除和用户界面返回到初始状态,没有任何重新加载。

The issue I'm experiencing is that when the user selects the app's home icon (i.e. "up navigation") the activity gets re-loaded (i.e. the animation that indicates that the activity is starting can be seen as both the action bar and the UI is been redrawn). The issue only happens when the app home icon is pressed. If the user presses the back button or a cancel/done/delete action bar button, the fragment is simply remove from the right-pane and the UI returns to initial state without any "re-loading".

该活动的XML布局如下(内部的LinearLayout; prettify躲在那条线):     

The XML layout for the activity is the following (inside LinearLayout; prettify is hiding that line):

<fragment class="*.*.*.ListFragment"
        android:id="@+id/titles" android:layout_weight="1"
        android:layout_width="0px"
        android:layout_height="match_parent" />

<FrameLayout android:id="@+id/details" android:layout_weight="2"
        android:layout_width="0px"
        android:layout_height="match_parent" />

该DetailsFragement在其onCreate方法的actionBar.setDisplayHomeAsUpEnabled语句:

The DetailsFragement has the actionBar.setDisplayHomeAsUpEnabled statement in its onCreate method:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);


    ActionBar actionBar = getSherlockActivity().getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);

}

对于这两个ListView的片段和细节片段onCreateOptionsMenu()和onOptionsItemSelected()方法是在片段中实现。下面以code的细节片段:

For both the ListView fragment and the Detail fragments the onCreateOptionsMenu() and onOptionsItemSelected() method are implemented within the fragments. Below the code for the Details fragment:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.edit_menu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    // some variable statements...

    switch (item.getItemId()) {
        case android.R.id.home:
            //Toast.makeText(getSherlockActivity(), "Tapped home", Toast.LENGTH_SHORT).show();
            onHomeSelectedListener.onHomeSelected();
            return true;

        case R.id.menu_edit_item_done:
            editedTask.setTitle(editedTaskTitle);
            onTaskEditedListener.onTaskEdited(editedTask, UPDATE_TASK, true);
            return true;

        default:
            return super.onOptionsItemSelected(item);

    }
}

在主机活动我实现了onHomeSelectedListner处理应用程序主页图标preSS(即向上导航:

In the host activity I implement the onHomeSelectedListner to handle the app home icon press (i.e. "up navigation":

public void onHomeSelected(){

    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction ft = manager.beginTransaction();
    TaskFragment taskFragment = (TaskFragment)getSupportFragmentManager().findFragmentById(R.id.details);
    ft.remove(taskFragment);
    ft.commit();
    manager.popBackStack();

}

在带电处理所有其他操作栏按钮的活动的监听器(即做/删除/取消)是onTaskEditedListener和,除了其他code,用于处理一些数据,它上面显示的相同片段的交易。

The activity's listener in charged of handling all other action bar buttons (i.e. done/delete/cancel) is onTaskEditedListener and, aside of other code that processes some data, it has the same fragment transactions shown above.

更新(1/24) 基于tyczj和straya反馈我把日志报表内的活动的onCreate(),onResume(),在onPause()来确定onHomeSelected之间的差异和onTaskEdited听众。我能确认向上导航活动(即onHomeSelected)的onPause()的onCreate()和onResume()被调用时。鉴于onTaskEdited调用(即后退按钮或做/删除/取消preSS)没有这些事件被调用。

Update(1/24) Based on tyczj and straya feedback I placed log statements inside onCreate(), onResume(), onPause() of the activity to determine the differences between onHomeSelected and onTaskEdited listeners. I'm able to confirm that during the "up navigation" event (i.e. onHomeSelected) onPause(), onCreate() and onResume() are called. Whereas during the onTaskEdited call (i.e. back button or done/delete/cancel press) none of those events are called.

更新(1/25) 根据建议由马克·墨菲,我注释掉onHomeSelected方法调用中的案件android.R.id.home的声明只是为了看看会的活动做。该想法是,应用程序会做什么,因为没有发言。事实证明,情况并非如此。即使没有调用监听方法(即,去除的片段),该活动被重新启动,并在细节片段被从片段容器中取出。

Update (1/25) Based on a suggestion by Mark Murphy, I commented out the onHomeSelected method call in the "case android.R.id.home" statement just to see what would the Activity do. The thinking was that the app would do nothing since the are no statements. Turns out that is not the case. Even without a call to the listener method (i.e. that removes the fragment), the activity is restarted and the detail fragment is removed from the fragment container.

更新(2/28) 我暂时解决该事实,我的主要活动是得到通过禁用窗口动画重新启动(在我自己的答案高亮显示)。然而,通过进一步的测试我发现了一个错误。由于钨Rittmeyer的样品code我能找出真正的原因(S)为什么我的活动是在导航过程中重新启动起来(在主/从单一布局): 1)虽然我是用这个onHomeSelectedListener正确地删除该backstack的片段,我仍然有一些残留code在ListView片段的onOptionsItemSelected这是创建一个新的意图开始举办的活动。这就是为什么pressing应用程序的主页图标重新开始活动。 2)在我最后的实施(图中我自己的答案),我得到了在活动摆脱onHomeSelectedListener和更换startActivity意图(即违规code)ListView的onOptionsItemSelected内使用碎片去除+ popBackStack $ C $ Ç原本在onHomeSelectedListener。

Update (2/28) I temporarily workaround the fact that my main activity was getting restarted by disabling the window animations (as highlighted in my own answer). However, through further testing I uncovered a bug. Thanks to Wolfram Rittmeyer's sample code I was able to figure out the real reason(s) why my activity was restarting (in master/detail single layout) during up navigation: 1) Although I was using this "onHomeSelectedListener" to properly remove the fragment from the backstack, I still had some remnant code in the ListView fragment's onOptionsItemSelected that was creating a new intent to start the hosting activity. That's why pressing the app's home icon was re-starting the activity. 2) In my final implementation (shown in my own answer), I got rid of the onHomeSelectedListener in the activity and replace the startActivity intent (i.e. offending code) inside the ListView's onOptionsItemSelected to use the fragment removal + popBackStack code originally in the onHomeSelectedListener.

推荐答案

大量的研究和闲逛后,事实证明,为什么我的活动是在向上导航重新启动的主/从配置,是因为我留下了一些$唯一原因C $ c在ListView控件片段的onOptionsItemSelected这是创建一个意图开始在另外的主要活动,以我的全部片段交易code别处。下面是与我向上导航这两个电话(多项活动)和平板电脑(单个活动/多窗格)配置上正常工作的最终实现。由于钨Rittmeyer 为一对夫妇在他的code的提示(链接注释部分),帮助我找出我的问题!

After much research and poking around, turns out that only reason why my activity was restarting during "up navigation" for master/detail configuration was because I left some code in the ListView Fragment's onOptionsItemSelected that was creating an intent to start the main activity in addition to my full fragment transaction code elsewhere. Below is the final implementation with which I got "up navigation" to work properly on both phone (multiple activities) and tablet (single activity/multi-pane) configurations. Thanks to Wolfram Rittmeyer for a couple of hints in his code (link in the comment section) that help me pinpoint my problem!

主要活动:主机的片段并执行其他一些应用程序特定的操作。

Main Activity: Hosts the fragments and performs some other app-specific operations

的ListView片段:把手了导航表配置

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            if(mDualPane){
                FragmentManager manager = getSherlockActivity().getSupportFragmentManager();
                FragmentTransaction ft = manager.beginTransaction();
                DetailFragment detailFragment = (DetailFragment)manager.findFragmentById(R.id.details);
                ft.remove(detailFragment);
                ft.commit();
                manager.popBackStack();
                getSherlockActivity().getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                getSherlockActivity().getSupportActionBar().setHomeButtonEnabled(false);
            }
            return true;

        // Other case statements...

        default:
            return super.onOptionsItemSelected(item);
    }
}

详细信息片段:处理高达导航手机配置

Details Fragment: Handles up navigation in phone configuration

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);

    // Sets "up navigation" for both phone/tablet configurations
    ActionBar actionBar = getSherlockActivity().getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case android.R.id.home:
            if(!mDualPane){
                Intent parentActivityIntent = new Intent(getSherlockActivity(), MainActivity.class);
                parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(parentActivityIntent);
                getSherlockActivity().finish();
            }
            return true;

        // Other case statements...

        default:
            return super.onOptionsItemSelected(item);
    }

}