Dagger注入 - 何时调用提供方法

时间:2015-03-18 13:30:02

标签: java android dependency-injection dagger

我正在尝试使用Android上的Dagger,这似乎是一个很好的工具来隔离依赖项。首先,我从GitHub复制了android-activity-graphs示例:https://github.com/square/dagger/tree/master/examples/android-activity-graphs

然后我在ActivityModule

中添加了几个类
@Module(
    injects = {
            HomeActivity.class,
            HomeFragment.class
    },
    addsTo = AndroidModule.class,
    library = true
)

public class ActivityModule {
    private static final String TAG = "Activity_Module";
    private final DemoBaseActivity activity;

    public ActivityModule(DemoBaseActivity activity) {
        this.activity = activity;
    }

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

    @Provides
    @Singleton
    ActivityTitleController provideTitleController() {
        return new ActivityTitleController(activity);
    }

    //My addition from here
    @Provides
    @Singleton
    Player providePlayer() {
        Log.i(TAG, "in providePlayer()");
        return new MyAndroidTestPlayer(activity);
    }

    @Provides
    RandomNumberGenerator provideRandomNumberGenerator() {
        Log.i(TAG, "in provideRandomNumberGenerator()");
        return new RealRandomNumberGenerator();
    }
}

图初始化的其余部分与github中的示例相同。

让我感到困惑的是,注入的对象在构造类(HomeFragment)之后会为null一段时间。 HomeFragment与来自github中的示例的HomeFragment或多或少相同,只增加了一些我自己的。 如果我在HomeFragment的onCreateView()中的任何一个注入的Player或RandomNumberGenerator对象上调用任何内容,我会收到一条错误消息,指出它们为空。 但是,如果我在内部OnClickListener - onClick()内部调用它们,它们将按预期工作。

有人能指出我所缺少的知识,以了解这里发生了什么吗?

public class HomeFragment extends DemoBaseFragment {
public static final String TAG = "HOME_FRAGMENT";

public static HomeFragment newInstance() {
    return new HomeFragment();
}

@Inject
ActivityTitleController titleController;
@Inject
Player player;
@Inject
RandomNumberGenerator randomNumberGenerator;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    TextView tv = new TextView(getActivity());
    if (randomNumberGenerator != null) {
        Log.i(TAG, "randomNumberGenerator is NOT null");
    } else {
        Log.e(TAG, "randomNumberGenerator is NULL!");
    }
    if (player != null) {
        Log.i(TAG, "player is NOT null");
    } else {
        Log.e(TAG, "player is NULL!");
    }
    //int randomNumber = randomNumberGenerator.getIntegerInRange(48, 50);
    //player.playTestNote();
    tv.setGravity(CENTER);
    tv.setText("Play test note");
    tv.setTextSize(40);
    tv.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            player.playTestNote();
            int randomNumber = randomNumberGenerator.getIntegerInRange(48, 50);
            Log.i(TAG, "Text view clicked, random number is: " + randomNumber);
        }
    });
    return tv;
}

我用来测试的类非常简单(RandomNumberGenerator比Player类更多)。我将跳过RandomNumberGenerator。这是实现Player的MyAndroidTestPlayer(只有一个playTestNote()方法)。

public class MyAndroidTestPlayer implements Player {

SoundPool soundPool;
private static final int MAX_STREAMS = 10;
private static final int DEFAULT_SRC_QUALITY = 0;
private static final int HARDCODED_SOUND_RESOURCE_C3 = R.raw.midi_48_c3;
private static final int DEFAULT_PRIORITY = 1;
private static final String TAG = "MyAndroidTestPlayer";
private Context context;
private boolean isLoaded = false;
private int streamId;
private int soundId;

public MyAndroidTestPlayer(Context context) {
    this.context = context;
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        createNewSoundPool();
    } else {
        createOldSoundPool();
    }
}

protected void createOldSoundPool() {
    soundPool = new SoundPool(MAX_STREAMS, AudioManager.STREAM_MUSIC, DEFAULT_SRC_QUALITY);
    Log.i(TAG, "created old sound pool");
    loadSoundPool();
}

protected void createNewSoundPool() {
    AudioAttributes attributes = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build();
    soundPool = new SoundPool.Builder().setAudioAttributes(attributes).build();

    Log.i(TAG, "created new sound pool");
    loadSoundPool();
}

private void loadSoundPool() {
    soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {

        @Override
        public void onLoadComplete(SoundPool soundPool, int sampleId,
                                   int status) {
            isLoaded = true;
            Log.i(TAG, "Loaded");
            Log.i(TAG, "Status: " + status);
        }
    });
    soundId = soundPool.load(context, HARDCODED_SOUND_RESOURCE_C3, DEFAULT_PRIORITY);
}

@Override
public void playTestNote() {
    Log.i(TAG, "before loaded check");
    if (isLoaded) {
        streamId = soundPool.play(soundId, 1, 1, 1, 0, 1f);
        Log.i(TAG, "Played Sound");
        Log.i(TAG, "streamId: " + streamId);
    }
}

}

提前谢谢。

1 个答案:

答案 0 :(得分:0)

我想我明白了。 HomeFragment必须@Override onCreate并注入以下行

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

    ((DemoBaseActivity) getActivity()).inject(this);
}

然后它适合我。

我希望这能帮助其他用户达到我的理解水平。