如何在关注可重用性和关注点分离的 android 库模块之间实现导航? [英] How do I implement navigation between android library modules focusing reusability and separation of concerns?

查看:18
本文介绍了如何在关注可重用性和关注点分离的 android 库模块之间实现导航?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个单独的导航模块,以便在关注可扩展性、可重用性和模块独立性的 android 库模块之间导航.我的应用架构类似于这个例子:

I'm trying to implement a separate navigation module to navigate between android library modules focusing scalability, reusability and module independence. My application architecture is similar to this example:

我目前的做法

1- 为每个库定义 NavigatorInterface

2- 在 NavigationModule 中实现每个 NavigatorInterface.(当然导航模块会知道所有其他库模块,但没关系,因为它不会被重用)

2- Implement each NavigatorInterface in NavigationModule. (ofcourse navigation module will know about all other library modules but it does not matter as it won't be reused)

以下是我上面提到的架构的示例代码:

Following is the example code for my above mentioned architecture:

:auth

|-- 登录活动

|-- 注册活动

|-- 认证导航器

public class LoginActivity extends AppCompatActivity {
    private NavigatorCoordinator navigator; // how do I achieve this injection, without using Dagger etc.

    .....
    private void signup(){
        navigator.NavigateToSignup(this);
    }

    private void profile(){
        navigator.NavigateToProfile(this);
    }
    .....
}


public class SignupActivity extends AppCompatActivity {
    private NavigatorCoordinator navigator; // how do I achieve this injection, without using Dagger etc.

    .....
    private void login(){
        navigator.NavigateToLogin(this);
    }

    private void profile(){
        navigator.NavigateToProfile(this);
    }
    .....
}



public interface AuthNavigator {
    void NavigateToLogin(Context context);
    void NavigateToRegister(Context context);
}

:个人资料

|-- 个人资料活动

|-- ProfileNavigator

|-- ProfileNavigator

public class ProfileActivity extends AppCompatActivity {
    private NavigatorCoordinator navigator; // how do I achieve this injection, without using Dagger etc.

    .....
    private void about(){
        navigator.NavigateToAbout(this);
    }
    .....
}


public interface ProfileNavigator {
    void NavigateToProfile(Context context);
}

:关于

|-- 关于活动

|-- 关于导航器

public class AboutActivity extends AppCompatActivity {
    private NavigatorCoordinator navigator; // how do I achieve this injection, without using Dagger etc.

    .....
    private void profile(){
        navigator.NavigateToProfile(this);
    }
    .....
}


public interface AboutNavigator {
    void NavigateToAbout(Context context);
}

上述方法是尝试消除同一模块 :auth 内以及两个模块 :profile & 之间的循环依赖.:关于.下面是:navigation的实现.

The above approach is a try to eliminate circular dependency within same module :auth as well as between two modules :profile & :about. Below is the implementation of :navigation.

:导航

|-- 导航器

public class Navigator implements AuthNavigator, ProfileNavigator, AboutNavigator {
    @Override
    public void NavigateToLogin(Context context) {
        context.startActivity(new Intent(context, LoginActivity.class));
    }

    @Override
    public void NavigateToSingup(Context context) {
        context.startActivity(new Intent(context, SignupActivity.class));
    }

    @Override
    public void NavigateToProfile(Context context) {
        context.startActivity(new Intent(context, ProfileActivity.class));
    }

    @Override
    public void NavigateToAbout(Context context) {
        context.startActivity(new Intent(context, AboutActivity.class));
    }
}

问题:

1- 我相信,我需要在 :navigation 模块中实现 NavigatorCoordinator,但我该怎么做呢?有这个实现的例子吗?

1- I believe, I need to implement the NavigatorCoordinator in :navigation module, but how do I do it? Any example for this implementation?

2- 如何在不使用 Deggar 或任何其他框架的情况下将 NavigatorCoordinator 的依赖项注入驻留在不同 modules 中的每个 Activity 类中?我们可以使用 Application 类来实现吗,如果可以,请给出一个实现示例?

2- How do I inject the dependency of NavigatorCoordinator in each Activity Class residing in different modules without using Deggar or any other framework? Can we do it by using Application class, if yes please give an example of implementation?

3- 如何从任何库设置 Launcher 活动,例如:LoginActivity?

3- How do I setup the Launcher activity from any library, for example: LoginActivity?

4- 如何从 :app 模块调用 :navigation 模块以启动特定活动,例如:ProfileActivity?

4- How do I call the :navigation module from :app module in a way that it starts a specific activity, for example: ProfileActivity?

5- 这是实现可重用性、可扩展性和关注点分离的良好模块间导航方法吗?

5- Is this a good inter-module navigation approach to achieve reusability, scalability and separation of concerns?

6- 还有其他类似的好方法吗?任何代码示例?链接到文章?

6- Are there any other similar and good approaches? Any code examples? Link to article?

PS:请不要告诉我使用导航架构组件.

PS: Please don't tell me to use Navigation Architecture Component.

推荐答案

实际上,您可以为此应用一些面向对象的解决方法.首先,您可以考虑在 common 模块中声明一个导航器接口.由于每个模块都是独立的并且彼此不认识,因此您需要遵循更通用的方法.您可以定义类似 Navigator 界面的东西

Actually you can apply some object oriented workaround for this. First of all, you can consider declaring an navigator interface inside common module. Since every module is independent and doesn't know each other, you need to follow a more generic approach. You can define something like a Navigator interface

interface Navigator {
    fun navigate(activity: Activity, bundle: Bundle)
}

现在考虑打开活动而不引用它,但使用一个键.您应该有一个工厂来将给定的键映射到活动导航器.你可以认为你想用一个键打开 AboutActivity,因为你没有它的引用.键可以是整数,也可以是类包名,没关系.我会坚持使用包名作为键.

Now consider opening activities without referencing it, but with a key. You should have a factory to map your given key to an activity navigator. You can think like you want to open AboutActivity with a key, since you don't have its reference. The key can be an integer or maybe class package name, it doesn't matter. I'll stick with package name as a key.

interface NavigatorFactory {
    fun of(packageName: String): Navigator
}

在活动中导航时,您需要以某种方式获取这些导航器.一种理想的方法是使用应用程序类,因为您在任何活动中都有它的引用.所以我们定义了一个接口应用到应用类.

And somehow you need to get those navigators when navigating inside an activity. An ideal way is to use application class, because you have its reference in any of your activities. So we defined an interface to apply to application class.

interface NavigatorApplication {
    fun getNavigatorFactory(): NavigatorFactory
}

所以我们在 common 模块中结束我们的实现.让我们继续应用程序模块.你需要开始声明这些接口的实现

So we end our implementations in common module. Let's continue with app module. You need to start declaring implementations of these interfaces

class AboutActivityNavigator: Navigator {
    public void navigate(Activity activity, bundle: Bundle) {
        val intent = Intent(activity, AboutActivity::class.java)
        activity.startActivity(intent, bundle)
    }
}

返回这些 Navigator 实例的工厂实现.

Factory implementation to return these Navigator instances.

object NavigatorFactoryImpl: NavigatorFactory {
    fun get(key: String): Navigator {
        when(key) {
            is "com.example.AboutActivity" -> AboutActivityNavigator()
        }
    }
}

为工厂提供模块已知的接口.这样模块就可以到达接口并接收工厂实例.

Provide factory with an interface that known by modules. This way modules can reach interface and receive factory instance.

class Application: NavigatorApplication {
    val factoryImpl = NavigatorFactoryImpl()
    fun getNavigatorFactory() = factoryImpl
}

我们也完成了应用模块.现在,您可以导航到任何模块中所需的每个活动.

We are done with app module too. Now you can navigate to every activity you want inside any of your modules.

class ProfileActivity: Activity() {
    fun navigateToAboutActivity() {
        (application as? NavigatorApplication)?
            .getNavigatorFactory()
            .of("com.example.AboutActivity")
            .navigate(this, Bundle())
    }
}

最后,一切都是有代价的.您的模块是完全独立的.但不要忘记,您仍然在传递一些硬编码的密钥来打开活动.此外,您无法保证类型安全.如果您在捆绑包中传递诸如 ("page-id",34) 之类的键值对,您可能永远不知道目标活动是否接受相同的键和相同的类型.

In the end everything comes with a price. Your modules are totally independent. But don't forget, you are still passing some hardcoded key to open an activity. And besides, you have no guarantees for type safety. If you pass something key-value like ("page-id",34) inside a bundle, you may never know if target activity accepts same key and same type.

如果你以后有基于单activity的架构,你还可以查看Jetpack Navigation由谷歌

And if you have a single-activity based architecture in the future, you can also check Jetpack Navigation by Google

这篇关于如何在关注可重用性和关注点分离的 android 库模块之间实现导航?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆