Експериментирам малко с Dagger на Android, което изглежда е добър инструмент за изолиране на зависимости. На първо място копирах примера за android-activity-graphs от GitHub: 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)... за известно време. Отново HomeFragment е повече или по-малко идентичен с HomeFragment от примерите в github, с няколко мои допълнения. Ако извикам каквото и да е на един от инжектираните обекти Player или RandomNumberGenerator в onCreateView() на HomeFragment, получавам грешка, че са нулеви. Ако обаче ги извикам във вътрешния 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. Ето MyAndroidTestPlayer, който имплементира Player (само един метод 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);
}
}
}
Благодаря ви предварително.