How to use Factories injected by Guice in android? - android

I have problem using Factory injected by Guice.
I've read this nice article http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/assistedinject/FactoryModuleBuilder.html but still don't understand something. I.e. why does Module never used? Like in Guice.createInjector() method.
I tried this simple application and I have NullPointerException, because Guice couldn't resolve Factory I need.
public interface FooInterface
{
String getString();
}
public class Foo implements FooInterface {
String bar;
#Inject
Foo(#Assisted String bar)
{
Log.i("main", "Foo constructor");
this.bar = bar;
}
public String getString(){
Log.i("main", "getString");
return this.bar;
}
}
public interface FooFactory
{
FooInterface create(String bar);
}
Here is configuration Module
public class ConfigurationModule extends AbstractModule
{
#Override
protected void configure()
{
Log.i("main", "Configuration module");
install(new FactoryModuleBuilder().implement(FooInterface.class, Foo.class).build(FooFactory.class));
}
}
And my Activity
public class MyActivity extends Activity implements View.OnClickListener
{
#Inject private FooFactory fooFactory;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i("main", "onCreate");
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(this);
}
#Override
public void onClick(View view)
{
Log.i("main", "onClick");
FooInterface foo = this.fooFactory.create("foo name");
String str = foo.getString();
Toast.makeText(getApplicationContext(), "String is: "+ str, Toast.LENGTH_SHORT);
}
}
As I can see from logs, Foo constructor is never called. The same with ConfigurationModule. I can't see where this module is used. Any ideas? Maybe I'm missing something?

From all I've read I start thinking that there is no advantages in using pure Guice for Android application. Roboguice is right choice.

If you need to use ActionBarSherlock as well, look at roboguice-sherlock.

Related

Dagger listener/interface injection

Hello everyone I've been struggling to understand how to inject a listener to a main activtity with Dagger2, I wonder if what I'm trying to do is possible or even a right move with dagger or should I just let it like it is right now I have read that I need to create another class with the implementation of that interface but is not possible(or recommended) to inject on the mainactivity?, thanks in advance to anyone who can help me, I have everything in short as follows:
//////////////////////////////////////MainActivity.class//////////////////////////////////////
public class MainActivity extends AppCompatActivity implements CustomListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//this is the object I want to inject in Dagger
LongProcess longProcess = new LongProcess(this);
longProcess.longRunningProcess();
}
#Override
public void onProcessStarted() {
Log.i(TAG, "onProcessStarted: CALLBACK!");
}
#Override
public void onProcessFailed() {
Log.e(TAG, "onProcessFailed: CALLBACK!");
}}
//////////////////////////////////////LongProcess.class//////////////////////////////////////
public class LongProcess {
private CustomListener customListener;
public LongProcess(CustomListener customListener) {
this.customListener = customListener;
}
public void longRunningProcess() {
try {
//some long process started...
customListener.onProcessStarted();
} catch (Exception e) {
//some long process failed...
customListener.onProcessFailed();
}
}
}
//////////////////////////////////////interface.java//////////////////////////////////////
public interface CustomListener {
void onProcessStarted();
void onProcessFailed();
}
You can take a look at Assisted Injection for this use case: https://dagger.dev/dev-guide/assisted-injection

Is it a good practice to access the Actvity's Context in the Presenter class? If no then is there any other better way to do it?

I am new to Android MVP Architecture. As far as I have researched the Presenter should be kept free from any android things like for example: Don't use getActivity or Context in the Presenters. I have written the following code where a BasePresenter is the parent class of all the Presenter classes that I will be using.The BaseView interface is the parent interface of all View classes and BaseActivity class is the parent class of all Activity classes. I have more than one activity and it is required to show Toast messages in all of my activity. So I have written the following code as follows. I am not very sure whether using the getactivity from the presenter class is a good practice or not. If it is not then can anyone suggest any better way to do it?
BasePresenter class
public class BasePresenter<V extends BaseView> {
private V mView;
private Context mContext;
public void attachView(V view) {
mView = view;
mContext=mView.getActivity();
}
public void showToast(String msg) {
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
}
private Context getContext() {
return mContext;
}
public void detachView() {
mView = null;
}
}
BaseView class
public interface BaseView {
AppCompatActivity getActivity();
}
BaseActivity class
public class BaseActivity extends AppCompatActivity {
public AppCompatActivity getActivity() {
return this;
}
}
MainActivity class
public class MainActivity extends BaseActivity implements MainView {
MainPresenter basePresenter;
#Override
protected void onStart() {
super.onStart();
basePresenter = new MainPresenter();
basePresenter.attachView(this);
}
// some more codes here
switch (item.getItemId()) {
case R.id.about:
basePresenter.showToast("About is Clicked");
break;
case R.id.cart:
basePresenter.showToast("Cart is Clicked");
break;
case R.id.favs:
basePresenter.showToast("Favs is Clicked");
break;
case R.id.home:
basePresenter.showToast("Home is Clicked");
break;
}
}
It is not a good idea. You Presenter (base or otherwise) should not know about Context, Activity, Toast or anything else Android based.
View
displays things.
handles user input and passes it to the Presenter.
Presenter
decides what to do with user input.
gathers data from the model.
tells the View what to do.
So for your example of clicking Buttons and showing Toasts you would need a setup something like:
View Interface
This is how your Presenter will talk to your View. It will be implemented by the Activity.
public interface MainView {
void showToast(String message);
}
Presenter (Base & Main)
BasePresenter has almost no tasks at all. Simply there to bind the View interface. Note the method names in the MainPresenter are ambiguous to things like 'click' to seperate them from the View implementation.
public class BasePresenter<V> {
protected V view;
public void attachView(V view) {
this.view = view;
}
}
public class MainPresenter extends BasePresenter<MainView> {
public void about() {
view.showToast("About was clicked");
}
public void cart() {
view.showToast("Cart was clicked");
}
}
Activity
The Activity implements the View interface. It's responsible for passing user events to the Presenter and actioning the Presenter commands.
public class MainActivity extends AppCompatActivity implements MainView {
private MainPresenter presenter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
presenter = new MainPresenter();
presenter.attachView(this);
Button about = findViewById(R.id.button_about);
about.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
presenter.about();
}
});
Button cart = findViewById(R.id.button_cart);
cart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
presenter.cart();
}
});
}
#Override
public void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
In this setup the Presenter no longer knows anything about Android (has no imports from the framework at all) and you are able to write unit tests for it which can run directly on the JVM without Android dependencies.
Toast is actually visible on screen. So It should not be in presenter. It should be triggered from the View.

Invoke Toast in an external class

I have an external class and I want to use Toast in this class.
I tried to implement this but I get an error.
How can I do this in easy way without any error?
public class ElevenActivity extends AppCompatActivity {
#
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_eleven);
}
public class MyToast {
public MyToast(String message) {
Toast.makeText(ElevenActivity.this, message, Toast.LENGTH_SHORT).show();
}
}
}
public class externalClass extends SQLiteOpenHelper {
public void CreateDB() {
ElevenActivity.MyToast t = new ElevenActivity.MyToast("Here");
}
}
Just make a Toast in the external class using getApplicationContext(). Like,
public class externalClass extends SQLiteOpenHelper {
public void CreateDB() {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
If you want to provide a method which should be valid for different contexts (e.g. activities), pass this context as parameter.
public static void textToast(String textToDisplay, Context context) { ... }
If you want to call this method from nested inner classes (as is often the case), you can use this as context
public void textToast(String textToDisplay) {
...
Toast toast = Toast.makeText(OuterClass.this, text, duration);
...
}
(or implement textToast in the outer class and call it via OuterClass.this.textToast from the nested inner class)
..........

Dagger, how to inject a class, not a module

According to JakeWharton's slide 97 at https://speakerdeck.com/jakewharton/2014, the object graph allows injecting a class.
However, I did try and I got an NPE, seems that the constructor of the said class is never called.
My code is as follow. I have no trouble with AppModule, which provides AnalyticsManager.
public class App extends Application implements ModuleCreator {
private ObjectGraph objectGraph;
#Inject
AnalyticsManager analyticsManager;
#Override
public void onCreate(){
super.onCreate();
objectGraph = ObjectGraph.create(getModules().toArray());
objectGraph.inject(RealBusEvent.class);
objectGraph.inject(Trip.class);
objectGraph.inject(this);
analyticsManager.registerAppEnter();
}
public List<Object> getModules() {
return Arrays.<Object>asList(new AppModule(this));
}
}
The other 2 classes:
public class RealBusEvent {
#Inject Trip trip;
#Inject
public RealBusEvent(){; }
public Trip getTrip() {
return trip;
}
}
public class Trip {
#Inject
public Trip(){
this.time = 123;
}
public Trip(long time) {
this.time = time;
}
public long getTime() {
return time;
}
private long time;
}
And the class consuming RealEventBus is like below:
public class MyActivity extends Activity {
#Inject RealBusEvent event;
TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
mTextView = (TextView) findViewById(R.id.txtView);
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mTextView.setText(String.valueOf(event.getTrip().getTime()));
}
});
}
}
I the object event is always null. Am I missing anything?
Thanks.
On every class you need to perform a #Inject you have to call: objectGraph.inject(this); usually you put it in the constructor, like this:
public class RealBusEvent {
#Inject Trip trip;
#Inject
public RealBusEvent(){
YOU_OBJECTGRAPH_REFERENCE.inject(this);
}
public Trip getTrip() {
return trip;
}
}
The main challenge is 'How to get the YOU_OBJECTGRAPH_REFERENCE' if you don't have a 'Context'. For that you can make the ObjectGraph accessible via a Singleton, not very elegant, but sometimes it's the only alternative if you can't pass the Context.
But if you do have a Context, you can just follow the example on this link:
https://github.com/nuria/android-examples/tree/master/dagger-logger-example/Sample/src/com/example/android/ui
And see how they make the ObjectGraph (defined int the DemoApplication) be accessible from DemoBaseActivity.

Android: call method of overrided class from library

In this example I have an app which is playing mp3 songs, but there are different license checks by companies.
So in my library I have 3 files:
public interface UserCheckerInterface {
public void appIsEnabled(boolean result);
}
public class UserChecker {
public static void appisEnabled(final UserCheckerInterface userCheckerInterface) {
userCheckerInterface.appIsEnabled(true);
}
}
public class MainActivity extends Activity {
#Override
public void onCreate(final Bundle savedInstanceState) {
....
UserChecker.appisEnabled(new UserCheckerInterface(
#Override
public void appisEnabled(final boolean result) {
Toast.makeText(getApplicationContext(), "" + result, 0).show();
}
));
}
}
I would like override the UserChecker.appisEnabled method in my app which is using this library, but I don't know how.
I am not sure whether I have understood your question, if I did, than you simply have to implement your interface by writing
public class UserChecker implements UserCheckerInterface{
#Override
public static void appisEnabled(final UserCheckerInterface userCheckerInterface) {
userCheckerInterface.appIsEnabled(true);
}
}
Once you do that, then the IDE will show you an error IF you have not implemented the method; which is not the case in this scenario.

Categories

Resources