代码之家  ›  专栏  ›  技术社区  ›  Soren Stoutner

如何在Android上打开抽屉布局时编辑导航菜单项标题

  •  0
  • Soren Stoutner  · 技术社区  · 6 年前

    在Android上,当 NavigationView 是在 DrawerLayout ,个人的头衔 MenuItems 可以通过1)获取 菜单项 在主要活动中:

    // Get a handle for the navigation view.
    NavigationView navigationView = findViewById(R.id.navigationview);
    
    // Get handles for the navigation menu items.
    final Menu navigationMenu = navigationView.getMenu();
    final MenuItem navigationFirstMenuItem = navigationMenu.getItem(0);
    final MenuItem navigationSecondMenuItem = navigationMenu.getItem(1);
    final MenuItem navigationThirdMenuItem = navigationMenu.getItem(2);
    

    DrawerListener :

    // The drawer listener is used to update the navigation menu.
    drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
        @Override
        public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
        }
    
        @Override
        public void onDrawerOpened(@NonNull View drawerView) {
        }
    
        @Override
        public void onDrawerClosed(@NonNull View drawerView) {
        }
    
        @Override
        public void onDrawerStateChanged(int newState) {
            if ((newState == DrawerLayout.STATE_SETTLING) || (newState == DrawerLayout.STATE_DRAGGING)) {  // A drawer is opening or closing.
                // Update the title of the menu items.
                navigationFirstMenuItem.setTitle(getString(R.string.newString));
                navigationSecondMenuItem.setEnabled(false);
                navigationThirdMenuItem.setTitle(getString(R.string.title) + " - " + counterInt);
                }
            }
        });
    

    但是,一旦抽屉打开,尝试从运行在不同线程上的主活动的一部分更改某个菜单项的标题将导致以下错误,从而使应用程序崩溃:

    W/System.err: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
    

    例如,此错误可以通过尝试从内部更新导航菜单项来产生 WebViewClient.shouldInterceptRequest() 具体如下:

    // Get a handle for the WebView.
    WebView webView = findViewById(R.id.webview);
    
    // Set a WebViewClient.
    webView.setWebViewClient(new WebViewClient() {
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url){
            navigationFirstMenuItem.setTitle(getString(R.string.newString));
            navigationSecondMenuItem.setEnabled(false);
            navigationThirdMenuItem.setTitle(getString(R.string.title) + " - " + counterInt);
        }
    }
    

    问题是如何更新菜单项,例如,当导航抽屉打开且需要更新菜单项的事件在另一个线程上运行时,计数器会在其中一个标题中递增。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Soren Stoutner    6 年前

    正如@MikeM所建议的,问题的解决方法是使用 Activity.runOnUiThread() 从创建导航的同一线程更新导航。具体来说,下面的代码对我有效。

    // Get a handle for the activity.  This is used to update the menu item titles while the navigation menu is open.
    Activity activity = this;
    
    // Get a handle for the WebView.
    WebView webView = findViewById(R.id.webview);
    
    // Set a WebViewClient.
    webView.setWebViewClient(new WebViewClient() {
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url){
            // Update the menu items' titles from the UI thread.
            activity.runOnUiThread(() -> {
                navigationFirstMenuItem.setTitle(getString(R.string.newString));
                navigationSecondMenuItem.setEnabled(false);
                navigationThirdMenuItem.setTitle(getString(R.string.title) + " - " + counterInt);
            });
        }
    }
    

    理解这个问题的关键是导航视图是由UI线程创建的。事后看来,这似乎很明显,但错误信息并没有明确说明这一点,而且这种行为最初让我相信 DrawerLayout 抽屉布局 听众。