简体   繁体   English

如何在不每次加载的情况下使用导航抽屉菜单?

[英]How to use the navigation drawer menu without loading it each time?

This is more of a Java question (having some trouble understanding how should the inheritance be set).这更像是一个 Java 问题(在理解如何设置 inheritance 时遇到了一些麻烦)。 I'm trying to add a side menu to my application (which works ok).我正在尝试向我的应用程序添加一个侧面菜单(可以正常工作)。 The class signature of my menu activity is:我的菜单活动的 class 签名是:

public class MenuActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener

Once the user logged in, the first window he see is the main dashboard.用户登录后,他看到的第一个 window 就是主仪表板。 The dashboard activity extends the menu activity in order to have the side menu:仪表板活动扩展了菜单活动以获得侧边菜单:

public class DashboardActivity extends MenuActivity 

For navigating to other activities, I implemented the onNavigationItemSelected method to select the intent to load (The method is located in the MenuActivity ):为了导航到其他活动,我实现了onNavigationItemSelected方法来 select 加载intent (该方法位于MenuActivity中):

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    if (toggle.onOptionsItemSelected(item)) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        Intent intent = null;
        switch (item.getItemId()) {
            case R.id.lay_dashboard:
                intent = new Intent(this, DashboardActivity.class);
                //intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                break;
            case R.id.lay_settings:
                intent = new Intent(this, SettingsActivity.class);
                //intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                break;
            case R.id.lay_contacts:
                startActivity(new Intent(this, ContactsActivity.class));
                break;
            case R.id.lay_about:
                startActivity(new Intent(this, AboutActivity.class));
                break;
            case R.id.lay_logout:
                mAuth.signOut();
                intent = new Intent(this, MainActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                break;
        }
        if (intent != null) {
            startActivity(intent);
        }
        drawerLayout.closeDrawer(GravityCompat.START);
        return true;
    }

As you can see I commented the intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);如您所见,我评论了intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); as part of debugging the issue.作为调试问题的一部分。 I want the navigation process not to start a new screen, rather move to it.我希望导航过程不要开始一个新屏幕,而是移动到它。

Also the OnCreate method in the MenuActivity looks like this: MenuActivity中的OnCreate方法也如下所示:


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_menu);

    ActionBar actionBar = getSupportActionBar();
    if (actionBar != null) {
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setHomeButtonEnabled(true);
    }

    drawerLayout = findViewById(R.id.drawer_layout);
    navigationView = findViewById(R.id.lay_nav_view);

    toggle = new ActionBarDrawerToggle(this, drawerLayout,
            R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawerLayout.addDrawerListener(toggle);
    toggle.syncState();
    navigationView.setNavigationItemSelectedListener(this);

    mAuth = FirebaseAuth.getInstance();
    logged_user = mAuth.getCurrentUser();

    if (logged_user != null) {
        // Get data from firebase in order to set the avatar
        // and user name in the menu
    }
}

protected void setLayoutView(int layout) {
    LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if (inflater != null) {
        View contentView = inflater.inflate(layout, null, false);
        drawerLayout.addView(contentView, 0);
    }
}

Each one of the activitise extends the MenuActivity and does the following in their onCreate method:每个活动都扩展了MenuActivity并在其onCreate方法中执行以下操作:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setLayoutView(R.layout.activity_about); // My method which loads UI
        // other code
    }

So, as you can see, each one of the activities is extending the MenuActivity .因此,如您所见,每个活动都在扩展MenuActivity As I understand, this means that everytime I navigate from one activity to another, the OnCreate of MenuActivity is being executed again.据我了解,这意味着每次我从一个活动导航到另一个活动时,都会再次执行MenuActivityOnCreate I fetch data from the Firebase in that method in order to set the username and the avatar in the top of the menu.我在该方法中从 Firebase 获取数据,以便在菜单顶部设置用户名和头像。 So everytime I navigate from one activity to another, it will fetch again and again.所以每次我从一个活动导航到另一个活动时,它都会一次又一次地获取。 How can I make the menu to load only once in a logged mode?如何使菜单在记录模式下仅加载一次? Also, thanks to all of you that have read this topic (I know it's long).另外,感谢所有阅读过这个主题的人(我知道它很长)。

EDIT : To make it more clear, I'm adding the hierarchy of my code:编辑:为了更清楚,我添加了代码的层次结构:

在此处输入图像描述

Maybe the solution for this issue is to make the MenuActivity a singleton class?也许这个问题的解决方案是让MenuActivity成为 singleton class?

All I want to have a menu on each one of the activities and fetching the data only once.我只想在每个活动上都有一个菜单,并且只获取一次数据。

Hello you could use NavigationDrawer with fragments.您好,您可以将 NavigationDrawer 与片段一起使用。 That will be the most optimal solution and easy, You could also use Navigation Component from Jetpack to change the destinations.这将是最优化且简单的解决方案,您还可以使用 Jetpack 的导航组件来更改目的地。

you could use something like this,the following layout uses a DrawerLayout with two child views: a NavHostFragment to contain the main content and a NavigationView for the contents of the navigation drawer.你可以使用这样的东西,以下布局使用带有两个子视图的 DrawerLayout:一个 NavHostFragment 包含主要内容,一个 NavigationView 用于导航抽屉的内容。

<?xml version="1.0" encoding="utf-8"?>
<!-- Use DrawerLayout as root container for activity -->
<androidx.drawerlayout.widget.DrawerLayout       xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">

<!-- Layout to contain contents of main body of screen (drawer will slide over this) -->
<fragment
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:id="@+id/nav_host_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_graph" />

<!-- Container for contents of drawer - use NavigationView to make configuration easier -->
<com.google.android.material.navigation.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true" />

Next, connect the DrawerLayout to your navigation graph by passing it to AppBarConfiguration, as shown in the following example:接下来,通过将 DrawerLayout 传递给 AppBarConfiguration 将其连接到导航图,如下例所示:

val appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)

Next, in your main activity class, call setupWithNavController() from your main activity's onCreate() method, as shown below:接下来,在您的主要活动 class 中,从您的主要活动的 onCreate() 方法调用 setupWithNavController(),如下所示:

override fun onCreate(savedInstanceState: Bundle?) {
setContentView(R.layout.activity_main)

...

val navController = findNavController(R.id.nav_host_fragment)
findViewById<NavigationView>(R.id.nav_view)
    .setupWithNavController(navController)

} }

Thats it, then you can use the navContoller to navigate to any fragment, and rest of what you need is a navigation graph and actions set on destinations to navigate between fragments this way:就是这样,然后您可以使用 navContoller 导航到任何片段,并且您需要的 rest 是导航图和在目的地上设置的操作,以便通过这种方式在片段之间导航:

navController.navigate(R.id.actionSettingFragment_to_ContactsFrament)

Hope this is kinda helpful.希望这有点帮助。 I have a blog written on this so please check it if it is useful to you.我有一个关于此的博客,所以请检查它是否对您有用。

There's more than one way to resolve your issue.解决您的问题的方法不止一种。 I'm going to provide different approaches towards a solution.我将为解决方案提供不同的方法。

Repository存储库

To reuse the data you fetch from Firebase , it needs to be persisted or cached within your application.要重用您从Firebase获取的数据,需要将其持久化或缓存在您的应用程序中。 In general you'd implement an repository abstraction around the Firebase .通常,您会围绕Firebase实现存储库抽象 This repository could be a singleton and just cache the data in memory directly.该存储库可以是 singleton 并直接将数据缓存在 memory 中。 You only have to make sure to cleanup the cache when necessary.您只需确保在必要时清理缓存。 The MenuActivity mustn't be a singlton . MenuActivity不能是单例

Intent extras意图附加功能

Instead of storing the data in memory, you could provide it as Intent extras .您可以将其作为Intent extras提供,而不是将数据存储在 memory 中。 Whenever the data is present, just skip the loading and reuse the data provided.只要数据存在,只需跳过加载并重用提供的数据。

Fragments碎片

Instead of a stack of activities, you could use fragments .您可以使用片段而不是一堆活动。 So you'll have a single activity and just replace the fragments within it.因此,您将有一个活动,只需替换其中的片段。 With this approach you'll just define a single drawer layout you'll automatically use with every fragment.使用这种方法,您只需定义一个抽屉布局,您将自动与每个片段一起使用。 This approach enables you to use Navigation components as well.这种方法也使您能够使用导航组件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM