【问题标题】:Inject existing MVP presenter from Activity into Service via Dagger2通过 Dagger2 将现有的 MVP 演示者从 Activity 注入到服务中
【发布时间】:2016-11-21 10:50:14
【问题描述】:

我正在使用 Dagger 2 处理 MVP 结构

我可以很好地使用ActivityFragment 通过属性注入来获取演示者的实例BaseTopPresenter

我的问题是我需要将我的演示者BaseTopPresenter presenter; 注入到服务FirebaseMsgService 中,而不需要在活动中获取静态方法getComponent() 来获取组件并调用inject() 来获取演示者BaseTopPresenter

p/s :我曾考虑使用 LocalBroadcastReceiverService 进行 UI 更新,但我正在尝试做 MVP。请提供一种优雅的方式来帮助我在我的Service 中获取演示者的实例,因为我有很多用例。

在 MainApplication.java 中:

public class MainApplication extends Application {

    /**
     * Dagger 2
     */
    private AppComponent appComponent;

    public static AppComponent getAppComponent(Context context) {
        return ((MainApplication) context.getApplicationContext()).appComponent;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        // Dagger 2
        appComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .networkModule(new NetworkModule(getString(R.string.base_url)))
                .build();
    }
    }

在 FirebaseMsgService.java 中:

@ActivityScope
public class FirebaseMsgService extends FirebaseMessagingService {

    @Inject
    BaseTopPresenter presenter;
    @Inject
    PreferenceStore preferences;

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        // Dagger 2 : ACTUALLY I DON'T WANT USE THIS STATIC METHOD ANYMORE
        // I'M TRYING TO FIND THE OTHER WAY TO GET EXISTED PRESENTER VIA @INJECT HERE
        BaseActivity.getAsukabuComponent().inject(this);

        if (remoteMessage != null)  sendNotification(remoteMessage);
    }

    private void sendNotification(RemoteMessage remoteMessage) {
        NotificationManager notificationManager = (NotificationManager)
                getSystemService(Context.NOTIFICATION_SERVICE);
        // PRESENTER AS PARAMETER
        CustomizeNotification customizeNotification =
                new CustomizeNotification(this, presenter, remoteMessage);

        notificationManager.notify(customizeNotification.getNotifyType(), customizeNotification.build());
    }

}

在 CustomizeNotifications.java 中:

public class CustomizeNotification extends NotificationCompat.Builder {

private BaseTopPresenter presenter;

// Data
private static final int NEW_FOLLOWER = 1;

private static final String KEY_IS_FOLLOWER = "is_follower";
private static final String KEY_NOTIFICATION_MESSAGE = "notification_message";
private static final String KEY_EXTRA_NOTIFICATION_DATA = "KEY_EXTRA_NOTIFICATION_DATA";

private int notifyType = 0;
private RemoteMessage remoteMessage;

// The others
private Context context;

public CustomizeNotification(Context context, BaseTopPresenter presenter, RemoteMessage remoteMessage) {
    super(context);

    this.presenter = presenter;
    this.context = context;
    this.remoteMessage = remoteMessage;

    // Inject dagger 2
    Map<String, String> map = remoteMessage.getData();

    Bundle mBundle = new Bundle();
    for (Map.Entry<String, String> entry : map.entrySet())
        mBundle.putString(entry.getKey(), entry.getValue());

    Intent intent = new Intent(context, StockActivity.class);
    intent.putExtra(KEY_EXTRA_NOTIFICATION_DATA, mBundle);

        notifyType = Integer.valueOf(mBundle.getString(KEY_NOTIFY_TYPE));

        switch (notifyType) {
            case NEW_FOLLOWER:
                if (remoteMessage.getNotification().getBody() != null)
                    implementFollower(intent, mBundle, remoteMessage.getNotification().getBody());
                break;
        }
}

private void implementFollower(Intent intent, Bundle mBundle, String body) {
        // Show dialog only
        runInForeground(mBundle);
}

private void runInForeground(Bundle mBundle) {
    // Handler
    Handler handler = new Handler(Looper.getMainLooper());

    // Foreground : I NEED UPDATE EXISTED DATA ON UI IN HERE
    handler.post(() -> {
        presenter.updateNotification(mBundle);
    });
}
}

在 BaseTopPresenter.java 中:

@ActivityScope
public class BaseTopPresenter extends BasePresenter {
@Inject
    public BaseTopPresenter(AsukabuApi asukabuApi, PreferenceStore preferenceStore) {
        super(asukabuApi, preferenceStore);
    }

public void updateNotification(Bundle mBundle) {
        if (notificationView != null)   notificationView.onUpdateNotifications(mBundle);
    }
}

BaseTopActivity.java 内:

    @ActivityScope
    public abstract class BaseTopActivity extends BaseActivity implements       BaseTopView, BaseTopView.NotificationView {
    @Inject
    BaseTopPresenter baseTopPresenter;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /**
         * Dagger2
         */
        getAsukabuComponent().inject(this);
    }

    @Override
    public void onUpdateNotifications(Bundle mBundle) {
        // Handle notifications

                    // show dialog
                    if (dialog != null) dialog.dismiss();
                    dialog = CustomDialog.getInstance(
                            mBundle.getString(KEY_NOTIFICATION_MESSAGE),
                            new CustomDialog.DialogButton(getString(R.string.OK),
                                    (dialog1, which) -> {
                                    }), new CustomDialog.DialogButton(getString(R.string.cancel),
                                    (dialog12, which) -> dialog12.dismiss()));

                    // show
                    dialog.show(getSupportFragmentManager());
                    break;
            }
        }
    }

BaseActivity.java 内:

@ActivityScope
public abstract class BaseActivity extends AppCompatActivity implements BaseView {

    // I DON'T WANT USE THIS STATIC VAR ANYMORE, TRYING TO GET THIS EXIST COMPONENT IN SERVICE WITHOUT CREATE INSTANCE AGAIN
    private static Component Component;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Dagger 2
    Component = DaggerComponent.builder()
            .appComponent(MainApplication.getAppComponent(this)).build();
    }

    public static Component getComponent() {
        return Component;
    }
}

在 Component.java 中:

@ActivityScope
@Component(dependencies = {AppComponent.class})
public interface Component {
// Services
void inject(FirebaseIDService service);
void inject(FirebaseMsgService service);
}

在 AppComponent.java 中:

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
    // Get FCM API
    FCMApi getFCMApi();

    // Get Shared Pref.
    PreferenceStore getPreferenceStore();

    Context context();
}

在 AppModule.java 中:

@Module
public class AppModule {

    private Application mApplication;

    public AppModule(Application application) {
        mApplication = application;
    }

    @Singleton
    @Provides
    Context provideContext() {
        return mApplication.getApplicationContext();
    }

    @Provides
    @Singleton
    Application providesApplication() {
        return mApplication;
    }

    @Singleton
    @Provides
    SharedPreferences provideSharedPreferences(Context context) {
        return context.getSharedPreferences(PREF, Context.MODE_PRIVATE);
    }

    @Singleton
    @Provides
    SharedPreferences.Editor provideSharedPreferencesEditor(SharedPreferences sharedPreferences) {
        return sharedPreferences.edit();
    }

}

更新:在尝试了亚历克斯的回答之后。这不适合我的情况。

其实我的情况:

我想在BaseActivity 中获取Component 对象。人们有其他想法吗?

【问题讨论】:

  • inject()Service 中的正确位置是onCreate(),不是吗?
  • @DavidRawson:完全正确。

标签: java android mvp dagger-2 dagger


【解决方案1】:

您可以将组件存储在Application 中,并使用接口和强制转换在任何地方访问它:

例子:

public interface HasComponent<T> {
    T getComponent();
}

public class MainApplication extends Application implements HasComponent<AppComponent> {

    //your code, then
    @Override
    public AppComponent getComponent() {
        return this.appComponent;
    }
}

在您的服务中,获取应用程序上下文并将其转换为该接口,如下所示:

((HasComponent<AppComponent>) getApplication()).getComponent();

【讨论】:

  • 实际上,这种方式适用于MainApplication。但就我而言,我想在BaseActivity(行private static Component Component;)中获取Component 对象。我试过做同样的事情,但看起来不一样。你有其他想法吗?
猜你喜欢
  • 2016-11-15
  • 1970-01-01
  • 2020-05-01
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多