【问题标题】:Navigation Drawer closing is not smooth for a FragmentFragment 的导航抽屉关闭不顺畅
【发布时间】:2016-12-21 19:48:47
【问题描述】:

我已经为我的应用实现了一个Navigation Drawer,它在大多数情况下都能正常工作。

我的Home 选项卡执行了几个 API 请求以显示一些信息,这些请求和它们所需的工作量(即使它相当小)阻止了抽屉的中途关闭,使其不顺畅。

我的第一个“解决方案”是to load the fragment only after the Drawer closes,就像这样:

toggle = new ActionBarDrawerToggle(
            this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {

        public void onDrawerClosed(View view) {
            super.onDrawerClosed(view);

            displaySelectedScreen(itemSelected.getItemId());
        }
    };

但这会在 Fragments 视图显示之前创建 0.5 秒的等待时间,从用户的角度来看,这并不是很有吸引力。

这是我activity_main.xml的一部分:

<android.support.design.widget.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:headerLayout="@layout/nav_header_main"
    app:menu="@menu/activity_main_drawer" />

到目前为止,这就是我显示 Fragments 的方式:

@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(final MenuItem item) {      
    displaySelectedScreen(item.getItemId());
    drawer.closeDrawer(GravityCompat.START);
    return true;
}

这是displaySelectedScreen 发生的事情:

private void displaySelectedScreen(int itemId) {
    Fragment fragment;
    fragment = checkFragment(itemId); // Instantiates the right Fragment

    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.content_frame, fragment);
    ft.commit();

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);

    // Close our Drawer since we have selected a valid item.
    drawer.closeDrawer(GravityCompat.START);
}

您有什么建议可以让我的Navigation Drawer 顺利关闭?

编辑

根据要求,这是我的 AsyncTask 的代码,它执行 API 请求并返回 JSONObject

/**
 * Requests information from the API via APIRequests
 * Extends AsyncTask in order to do network-related actions in background.
 */
private class SearchInfo extends AsyncTask<Void, Integer, JSONObject> {

    @Override
    protected JSONObject doInBackground(Void... params) {
        JSONObject information;

        APIRequests apiRequests = new APIRequests();
        information = apiRequests.getGameInfo();

        requestDone = true;

        return information;
    }
}

APIRequest 的方法通过HttpURLConnection 执行一个简单的HTTP GET 并返回一个带有检索数据的JSONObject

【问题讨论】:

  • displaySelectedScreen() 中发生了什么?

标签: android android-fragments navigation-drawer


【解决方案1】:

您似乎在抽屉关闭之前在 displaySelectedScreen() 中提交了 Fragment

@Override
public boolean onNavigationItemSelected(final MenuItem item) {      
    displaySelectedScreen(item.getItemId()); // Commit is there
    drawer.closeDrawer(GravityCompat.START); // And drawer closing simultaneously
    return true;
}

我会怎么做

// Create a field that marks that something needs to be displayed
// after drawer closes. When null means no action (drawer closed
// by the user, not by selecting an item)
Integer itemIdWhenClosed;

@Override
public boolean onNavigationItemSelected(final MenuItem item) {      
    itemIdWhenClosed = item.getItemId(); // Mark action when closed
    drawer.closeDrawer(GravityCompat.START); // Close it
    return true;
}

@Override
public void onDrawerClosed(View view) {
    super.onDrawerClosed(view);
    // If id to show is marked, perform action
    if (itemIdWhenClosed != null) {
        displaySelectedScreen(itemIdWhenClosed);
        // Reset value
        itemIdWhenClosed = null;
    }
}

// Now here just commit, don't close the drawer since this is already
// fired when it's closed
private void displaySelectedScreen(int itemId) {
    final Fragment fragment = checkFragment(itemId);
    final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.content_frame, fragment);
    ft.commit();
}

【讨论】:

  • 正如我所说,我的第一个“解决方案”是在抽屉关闭后加载 Fragment,但它的一点延迟破坏了界面的流动性。无论如何感谢您的帮助
【解决方案2】:

您是否尝试过不发出 API 请求,看看问题是否在片段的显示上?

【讨论】:

  • 当然,没有请求就很流畅了。
【解决方案3】:

确保您使用另一个线程来执行 API 请求。您可以使用 AsyncTaskLoadersServicesIntentServices 等,具体取决于具体的 API 请求是什么。这样Fragment 可以立即显示,并且可以在加载时将数据添加到其中

【讨论】:

  • 我已经在 AsyncTask 后台方法中完成了我的 API 请求。
  • 如果你不执行 AsyncTask 一切运行顺利吗?如果是这样,您能否也显示 AsyncTask 的代码?
【解决方案4】:

我用过的解决方案如下:

由于我显示的数据不会经常更改(至少不会每天更改),我现在在我的应用程序的每个会话(进程)中只执行一次 API 请求。

 if (!requestDone) { // Where requestDone == true when I have done an API request
      getGameInfo();
 }

并且只有在Fragment没有被实例化的时候才实例化它(为了保持requestDone的值)。

动画现在始终流畅(因为我有一个在 API 请求完成时结束的初始屏幕)。

现在对我来说似乎很明显,请求数据的次数必须等于其被更新的概率。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多