29

我开始使用Dagger设置依赖注入,如下所示。请感到鼓舞来纠正我的实施,因为我可能在那里有错误!实现遵循项目提供的android-simple 示例。在下文中,您可以看到我如何成功地为ActivitiesFragments. 我现在尽量保持简单,所以我决定注入Timber作为Android 的 log util的记录器替代品。

import android.app.Application;
import java.util.Arrays;
import java.util.List;
import dagger.ObjectGraph;
import com.example.debugging.LoggingModule;

public class ExampleApplication extends Application {

    private ObjectGraph mObjectGraph;

    protected List<Object> getModules() {
        return Arrays.asList(
                new AndroidModule(this),
                new ExampleModule(),
                new LoggingModule()
        );
    }

    private void createObjectGraphIfNeeded() {
        if (mObjectGraph == null) {
            Object[] modules = getModules().toArray();
            mObjectGraph = ObjectGraph.create(modules);
        }
    }

    public void inject(Object object) {
        createObjectGraphIfNeeded();
        mObjectGraph.inject(object);
    }
}

到目前为止,AndroidModule它没有在任何地方使用,但在需要 aContext和时可能会有所帮助,LayoutInflater例如在CursorAdapters.

import android.content.Context;
import android.view.LayoutInflater;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;

/**
 * A module for Android-specific dependencies which require a {@link Context} 
 * or {@link android.app.Application} to create.
 */
@Module(library = true)
public class AndroidModule {
    private final ExampleApplication mApplication;

    public AndroidModule(ExampleApplication application) {
        mApplication = application;
    }

    /**
     * Allow the application context to be injected but require that it be 
     * annotated with {@link ForApplication @Annotation} to explicitly 
     * differentiate it from an activity context.
     */
    @Provides @Singleton @ForApplication Context provideApplicationContext() {
        return mApplication;
    }

    @Provides @Singleton LayoutInflater provideLayoutInflater() {
        return (LayoutInflater) mApplication
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
}

我不确定哪些特定于应用程序的提供程序会出现在这里。我现在继续记录

import dagger.Module;

@Module(
        complete = false
)
public class ExampleModule {
    public ExampleModule() {
         // TODO put your application-specific providers here!
    }
}

我准备LoggingModule了提供对Timber的访问。

package com.example.debugging;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
import com.example.BuildConfig;
import com.example.activities.BaseFragmentActivity;
import com.example.activities.DetailsActivity;
import com.example.fragments.BaseListFragment;
import com.example.fragments.ProfilesListFragment;
import timber.log.Timber;

@Module(injects = {
        // Activities
        BaseFragmentActivity.class,
        DetailsActivity.class,
        // Fragments
        BaseListFragment.class,
        ProfilesListFragment.class
})
public class LoggingModule {

    @Provides @Singleton Timber provideTimber() {
        return BuildConfig.DEBUG ? Timber.DEBUG : Timber.PROD;
    }
}

基类Activities将自身注入到对象图中...

package com.example.activities;

import android.os.Bundle;    
import com.actionbarsherlock.app.SherlockFragmentActivity;    
import javax.inject.Inject;
import com.example.ExampleApplication;
import timber.log.Timber;

public abstract class BaseFragmentActivity extends SherlockFragmentActivity {

    @Inject Timber mTimber;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        super.onCreate(savedInstanceState);
        ((ExampleApplication) getApplication()).inject(this);
    }
}

......以及木材已经存在的任何子类的好处。

package com.example.activities;

import android.os.Bundle;
import com.example.R;

public class DetailsActivity extends BaseFragmentActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_details);
        mTimber.i("onCreate");
        // ...
    }
}

相同的Fragments:基类做了肮脏的工作......

package com.example.fragments;

import android.os.Bundle;
import com.actionbarsherlock.app.SherlockListFragment;
import javax.inject.Inject;
import com.example.ExampleApplication;
import timber.log.Timber;

public abstract class BaseListFragment extends SherlockListFragment {

    @Inject Timber mTimber;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        ((ExampleApplication) getActivity().getApplication()).inject(this);
    }

}

...并且子类受益于其超类。

package com.example.fragments;

import android.os.Bundle;

public class ProfilesListFragment extends BaseListFragment {

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // TODO This might be a good example to inject resources
        // in the base class. But how?
        setEmptyText(getResources()
           .getString(R.string.profiles_list_no_content));
        mTimber.i("onActivityCreated");
        // ...
    }

}

到目前为止,一切都很好。但是如何将Timber注入到, , , 和BaseCursorAdapterhelperBaseContentProvider方法BaseSQLiteOpenHelperBaseService呢?BaseAsyncTaskstatic

Christopher Perry不推荐使用的android 示例指出了如何将Adapter注入ListFragment,但没有指出如何将Context, Resources, LayoutInflater,Cursor注入(Cursor)Adapter或只是Timber


参考:

4

5 回答 5

8

查看 Andy Dennie 在不同场景中的注入示例:

https://github.com/adennie/fb-android-dagger

我注入的一些点:

  • Activity, Service, 和Fragment子类:在onCreate
  • BroadcastReceiver子类(包括,例如AppWidgetProvider):在onReceive
于 2013-10-03T08:54:20.617 回答
5

tl; dr 这个问题有很多内容,但我的 Gist可能会有所帮助。如果你能找到一个地方,你可以根据你的班级维护Context来注入它。ObjectGraphApplication


JJD编辑:

ObjectGraphGist 中可以集成如下:

public class ExampleApplication extends Application
        implements ObjectGraph.ObjectGraphApplication {

/* Application Lifecycle */
    @Override
    public void onCreate() {
        // Creates the dependency injection object graph
        _object_graph = ObjectGraph.create(...);
    }

/* ObjectGraphApplication Contract */
    @Override
    public void inject(@Nonnull Object dependent) {
        _object_graph.inject(dependent);
    }

    /** Application's object graph for handling dependency injection */
    private ObjectGraph _object_graph;
}

...

public abstract class BaseFragmentActivity extends SherlockFragmentActivity {
    @Inject Timber _timber;

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        ObjectGraph.inject(this);
    }
}

...

public abstract class BaseListFragment extends SherlockListFragment {    
    @Inject Timber _timber;

    @Override
    public void onActivityCreated(Bundle icicle) {
        super.onActivityCreated(icicle);
        ObjectGraph.inject(this);
    }
}

BaseCursorAdapter的类似作品。BaseContentProviderBaseService

于 2013-09-20T16:49:43.970 回答
2

注入Context,ResourcesLayoutInflater(在应用程序中新建时传递应用程序上下文)。

@Module(complete = false)
public class AndroidServicesModule {
  private final Context context;

  public AndroidServicesModule(@ForApplication Context context) {
    this.context = context;
  }

  @Provides @Singleton Resources provideResources() {
    return context.getResources();
  }

  @Provides @Singleton LocationManager provideLocationManager() {
    return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
  }

  @Provides @Singleton LayoutInflater provideLayoutInflater() {
    return (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  }

  @Provides @Singleton Resources provideResources() {
    return context.getResources();
  }

  @Provides @ForApplication Context provideContext() {
    return context;
  }
}

当然,您可能应该使用注释来限定上下文,指定它是应用程序上下文(例如@ForApplication)。

如果您需要与 Roboguice 相当的产品,@InjectResource(int)我想不出任何即兴的东西。Butterknife 似乎是添加它的正确库。看这里

于 2014-01-15T23:55:58.543 回答
2

我们必须做同样的事情(即到处注入一个记录器)。我们最终制作了一个非常小的静态包装器(因此随处可用),它包装了一个通过 dagger 静态注入的类。

package com.example.secret;

import javax.inject.Inject;

import com.example.interfaces.Logger;

public class LoggerProvider {

    @Inject
    static Logger logger;

    public LoggerProvider() {

    }

    public static Logger getLogger() {
            return logger;
    }

}

Logger 实现了你的日志接口。要在应用程序级别注入它,您需要:

   graph = ObjectGraph.create(getModules().toArray());
   graph.injectStatics();

此处代码:https ://github.com/nuria/android-examples/tree/master/dagger-logger-example

于 2013-11-15T11:38:31.233 回答
0

您可以将这些结构添加到ExampleApplication类中:

private static ExampleApplication INSTANCE;

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

    INSTANCE = this;
    mObjectGraph = ObjectGraph.create(getModules());
    mObjectGraph.injectStatics();
    mObjectGraph.inject(this);
}

public static ExampleApplication get() {
    return INSTANCE;
}

之后,您可以this使用一行简单的代码注入任何对象(用 表示):

ExampleApplication.get().inject(this)

这应该在您手动创建的对象或onCreate(或模拟)由 Android 系统管理的对象的构造函数中调用。

于 2013-09-22T21:12:39.737 回答