使用 Dagger 2 注入 SharedPreference class 时出现问题

Having problem in injecting SharedPreference class using Dagger 2

我是 Dagger 概念的新手,我猜我已经在一定程度上理解了,但在注入 classes 时一直遇到问题。我浏览了很多教程和示例代码,但是当我必须使用一个组件对多个模块进行操作时,我最终遇到了一个错误,而且大多数情况下,共享首选项模块没有被注入。无法理解实际错误或我犯的错误,需要一些帮助。

我的组件class:

@Singleton
@Component(modules = {VehicleModule.class, AppPreference.class})
public interface AppComponent {
//    void injectPreference(MainActivity activity);

 void inject(MainActivity activity);
 Vehicle provideVehicle();
}

我的共同偏好class:

@Module
public class AppPreference {
private SharedPreferences preferences;
private SharedPreferences.Editor edit;

@ApplicationScope
@Provides
@Inject
public SharedPreferences getPreferences() {
    return preferences;
}

public AppPreference(Context context) {
//        preferences       =   PreferenceManager.getDefaultSharedPreferences(context);
    preferences     =   context.getSharedPreferences(context.getString(R.string.app_name), MODE_PRIVATE);
    edit            =   preferences.edit();
}

@Singleton
@Provides
public String setDataPref(String strKey, String strValue) {
    edit.putString(strKey, strValue);
    commitPreference();
    return strKey;
}

@Singleton
@Provides
public String removeFromPreference(String strKey) {
    edit.remove(strKey);
    return strKey;
}

public void commitPreference()
{
    edit.commit();
}

@Singleton
@Provides
public String getDataPref(String strKey) {
    return preferences.getString(strKey, "");
}

@Singleton
@Provides
public boolean clear() {
    edit.clear();
    commitPreference();

    return true;
}
}

我的申请Class:

public class AppInstance extends Application {

AppComponent component;

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

    component = DaggerAppComponent.builder().appPreference(new AppPreference(getApplicationContext())).build();
}

public AppComponent getComponent() {
    return component;
}
}

最后我的 Activity:

public class MainActivity extends AppCompatActivity {

 //    @Inject
 //    AppPreference preference;

private AppComponent appComponent;
Vehicle vehicle;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });

    appComponent = DaggerAppComponent.builder().vehicleModule(new VehicleModule()).build();
    vehicle = appComponent.provideVehicle();

    ((AppInstance) getApplicationContext()).getComponent().inject(this);
}
}

此代码能够构建 DaggerAppComponent,但是一旦我在 Mainactivity 中注入 AppPreference,它就不再起作用了。

我在注入首选项时做错了什么 class? 需要帮助..

您需要将 SharedPreference class 的实例提供到 Dagger Graph 中,根据您的代码,您可以实现以下目标,

AppModule.java

@Module
class AppModule{

   @Provides
   @Singleton
   public SharedPreference providesSharedPreferences(application:Application){
      return new AppPreference(application);
   }


}

AppPreferences.java


public class AppPreference {
private SharedPreferences preferences;
private SharedPreferences.Editor edit;

public SharedPreferences getPreferences() {
    return preferences;
}

public AppPreference(Context context) {
//        preferences       =   PreferenceManager.getDefaultSharedPreferences(context);
    preferences     =   context.getSharedPreferences(context.getString(R.string.app_name), MODE_PRIVATE);
    edit            =   preferences.edit();
}


public String setDataPref(String strKey, String strValue) {
    edit.putString(strKey, strValue);
    commitPreference();
    return strKey;
}


public String removeFromPreference(String strKey) {
    edit.remove(strKey);
    return strKey;
}

public void commitPreference()
{
    edit.commit();
}

public String getDataPref(String strKey) {
    return preferences.getString(strKey, "");
}


public boolean clear() {
    edit.clear();
    commitPreference();

    return true;
}
}  

AppComponent.java

@Singleton
@Component(modules = {VehicleModule.class, AppModule.class})
public interface AppComponent {
 void inject(MainActivity activity);
 Vehicle provideVehicle();
}

MainActivity.java

class MainActivity extends Activity{

@Inject 
SharedPreference sharedPreference; //this is injected like this



}

在你的情况下,我会让 AppPreference 成为一个单例,并在需要的地方@Inject 它。

首先,您的组件应该如下所示:

@Singleton // Constraints this component to one-per-application or unscoped bindings.
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

        void inject(MainActivity mainActivity);

        //Exposed to sub-graphs

        Context context();

        AppPreference appPreference();
        }
}

那么你的模块应该是这样的:

@Module
public class ApplicationModule {
    private final Application application;

    public ApplicationModule(Application application) {
        this.application = application;
    }

    private final Application application;

    public ApplicationModule(Application application) {
         this.application = application;
    }

    @Provides
    @Singleton
    Context provideApplicationContext() {
        return application;
    }

    @Provides
    @Singleton
    AppPreference provideAppPreference() {
        return new AppPreference(provideApplicationContext());
    }
}

然后在您的应用程序 class 中初始化应用程序组件,同时保留对它的引用以便您以后可以使用它:

public ApplicationComponent getComponent() {
    return applicationComponent;
}

private void initializeInjector() {
        applicationComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this))
                .build();
    } 

像这样在 onCreate() 上注入 Main Activity 后:

MyApplication.get(this).getComponent().inject(this);

您终于可以使用了:

 @Inject
 AppPreference preference;

您弄错了几个概念和注释。

您可以通过使用 @Inject 注释字段或构造函数来注入对象。对于 Android 活动,您只能使用字段方法。所以你的 MainActivity.class 应该看起来更像这样:

public class MainActivity extends AppCompatActivity {

    @Inject
    SharedPreference preference;

    @Inject
    Vehicle vehicle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Inject dependencies into MainActivity
        ((AppInstance) getApplicationContext()).getComponent().inject(this);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }
}

您也不需要在 AppPreferences 模块中使用 @Inject 注释,因为您是 提供 依赖项,而不是 注入 那里。

说到提供,只要要注入 return 类型,就会调用带有 @Provides 注释的方法。如果有多个具有相同 return 类型的提供程序方法,则必须使用 @Named 注释或自定义限定符来区分它们。您的 AppPreferences 模块中有多个 return String 提供程序方法,但是我认为它们没有正确标记为提供程序,它们看起来更像是对 SharedPreferences 对象。清理后你应该留下这个模块:

@Module
public class AppPreference {
    private SharedPreferences preferences;

    public AppPreference(Context context) {
        preferences = context.getSharedPreferences(context.getString(R.string.app_name), MODE_PRIVATE);
    }

    @ApplicationScope
    @Provides
    public SharedPreferences getPreferences() {
        return preferences;
    }
}

并且您必须像对 Vehicle class:

那样在组件中公开 SharedPreferences
@Singleton
@Component(modules = {VehicleModule.class, AppPreference.class})
public interface AppComponent {
    void inject(MainActivity activity);

    SharedPreferences sharedPreferences();
    Vehicle vehicle();
}

编辑: 如果你想要某种 SharedPreferences 功能的包装器,你可以创建一个自定义的 class (它既不是 Dagger 组件也不是模块),例如MyAppPreferences:

public class MyAppPreferences {
    private SharedPreferences preferences;

    public MyAppPreferences(SharedPreferences preferences) {
        this.preferences = preferences;
    }

    // put setDataPref, removeFromPref, etc. in here
}

然后像这样注入:

@Module
public class AppPreferencesModule {
    private Context context;

    public AppPreferencesModule(Context context) {
      this.context = context;
    }

    // Dagger will inject the SharedPreferences object using the providePreferences() provider
    @ApplicationScope
    @Provides
    public MyAppPreferences provideMyAppPreferences(SharedPreferences preferences) {
        return new MyAppPreferences(preferences);
    }

    @ApplicationScope
    @Provides
    private SharedPreferences providePreferences() {
        return context.getSharedPreferences(context.getString(R.string.app_name), MODE_PRIVATE);
    }
}

@Singleton
@Component(modules = {VehicleModule.class, AppPreferencesModule.class})
public interface AppComponent {
    void inject(MainActivity activity);

    // expose MyAppPreferences instead of SharedPreferences
    MyAppPreferences myAppPreferences();
    Vehicle vehicle();
}

public class MainActivity extends AppCompatActivity {

    // inject MyAppPreferences instead of SharedPreferences
    @Inject
    MyAppPreferences myAppPreferences;

    ...
}