通过Dagger2将现有的MVP演示者从Activity注入服务

时间:2016-11-21 10:50:15

标签: java android mvp dagger-2 dagger

我正在使用Dagger 2

处理MVP结构

我可以与Activity& Fragment通过属性注入来获取演示者的实例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();
    }

}

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

实际上,我的情况:

我想在Component中获取BaseActivity个对象。人们有另一个想法吗?

1 个答案:

答案 0 :(得分:0)

您可以将组件存储在<!DOCTYPE html> <html lang="en"> <head> <title>TASKS</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script> </head> <body ng-app="app"> <div ng-controller="sampleController"> <h3>To do</h3> <table class="table table-striped table-hover col-sm-4"> <thead> <tr> <th>Task</th> <th>Time</th> <th>Done</th> </tr> </thead> <tbody ng-repeat="x in firstTable"> <tr> <td>x.taskName</td> <td> x.tastTime</td> <td><input type="checkbox" ng-click="moveData($index)"/></td> </tr> </tbody> </table> <h3>Done</h3> <table class="table table-striped table-hover col-sm-4"> <thead> <tr> <th>Task</th> <th>Time</th> <th>Done</th> </tr> </thead> <tbody ng-repeat="x in secondTable"> <tr> <td>x.taskName</td> <td> x.tastTime</td> <td><input type="checkbox" /></td> </tr> </tbody> </table> </div> </body> <script> var app=angular.module("app",[]); app.controller("sampleController",["$scope",function($scope){ $scope.firstTable=[{taskName:'Task_One',tastTime:'5 min'},{taskName:'Task_Two',tastTime:'2 min'},{taskName:'Task_Three',tastTime:'2 min'}]; $scope.secondTable=[]; $scope.moveData=function(index){ $scope.secondTable.push($scope.firstTable[index]); $scope.firstTable.splice(index,1); }; }]); </script> </html>中,并使用接口和转换访问它:

示例:

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;
    }
}