一个Fragment的导航抽屉关闭不够流畅

3

我为我的应用程序实现了一个导航抽屉,大部分情况下都可以正常工作。

我的主页选项卡需要进行一些API请求以显示一些信息,这些请求和它们所需的工作量(即使很小)会中途阻塞关闭抽屉,使其不够流畅。

我的第一个“解决方案”是在抽屉关闭后再加载片段,像这样:

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" />

这是我目前如何显示我的Fragment

@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);
}

你有什么建议可以使我的 导航抽屉 平稳关闭?

编辑:

如所请求,这是我用于 API 请求和返回 JSONObjectAsyncTask 代码:

/**
 * 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;
    }
}
< p > APIRequest的方法使用HttpURLConnection进行简单的HTTP GET,并返回一个包含检索数据的JSONObject


displaySelectedScreen() 函数中会发生什么? - dumazy
4个回答

3

看起来在关闭抽屉之前,您在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();
}

正如我所说,我的第一个“解决方案”是在抽屉关闭后加载片段,但它的小延迟破坏了界面的流畅性。无论如何,感谢您的帮助。 - user5448913

0
你尝试过不进行 API 请求,看看问题是否出现在片段的显示上了吗?

绝对的,没有请求非常顺畅。 - user5448913

0

请确保使用另一个线程来执行API请求。您可以根据特定的API请求使用AsyncTaskLoadersServicesIntentServices等等。这样,Fragment就可以立即显示,并在加载完成后添加数据。


我已经在AsyncTask后台方法中执行了我的API请求。 - user5448913
如果您不执行AsyncTask,一切都会顺利进行吗?如果是这样,您可以展示AsyncTask的代码吗? - dumazy

0
我使用的解决方案如下:
由于我显示的数据不会经常更改(至少不是每天),因此现在我仅在应用程序的每个会话(进程)中执行一次API请求。
 if (!requestDone) { // Where requestDone == true when I have done an API request
      getGameInfo();
 }

仅在未实例化时(为了保持requestDone的值)才实例化Fragment。

现在动画始终流畅(因为我有一个启动屏幕,当API请求完成时就会结束)。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接