Dagger listener/interface injection - android

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

Related

Android MVP presenter unit test with Mockito causes "Wanted but not invoked" error

I know it was asked before, but i am currently diving into testing and i have the struggle to unit test presenter in MVP pattern with Mockito
My code setup:
Item class
public class ItemJSON {
#SerializedName("title")
String textHolder;
#SerializedName("id")
int factNumber;
public ItemJSON(String factText, int factNumber) {
this.textHolder = factText;
this.factNumber = factNumber;
}
//getters and setters
}
Contractor:
public interface Contractor {
interface Presenter {
void getPosts();
}
interface View {
//parse data to recyclerview on Succesfull call.
void parseDataToRecyclerView(List<ItemJSON> listCall);
void onResponseFailure(Throwable throwable);
}
interface Interactor {
interface onGetPostsListener {
void onSuccessGetPostCall(List<ItemJSON> listCall);
void onFailure(Throwable t);
}
void getPosts(onGetPostsListener onGetPostsListener);
}
}
API class:
#GET("posts")
Call<List<ItemJSON>> getPost();
Interactor class:
public class InteractorImpl implements Contractor.Interactor{
#Override
public void getPosts(onGetPostsListener onGetPostsListener) {
// NetworkService responsible for seting up Retrofit2
NetworkService.getInstance().getJSONApi().getPost().enqueue(new Callback<List<ItemJSON>> () {
#Override
public void onResponse(#NonNull Call<List<ItemJSON>> call, #NonNull Response<List<ItemJSON>> response) {
Log.d("OPERATION #GET","CALLBACK SUCCESSFUL");
onGetPostsListener.onSuccessGetPostCall (response.body ());
}
#Override
public void onFailure(#NonNull Call<List<ItemJSON>>call, #NonNull Throwable t) {
Log.d("OPERATION #GET","CALLBACK FAILURE");
onGetPostsListener.onFailure (t);
}
});
}
Presenter class:
public class PresenterImpl implements Contractor.Presenter, Contractor.Interactor.onGetPostsListener {
private final Contractor.View view;
private final Contractor.Interactor interactor;
public PresenterImpl (Contractor.View view,Contractor.Interactor interactor){
this.view = view;
this.interactor = interactor;
}
#Override
public void getPosts() {
interactor.getPosts (this);
}
#Override
public void onSuccessGetPostCall(List<ItemJSON> listCall) {
view.parseDataToRecyclerView (listCall);
}
}
So i try to ran some unit test on presenter, but they constanlty fail and i keep getting next error
Wanted but not invoked Actually, there were zero interactions with this mock
Unit test class:
#RunWith (MockitoJUnitRunner.class)
public class ApiMockTest{
#Mock
Contractor.View view;
private PresenterImpl presenter;
#Captor
ArgumentCaptor<List<ItemJSON>> jsons;
#Before
public void setUp() {
MockitoAnnotations.openMocks (this);
presenter = new PresenterImpl (view,new InteractorImpl ());
}
#Test
public void loadPost() {
presenter.getPosts ();
verify(view).parseDataToRecyclerView (jsons.capture ());
Assert.assertEquals (2, jsons.capture ().size ());
}
}
I try to understand what i am doing wrong and how to fix this issue, but as for now i am ran out of ideas. I will aprecciate any help.
Thanks in the adavance
UPD: in all cases in main activity presenter get called in onClick
Main Activity class:
public class MainActivity extends AppCompatActivity implements Contractor.View {
public Contractor.Presenter presenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
presenter = new PresenterImpl (this,new InteractorImpl ());
binding.getButton.setOnClickListener(view ->presenter.getPosts () );
...//code
#Override
public void parseDataToRecyclerView(List<ItemJSON> listCall) {
adapter.updateList(listCall); //diff call to put data into recyclerview adapter
}
}
}
I ran into this situation also, even using the mockk library. The problem is that your method is an interface method. You need to actually call it from a view which has implemented this interface.

Is it fine to create a separate interface for call back function in MVP pattern

I am trying to create an app by using MVP design pattern. This is the first time i am using this pattern, thats the reason i am little concerned that either i am following the pattern correctly or not.
This is what i have done so far. I am not using Dagger2.
Interface
public interface MainActivityMVP {
interface Model{
void sendTokenToServer(MainActivityMVP.Presenter presenter);
}
interface View{
boolean isPnTokenRegistered();
void tokenUpdated();
void tokenFailedToUpdate();
}
interface Presenter{
void tokenUpdatedSuccessfully();
void tokenAlreadyExists();
void detachView();
}
On MainActivity, I have created an instance of Presenter and Model and pass the Model object to Presenter Constructor
MainActivity
public class MainActivity extends BaseActivity implements MainActivityMVP.View {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base);
mainPresenter= new MainPresenter(this, new MainModel());
mainPresenter.sendFCMTokenToServer();
}
On Presenter I call Model's method to perform operation, and pass presenter reference to it.
Presenter
public class MainPresenter implements MainActivityMVP.Presenter{
MainActivityMVP.View view;
MainActivityMVP.Model model;
public MainPresenter(MainActivityMVP.View view, MainActivityMVP.Model model){
this.view= view;
this.model= model;
}
public void sendFCMTokenToServer() {
model.sendTokenToServer(this);
}
#Override
public void tokenUpdatedSuccessfully() {
view.tokenUpdated();
}
#Override
public void tokenAlreadyExists() {
view.tokenFailedToUpdate();
}
In Model, I create instance of PreferenceManager class that gets data from SharedPreference
public class MainModel implements MainActivityMVP.Model {
PreferencesHelper preferencesHelper;
public MainModel(){
preferencesHelper= new PreferencesHelper();
}
#Override
public void sendTokenToServer(MainActivityMVP.Presenter presenter) {
if (preferencesHelper.getNotificationSettings().isEmpty()) {
//do stuff
presenter.tokenUpdatedSuccessfully();
}
}
Now i have these questions.
Is the above approach of implementing MVP pattern is fine, or i am
missing something here.
Is it fine if i add an other interface for call backs, or passing
Presenter to model is better approach, as i have seen some example
where they pass interactor reference to model.
Is it necessary to create Interactor Class in MVP pattern
Is it fine, and not against MVP rule if i create a separate
interface for Repository,
Developers have different varieties of implementing MVP. Few people use interactors. Its is not compulsory to use interactors in MVP. I will suggest you below since you are in a starting stage.
public interface MainView extends BaseView {
boolean isPnTokenRegistered();
void tokenUpdated();
void tokenFailedToUpdate();
}
Then have your basepresenter be like this
public interface BasePresenter<V extends BaseView> {
void setView(V view);
void destroyView();
void destroy();
}
Now your MainPresenter
public class MainPresenter implements BasePresenter<MainView>{
MainView view;
PreferencesHelper preferencesHelper;
MainPresenter(){
preferencesHelper= new PreferencesHelper();
}
#Override
public void setView(MainView view) {
this.view = view;
}
#Override
public void destroyView() {
this.view = null;
}
#Override
public void destroy() {
}
public void sendFCMTokenToServer() {
//Do whatever you want
}
}
Finally have your activity like this,
public class MainActivity extends BaseActivity implements MainView {
MainPresenter mainPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base);
mainPresenter= new MainPresenter();
mainPresenter.attachView(this)
mainPresenter.sendFCMTokenToServer();
}

Gomobile android using callbacks

I have an library written using go mobile and it should has only one callback but when trying implement it, I get two additional methods.
#Override
public Seq.Ref ref() {
return null;
}
#Override
public void call(int i, Seq seq, Seq seq1) {}
Question is, which is right way to implement callback from go on Android Activity?
Right now i have next:
public class MainActivity extends Activity implements implements Mobile.Callback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
Mobile.Client client = Mobile.New("192.168.2.1", 9000, this);
try {
client.Connect();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void OnMessage(String s) {
Log.e("GO", s);
}
#Override
public Seq.Ref ref() {
return null;
}
#Override
public void call(int i, Seq seq, Seq seq1) {
}
}
Connection is established successfully but on callback to activity i getting:
panic: runtime error: invalid memory address or nil pointer dereference
If someone can help I'll be really appreciate.
What is the Go source you are binding? (The package mobile and Callback interface)
For passing the Java class that implements Go interface type, see the section "Passing target language objects to Go" of
https://godoc.org/golang.org/x/mobile/cmd/gobind
Basically, the generated Java interface type is not meant to be used directly. Instead, the Java class should extends the generated Java interface's Stub class.
Use Mobile.Callback.Stub instead of Mobile.Callback for android
...
Mobile.Client client = Mobile.New("192.168.2.1", 9000, new Callbacks());
...
class Callbacks extends Mobile.Callback.Stub {
#Override
public void OnMessage(String s) {
....
}
}

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.

How to use Factories injected by Guice in 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.

Categories

Resources