【问题标题】:The model layer (MVP) should use the Activity reference模型层 (MVP) 应该使用 Activity 引用
【发布时间】:2017-04-13 21:26:28
【问题描述】:

当我在模型中有需要当前活动实例的操作时,如何在模型层和视图层之间进行适当的分离?

例如,我在我的 Android 应用程序中集成了 Linkedin SDK(用 MVP 编写)。 在身份验证过程中,我有以下代码 sn-p,当 init() 方法的第一个参数类型是 Activity 时:

public void authWithLinkedin(final IAuth listener, Activity activity) {
    LISessionManager.getInstance(MyApplication.getContext()).init(activity, buildScope(), new AuthListener() {

        @Override
        public void onAuthSuccess() {
            listener.onSuccess();
        }

        @Override
        public void onAuthError(LIAuthError error) {
            listener.onError();
        }

    }, true);
}

如果我的模型层应该了解 Android 框架组件,我还有哪些选择可以保持 MVP 架构的整洁?

【问题讨论】:

    标签: android android-mvp


    【解决方案1】:

    您可以使用软件约定/原则,例如

    "dependency inversion principle"

    "ports and adapters"

    你的模型层应该了解Android如果你能避免它才是重点。


    试试这样的:

    型号:

    private final SocialLoginProvider socialLoginProvider;
    
    public MyModel(SocialLoginProvider socialLoginProvider) {
           this.socialLoginProvider = socialLoginProvider;
    }
    
    public void authWithLinkedin(final IAuth listener) {
           socialLoginProvider.init(buildScope(), new SocialLoginProvider.Listener() {
    
            @Override
            public void onAuthSuccess() {
                listener.onSuccess();
            }
    
            @Override
            public void onAuthError() {
                listener.onError();
            }
    
        }, true);
    }
    

    工厂:

    public MyModel getModel(Context context) {
        LISessionManager li = LISessionManager.getInstance(context);
        SocialLoginProvider provider = new LinkedInSocialLoginProvider(context, li);
        return new MyModel(provider);
    }
    

    界面:

    public interface SocialLoginProvider {
         void init(Scope scope, Listener listener);
    
         interface Listener {
               void onAuthSuccess();
               void onAuthError();
         } 
    }
    

    SocialLoginProvider 的适配器:

    public class LinkedInSocialLoginProvider implements SocialLoginProvider {
    
              private final Context context;
              private final LISessionManager linkedInSessionManager;
    
              public LinkedInSocialLoginProvider(Context context, LISessionManager linkedInSessionManager) {
                   this.context = context;
                   this.linkedInSessionManager = linkedInSessionManager;
              }
    
              @Override
              public void init(Scope scope, Listener listener) {
                  linkedInSessionManager.init(context, scope, 
                        new AuthListener() {
                          @Override
                          public void onAuthSuccess() {
                             listener.onSuccess();
                          }
    
                          @Override
                          public void onAuthError(LIAuthError error) {
                             listener.onError();
                          }
                       }, true);
               }
    
    }
    

    【讨论】:

    • 我已经尝试实现您的想法,但我仍然很难理解事物最终如何连接到 View 层。如果我们尝试描述一般过程,我有一个演示者对象,它包含一个视图和一个存储库(当然是通过它们的接口)。如果我理解正确,在我的存储库中,我需要与工厂交互,这是了解上下文对象存在的最高层。但为了做到这一点,我需要通过演示者从视图发送此上下文,然后通过存储库从演示者发送此上下文。所以我还是有同样的问题。
    • no MyModel 应该由 LinkedInSocialLoginProvider 和你的 Repository 组成,这一切都在 Activity onCreate 中实例化(连接)通常所以你有 Context 那里。我展示的getModel 方法希望你在Activity 中使用类似new Presenter(view, model);
    【解决方案2】:

    理想情况下,模型层中有 Android 框架组件是可以的。例如,您将需要Context 使用getDefaultSharedPreferences(Context) 在本地存储/访问数据和/或使用SQLiteOpenHelper 管理本地数据库。

    LISessionManager.getInstance(MyApplication.getContext()).init 看起来像BroadcastReceiver,因为它是一种从外部组件接收特定结果的侦听器。处理这种情况可以参考this

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-26
      • 2019-08-07
      • 1970-01-01
      相关资源
      最近更新 更多