Dagger 2, Предоставление контекста приложения в модуле - PullRequest
0 голосов
/ 02 июня 2018

Я довольно новичок в разработке для Android и новее в DI.Я использую Kotlin в личном проекте, где я экспериментирую с Dagger 2. Мне удалось настроить его для класса util, но там, где мне нужно иметь контекст, чтобы использовать его для внедрения класса, который требует контекста (менеджер sharedprefкласс) мне не удалось.Вот мой код, и вот ошибка (NPE), которую я получаю.Заранее благодарю.

мой класс модуля

package com.android.pine

import android.content.Context
import com.android.pine.utils.SharedPreferencesManager
import dagger.Module
import dagger.Provides
import javax.inject.Singleton

@Module
class AppModule {

    @Provides
    @Singleton
    fun context(pineApplication: PineApplication): Context = pineApplication.applicationContext

    @Provides
    @Singleton
    fun provideSharedPrefManager(context: Context): SharedPreferencesManager = SharedPreferencesManager(context)
}

мой класс компонента:

package com.android.pine

import com.android.pine.home.HomePresenter
import com.android.pine.home.categories.CategoryAdapter
import dagger.Component
import javax.inject.Singleton

@Singleton
@Component(modules = arrayOf(AppModule::class))
interface AppComponent {
    fun inject(categoryAdapter: CategoryAdapter)
    fun inject(homePresenter: HomePresenter)
}

edit: добавлена ​​информация ниже, как я вызываю внедрение метода sharedPreferencesManager:

class HomePresenter : BasePresenter<HomeView>() {

    @Inject
    lateinit var sharedPreferencesManager: SharedPreferencesManager
.
.
.

Также в моем классе HomePresenter, в переопределении метода onAttached:

 DaggerAppComponent.create().inject(this)

Мой класс pineApplication и класс SharedPrefManager выглядят так:

class PineApplication @Inject constructor(): Application()

SharedPref:

class SharedPreferencesManager @Inject constructor(context: Context) {
.
.
.

Сбой, не удается получить pineApplication.getContext () (отредактировано, добавлена ​​полная трассировка стека)

     06-02 11:57:01.028 14840-14840/com.android.pine.debug E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.pine.debug, PID: 14840
java.lang.RuntimeException: Unable to resume activity {com.android.pine.debug/com.android.pine.home.HomeActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3429)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3469)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2732)
    at android.app.ActivityThread.-wrap12(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6119)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
    at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:106)
    at com.android.pine.AppModule.context(AppModule.kt:12)
    at com.android.pine.AppModule_ContextFactory.proxyContext(AppModule_ContextFactory.java:34)
    at com.android.pine.DaggerAppComponent.getContext(DaggerAppComponent.java:29)
    at com.android.pine.DaggerAppComponent.getSharedPreferencesManager(DaggerAppComponent.java:34)
    at com.android.pine.DaggerAppComponent.injectHomePresenter(DaggerAppComponent.java:59)
    at com.android.pine.DaggerAppComponent.inject(DaggerAppComponent.java:49)
    at com.android.pine.home.HomePresenter.onAttached(HomePresenter.kt:31)
    at com.android.pine.home.HomePresenter.onAttached(HomePresenter.kt:10)
    at com.android.pine.core.BaseActivity.onResume(BaseActivity.kt:34)
    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1269)
    at android.app.Activity.performResume(Activity.java:6783)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3406)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3469) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2732) 
    at android.app.ActivityThread.-wrap12(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6119) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

Ответы [ 4 ]

0 голосов
/ 16 августа 2019

Вот как это делается.Использование @BindsInstance в вашем компоненте приведет к внедрению приложения во все ваши модули. В вашем случае просто в AppModule

@Singleton
@Component(modules = arrayOf(AppModule::class))
interface AppComponent {
    @Component.Builder
    interface Builder() {
        fun build(): AppComponent

        @BindsInstance
        fun application(application: Application): Builder
    }
}

** Удалите код для функции «Обеспечивает приложение» в вашем модуле APP и убедитесь, что вы передаете приложениеконтекст для создания sharedPreferences.

@Module
class AppModule {


@Provides
@Singleton
fun provideSharedPrefManager(context: Application): SharedPreferencesManager = 
    SharedPreferencesManager(context)
}

и теперь в вашем onCreate applicationClass

DaggerAppComponent.builder().application(this).build()

Необязательно: если вы хотите внедрить что-то в applicationClass, выполните следующее

 DaggerAppComponent.builder().application(this).build().inject(this)
0 голосов
/ 02 июня 2018

Для обеспечения контекста приложения вы можете создать класс, например ComponentsManager, с помощью:

public class ComponentsManager {

    private Context context;
    private AppComponent appComponent;

    public ComponentsManager(Context context) {
        this.context = context.getApplicationContext();
    }

    public AppComponent getAppComponent(){
        if (appComponent == null){
            appComponent = DaggerAppComponent.builder()
                    .appModule(new AppModule(context))
                    .build();
        }
        return appComponent;
    }
}

И в вашем классе приложения init это ComponentsManager выглядит так:

public class YourApp extends Application {

    private static ComponentsManager componentsManager;

    @Override
    public void onCreate() {
        super.onCreate();
        initComponentsManager();
        initAppComponent();
    }

    public static ComponentsManager getComponentsManager(){
        return componentsManager;
    }

    private void initComponentsManager(){
        componentsManager = new ComponentsManager(this);
    }

    private void initAppComponent(){
        componentsManager.getAppComponent();
    }
}
0 голосов
/ 05 июня 2018

Вы можете попробовать модифицировать свой модуль приложения следующим образом.

@Module
class ApplicationModule(private val application: Application) {

    @Provides
    @Singleton
    fun provideContext(): Context {
        return application.applicationContext
    }

    @Provides
    @Singleton
    fun provideSharedPreferences(context: Context): SharedPreferences {
        return context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE)
    }
}

Затем вы можете создать такой компонент кинжала из своего класса приложения.

val appComponent = DaggerAppComponent.builder()
                .applicationModule(ApplicationModule(this))
                .build()

Вставить значения в презентере какэто.

application.appComponent.inject(this)
0 голосов
/ 02 июня 2018

Вы не можете использовать class PineApplication @Inject constructor(): Application() для создания PineApplication.Это класс фреймворка, который должен быть создан в Android Framework.

В этом случае Dagger создаст PineApplication, но applicationContext вернет null, поскольку он никогда не был инициализирован (системой).

Не используйте инъекцию конструктора для классов каркаса и не создавайте сами.Используйте @Bindsintance, чтобы добавить объект в компонент с его компоновщиком, или используйте модуль для его предоставления.

...