0

I'm working with MVP structure using Dagger 2

I can work really well with Activity & Fragment via property injection to get an instance of a presenter, BaseTopPresenter.

My issue is I need to inject my presenter BaseTopPresenter presenter; into a Service FirebaseMsgService without getting the static method getComponent() inside the activity to get the component and call inject() to get the presenter BaseTopPresenter.

p/s : I thought about using LocalBroadcastReceiver to do UI updates from the Service but I am trying to do MVP. Please help me by providing an elegant way of obtaining an instance of the presenter inside my Service because I have many use cases for it.

inside 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();
    }
    }

inside 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());
    }

}

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

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

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

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

inside Component.java:

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

inside AppComponent.java:

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

    // Get Shared Pref.
    PreferenceStore getPreferenceStore();

    Context context();
}

inside 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();
    }

}

UPDATE : After tried the Alex's answer. It is not right for my case.

Actually, my case :

I want to get Component object in BaseActivity. People have the other idea?

Huy Tower
  • 7,769
  • 16
  • 61
  • 86

1 Answers1

0

You can store you component in Application and access it everywhere using interfaces and casting:

Example:

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

public class MainApplication extends Application implements HasComponent<AppComponent> {

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

Within your Service, get application context and cast it to that interface like this:

((HasComponent<AppComponent>) getApplication()).getComponent();
David Rawson
  • 20,912
  • 7
  • 88
  • 124
Alex Shutov
  • 3,217
  • 2
  • 13
  • 11
  • Actually, this way work with `MainApplication`. But in my case, I want to get `Component` object in `BaseActivity` (line `private static Component Component;`). I tried do the same, but looks like different .Do you have the other idea? – Huy Tower Nov 23 '16 at 04:55