Trying to learn Room and RXJAVA.
I have about 80% of this understood but I'm getting stuck on figuring the rest out.
Here is the error I get on the insert data.
java.lang.NullPointerException: Attempt to invoke interface method
'void
com.example.learnroom.EntityDao.insert(com.example.learnroom.Entitys)'
on a null object reference
If I don't run the try catch I get the following error which seems to be related.
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.learnroom/com.example.learnroom.MainActivity}:
java.lang.NullPointerException: Attempt to invoke interface method
'io.reactivex.Maybe
com.example.learnroom.EntityDao.getEntity(java.lang.String)' on a null
object reference
How do I fix this?
I have tried to simplify from the tutorials all over the web most using recyclerviews to just 2 text fields. They say this is 3 pieces but it doesn't seem like it, as the DB was never set up so I ran it in a method to run the code. Maybe someone can help explain to me how this really works.
my code
Dao
public interface EntityDao {
#Query("SELECT * FROM Entitys WHERE ID = :ID LIMIT 1")
Maybe<List<Entitys>> getEntity(String ID);
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Entitys entitys);
#Query("DELETE FROM Entitys")
void deleteAllEntity();
}
Entity
public class Entitys {
#PrimaryKey
#NonNull
public String ID;
public String ts;
public String tss;
public Entitys(#NonNull String ID, String ts, String tss) {
this.ID = ID;
this.ts = ts;
this.tss = tss;
}
public String getTss() {
return tss;
}
public void setTss(String tss) {
this.tss = tss;
}
public void setID(String ID) {
this.ID = ID;
}
public void setTs(String ts) {
this.ts = ts;
}
public String getID() {
return ID;
}
public String getTs() {
return ts;
}
}
database
#Database(entities = {Entitys.class}, version = 1)
public abstract class PathwaysDB extends RoomDatabase {
private static volatile PathwaysDB INSTANCE;
public static EntityDao entityDao() {
return null;
}
public static PathwaysDB getInstance(Context context) {
if (INSTANCE == null) {
synchronized (PathwaysDB.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
PathwaysDB.class, "Pathwaysdb")
.build();
}
}
}
return INSTANCE;
}
}
MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = MainActivity.class.getSimpleName();
Button tb;
EditText te, tes;
String ts, tss, ID;
CompositeDisposable compositeDisposable = new CompositeDisposable();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ID ="test";
te = findViewById(R.id.te);
tb = findViewById(R.id.tb);
tb.setOnClickListener(this);
tes = findViewById(R.id.tes);
Builddb();
try{
getData();}catch (Exception e){}
}
private void Builddb() {
Completable.fromAction(() -> PathwaysDB.getInstance(this))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onComplete() {
// action was completed successfully
}
#Override
public void onError(Throwable e) {
// something went wrong
}
});
}
private void getData() {
Maybe<List<Entitys>> single = entityDao().getEntity(ID);
single.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new MaybeObserver<List<Entitys>>() {
#Override
public void onSubscribe(Disposable d) {
// add it to a CompositeDisposable
}
#Override
public void onSuccess(List<Entitys> entity) {
te.setText(entity.indexOf(ts));
tes.setText(entity.indexOf(tss));
}
#Override
public void onError(Throwable e) {
// show an error message
}
#Override
public void onComplete() {
}
});
compositeDisposable.add((Disposable) single);
}
#Override
protected void onDestroy() {
super.onDestroy();
compositeDisposable.dispose();
}
private void updateUserName() {
ts = te.getText().toString();
tss = tes.getText().toString();
Entitys entitys = new Entitys(ID, ts, tss);
Completable.fromAction(() -> entityDao().insert(entitys))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onComplete() {
// action was completed successfully
}
#Override
public void onError(Throwable e) {
// something went wrong
}
});
}
#Override
public void onClick(View view) {
updateUserName();
Intent forward = new Intent(this, secondpage.class);
startActivity(forward);
}
}
Reason for crash is this line in your PathwaysDB class
public static EntityDao entityDao() {
return null;
}
it is returning null. It should be like
public abstract EntityDao entityDao()
You forget to add #Dao annonation to your EntityDao interface class.
also you need to change below method :
public static EntityDao entityDao() {
return null;
}
To
public abstract EntityDao entityDao();
Related
I have some classes as presenter and in these classes I use retrofit for some methods. But some methods are duplicated. So I want to use a class for all retrofit and connect to server methods and call them when I want.
But when I created that class it has NullpointerException Error
I will be very thankful if you help me
this is presenter codes:
public class DefinitionPresenter implements DefinitionContract.Presenter {
private KalaBeanDataSource kalaBeanDataSource;
private DefinitionContract.View view;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private DatabaseMethods databaseMethods;
private ActivityKindList activityKindList;
public DefinitionPresenter(KalaBeanDataSource kalaBeanDataSource){
this.kalaBeanDataSource = kalaBeanDataSource;
databaseMethods = new DatabaseMethods(kalaBeanDataSource,compositeDisposable);
activityKindList = new ActivityKindList();
}
#Override
public void attachView(DefinitionContract.View view) {
this.view = view;
}
#Override
public void detachView() {
view = null;
if(compositeDisposable != null && compositeDisposable.size() > 0){
compositeDisposable.clear();
}
}
#Override
public void activityKind() {
activityKindList = databaseMethods.getActivityKind();
if(activityKindList.getItems().size() > 0){
view.getActivityKind(activityKindList);
}else{
view.showMessage(databaseMethods.message);
}
}
}
And this is a class that I created for get data from server with retrofit and RxJava
public class DatabaseMethods {
private KalaBeanDataSource kalaBeanDataSource;
private CompositeDisposable compositeDisposable;
private ActivityKindList activityKindListResult;
public String message = null;
public DatabaseMethods(KalaBeanDataSource kalaBeanDataSource,CompositeDisposable compositeDisposable){
this.kalaBeanDataSource = kalaBeanDataSource;
this.compositeDisposable = compositeDisposable;
activityKindListResult = new ActivityKindList();
}
public ActivityKindList getActivityKind(){
kalaBeanDataSource.getActivityKind().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<ActivityKindList>() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onSuccess(ActivityKindList activityKindList) {
activityKindListResult = activityKindList;
}
#Override
public void onError(Throwable e) {
message = e.toString();
}
});
if(message == null && activityKindListResult.getItems().size() > 0){
return activityKindListResult;
}else{
return null;
}
}
this method always returns null:
public ActivityKindList getActivityKind(){
kalaBeanDataSource.getActivityKind().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<ActivityKindList>() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onSuccess(ActivityKindList activityKindList) {
activityKindListResult = activityKindList;
}
#Override
public void onError(Throwable e) {
message = e.toString();
}
});
if(message == null && activityKindListResult.getItems().size() > 0){
return activityKindListResult;
}else{
return null;
}
}
1) make this method void
2) create an interface and call it in onSuccess() and onError()
3) implement interface in your presenter
I am using room as data store for my app. I am trying to save a list of sessions from a successful network call in viewmodel class. I have used a repository for interacting with the dao and asynctask for making crud operations async.
Now, I'm trying to display the "saved data" in a recyclerview but it shows nothing. On inspection of my database table, I find that nothing was saved. Here's my model class:
#Entity(tableName = "sessions")
public class Sessions{
// #PrimaryKey(autoGenerate = true)
// public int id;
#SerializedName("prg_session_image")
public String sessionImage;
#SerializedName("prg_session_name")
public String session_name;
#SerializedName("prg_session_id") // used session id as PK
#PrimaryKey
#NonNull
public String prog_sessionId;
#SerializedName("prg_session_description")
public String session_desc;
#SerializedName("reference_id")
public String reference_id;
#SerializedName("prg_name")
public String program_name;
#SerializedName("batch_name")
public String batch_name;
#SerializedName("player_count")
public String participants_count;
#SerializedName("prg_session_focus_points")
public String session_focus_points;
#SerializedName("prg_session_equipment")
public String equipments_reqd;
#SerializedName("session_complete")
public String is_complete;
public Sessions() {
}
// public int getId() {
// return id;
// }
public String getSessionImage() {
return sessionImage;
}
public void setSessionImage(String sessionImage) {
this.sessionImage = sessionImage;
}
public String getSession_name() {
return session_name;
}
public void setSession_name(String session_name) {
this.session_name = session_name;
}
public String getProg_sessionId() {
return prog_sessionId;
}
public void setProg_sessionId(String prog_sessionId) {
this.prog_sessionId = prog_sessionId;
}
public String getSession_desc() {
return session_desc;
}
public void setSession_desc(String session_desc) {
this.session_desc = session_desc;
}
public String getReference_id() {
return reference_id;
}
public void setReference_id(String reference_id) {
this.reference_id = reference_id;
}
public String getProgram_name() {
return program_name;
}
public void setProgram_name(String program_name) {
this.program_name = program_name;
}
public String getBatch_name() {
return batch_name;
}
public void setBatch_name(String batch_name) {
this.batch_name = batch_name;
}
public String getParticipants_count() {
return participants_count;
}
public void setParticipants_count(String participants_count) {
this.participants_count = participants_count;
}
public String getSession_focus_points() {
return session_focus_points;
}
public void setSession_focus_points(String session_focus_points) {
this.session_focus_points = session_focus_points;
}
public String getEquipments_reqd() {
return equipments_reqd;
}
public void setEquipments_reqd(String equipments_reqd) {
this.equipments_reqd = equipments_reqd;
}
public String getIs_complete() {
return is_complete;
}
public void setIs_complete(String is_complete) {
this.is_complete = is_complete;
}
}
And Dao class:
#Dao
public interface SessionsDAO {
// #Insert
// LiveData<List<Sessions>> saveSessions(List<Sessions> sessions);
#Insert
void addSessions(List<Sessions> list);
#Query("select * from sessions")
LiveData<List<Sessions>> getAllSessions();
#Query("select * from sessions where prog_sessionId = :id")
Sessions getSessionById(String id);
}
In repository, I have asynctasks for various operations with the Dao:
public class SessionsRepository {
public SessionsDAO dao;
private MutableLiveData<List<Sessions>> querySingleSession;
private LiveData<List<Sessions>> allSessions;
public SessionsRepository(Application application){
SportsDatabase database = SportsDatabase.getInstance(application);
dao = database.sessionsDAO();
querySingleSession = new MutableLiveData<>();
allSessions = dao.getAllSessions();
}
public void saveSessions(List<Sessions> sessions){
new SaveSessionsTask(dao).execute(sessions);
}
public LiveData<List<Sessions>> getAllSessions() {
return allSessions;
}
public void getSessionById(List<Sessions> sessions){
querySingleSession.setValue(sessions);
}
public class SaveSessionsTask extends AsyncTask<List<Sessions>, Void, Void>{
private SessionsDAO dao;
public SaveSessionsTask(SessionsDAO dao) {
this.dao = dao;
}
#Override
protected Void doInBackground(List<Sessions>... lists) {
dao.addSessions(lists[0]);
return null;
}
}
// public void getSessions(){
// new GetSessionsTask(dao).execute();
// }
// public class GetSessionsTask extends AsyncTask<Void, >
}
I am trying to at the moment save all the results from network call and display them from the database. Here's my operation in viewmodel class:
public class HomeSessionsViewModel extends AndroidViewModel {
private static final String TAG = HomeSessionsViewModel.class.getSimpleName();
private MutableLiveData<SessionDetails> liveDetails;
private SessionsRepository repository;
public HomeSessionsViewModel(#NonNull Application application) {
super(application);
repository = new SessionsRepository(application);
}
// public HomeSessionsViewModel (Application application){
// repository = new SessionsRepository(application);
// }
public MutableLiveData<SessionDetails> getSessions(){
if (liveDetails == null){
liveDetails = new MutableLiveData<>();
fetchSessions();
}
return liveDetails;
}
private void fetchSessions(){
String coachId = "4086";
Call<SessionDetails> call = RestClient.getRestInstance().getSessionsService().fetchSessions(coachId);
call.enqueue(new Callback<SessionDetails>() {
#Override
public void onResponse(Call<SessionDetails> call, Response<SessionDetails> response) {
if (response.isSuccessful()){
SessionDetails details = response.body();
List<Sessions> sessions = details.getSessions();
Log.d(TAG, "N/w sesh size:\t" + sessions.size());
liveDetails.setValue(details); // now just displaying from network
saveSessions(sessions);
}
}
#Override
public void onFailure(Call<SessionDetails> call, Throwable t) {
}
});
}
private void saveSessions(List<Sessions> sessions) {
repository.saveSessions(sessions);
}
public LiveData<List<Sessions>> fetchSessionsDB(){
return repository.getAllSessions();
}
}
and in ui controller (fragment), I have called the viewmodel's fetchSessionsDB() method but no data is shown. The network request works well as I was displaying from there before adding room. What could be wrong here? Thank you.
API Response:
{
"session_details": [
{
"prg_session_name": "Session-16",
"prg_session_id": "987",
"prg_session_equipment": null,
"prg_session_description": "",
"prg_session_focus_points": "",
"prg_session_image": "http://devsports.copycon.in/includes/uploads/Jellyfish5.jpg",
"session_complete": "0",
"prg_name": "cricket coaching",
"reference_id": "293",
"batch_id": "57",
"batch_name": "Batch 3",
"player_count": "10"
}, .... ]}
and SessionDetails POJO:
public class SessionDetails {
#SerializedName("session_details")
#Expose
private List<Sessions> sessions;
#SerializedName("status")
private String status;
#SerializedName("message")
private String msg;
public List<Sessions> getSessions() {
return sessions;
}
}
fragment class where db data should be displayed:
private void populateSessions() {
sessionsRV = fragmentBinding.sessionsRV;
sessionsRV.setHasFixedSize(false);
LinearLayoutManager hlm = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
sessionsRV.setLayoutManager(hlm);
sessionsViewModel = ViewModelProviders.of(this).get(HomeSessionsViewModel.class);
// sessionsViewModel.fetchSessions(""); // TODO: 3/16/2019 Use coach id from db
// calling db from viewmodel
sessionsViewModel.fetchSessionsDB().observe(this, new Observer<List<Sessions>>() {
#Override
public void onChanged(#Nullable List<Sessions> sessions) {
sessionsAdapter = new SessionsAdapter(getActivity(), sessions);
sessionsRV.setAdapter(sessionsAdapter);
Log.d(TAG, "Sessions Count:\t" + sessionsAdapter.getItemCount()); // logs 0
}
});
// previously from network directly displayed
// sessionsViewModel.getSessions().observe(this, new Observer<SessionDetails>() {
// #Override
// public void onChanged(#Nullable SessionDetails details) {
// List<Sessions> list = details.getSessions();
// sessionsAdapter = new SessionsAdapter(getActivity(), list);
// sessionsRV.setAdapter(sessionsAdapter);
// Log.d(TAG, "Sessions Count:\t" + sessionsAdapter.getItemCount());
// }
// });
}
Sports Database class:
#Database(entities = {CoachDB.class, Sessions.class}, version = 1, exportSchema = false)
public abstract class SportsDatabase extends RoomDatabase {
private static SportsDatabase instance;
public abstract CoachDAO coachDAO();
public abstract SessionsDAO sessionsDAO();
public static synchronized SportsDatabase getInstance(Context context) {
if (instance == null){
instance = Room.databaseBuilder(context.getApplicationContext(), SportsDatabase.class, "sports_db")
.fallbackToDestructiveMigration()
.build();
}
return instance;
}
}
I have solved this issue by modifying my #insert method in dao like
#Dao
public interface SessionsDAO {
#Insert
void addSessions(List<Sessions> sessions);
#Query("select * from sessions")
LiveData<List<Sessions>> getAllSessions();
#Query("select * from sessions where prog_sessionId = :id")
Sessions getSessionById(String id);
}
and run my async task with a list of sessions as input and it worked successfully.
private void saveSessions(List<Sessions> sessions) {
new SaveSessionsTask(dao).execute(sessions);
}
public class SaveSessionsTask extends AsyncTask<List<Sessions>, Void, Void> {
private SessionsDAO dao;
public SaveSessionsTask(SessionsDAO dao) {
this.dao = dao;
}
#Override
protected Void doInBackground(List<Sessions>... lists) {
dao.addSessions(lists[0]);
return null;
}
}
I'm new in android architecture component. this is my code , i'm at the point that I don't know how to notify my activity and get the results back
these are my codes:
Activity:
private void iniViewModels() {
Observer<List<User>>usersObserver=new Observer<List<User>>() {
#Override
public void onChanged(#Nullable List<User> users) {
Log.v("this","LiveData: ");
for (int i=0;i<users.size();i++){
Log.v("this",users.get(i).getName());
}
}
};
mViewModel = ViewModelProviders.of(this)//of-->name of act or fragment
.get(AcActivityViewModel.class);///get -->the name of viewModelClass
mViewModel.mUsers.observe(this,usersObserver);
}
this is my viewModel Class:
public class IpStaticViewModel extends AndroidViewModel {
public LiveData<List<Ipe>> ips;
private AppRepository repository;
public IpStaticViewModel(#NonNull Application application) {
super(application);
repository=AppRepository.getInstance(application.getApplicationContext());
}
public void getIpStatics() {
repository.getStaticIps();
}
}
this is my repository class:
public class AppRepository {
private static AppRepository ourInstance ;
private Context context;
private IpStaticInterface ipInterface;
public static AppRepository getInstance(Context context) {
if (ourInstance == null) {
ourInstance=new AppRepository(context);
}
return ourInstance;
}
private AppRepository(Context context) {
this.context=context;
}
public void getStaticIps() {
ipInterface= ApiConnection.getClient().create(IpStaticInterface.class);
ipInterface.getIpes()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new SingleObserver<IpStaticList>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(IpStaticList ipStaticList) {
List<Ipe>ips=ipStaticList.getIpes();
}
#Override
public void onError(Throwable e) {
Log.v("this","Eror "+ e.getMessage());
}
});
}
}
I'm using retrofit for fetching the data ,it fetch the data successfully but I don't know how to notify my activity
can you help me?
Have a MutableLiveData
final MutableLiveData<List<Ipe>> data = new MutableLiveData<>();
In onSucess
public MutableLiveData<List<Ipe>> getStaticIps() {
ipInterface= ApiConnection.getClient().create(IpStaticInterface.class);
ipInterface.getIpes()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new SingleObserver<IpStaticList>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(IpStaticList ipStaticList) {
List<Ipe>ips=ipStaticList.getIpes();
data.setValue(ips);
}
#Override
public void onError(Throwable e) {
Log.v("this","Eror "+ e.getMessage());
}
});
return data;
}
In repository expose this to viewmodel
public LiveData<List<Ipe>> getIpStatics() {
return repository.getStaticIps();
}
In Activity you observe the livedata
IpStaticViewModel viewmodel = ViewModelProviders.of(this
.get(IpStaticViewModel.class)
viewModel.getIpStatics().observe(this, new Observer<List<Ipe>>() {
#Override
public void onChanged(#Nullable List<Ipe> ipes) {
if (ipes != null) {
// dosomething
}
}
});
If you want to generalize your response in case you have a error or something have a look at https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/vo/Resource.kt
I am using rxjava 2 and trying to use rxbus for passing a value
rxbus code
public class SeasonTabSelectorBus {
private static SeasonTabSelectorBus instance;
private PublishSubject<Object> subject = PublishSubject.create();
public static SeasonTabSelectorBus instanceOf() {
if (instance == null) {
instance = new SeasonTabSelectorBus();
}
return instance;
}
public void setTab(Object object) {
try {
subject.onNext(object);
subject.onComplete();
} catch (Exception e) {
e.printStackTrace();
}
}
public Observable<Object> getSelectedTab() {
return subject;
}
}
I am setting the value as
SeasonTabSelectorBus.instanceOf().setTab(20);
This is code of my subscription
SeasonTabSelectorBus.instanceOf().getSelectedTab().subscribe(new Observer<Object>(){
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Object o) {
if (o instanceof Integer) {
int seasonSelected =(int) o;
Log.e("season selected",seasonSelected+"");
}
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
Now I am getting the value on the first call, but when I call again with different values, I do not get the callback.
SeasonTabSelectorBus.instanceOf().setTab(40);
SeasonTabSelectorBus.instanceOf().setTab(90);
SeasonTabSelectorBus.instanceOf().setTab(120);
SeasonTabSelectorBus.instanceOf().setTab(290);
You are receiving only the first one because, after publish (subject.onNext(object)), you are calling subject.onComplete(). Just remove that line.
I've never create unit testing before. I'm planning to create UI test & Unit test for my presenter & datasource. I use Retrofit, RxJava, and Dagger in my apps.
Here's what i've tried so far
DataSource (My Datasource is coming from API)
public class DataSource implements DataSourceContract {
private static DataSource dataSource;
#Inject
SharedPreferences sharedPreferences;
#Inject
NewsService newsService;
private DataSource(Context context) {
DaggerAppComponent.builder()
.networkModule(new NetworkModule(API_URL))
.appModule(new AppModule(context.getApplicationContext()))
.preferencesModule(new PreferencesModule())
.build()
.inject(this);
}
public static synchronized DataSource getInstance(Context context) {
if(dataSource == null) {
dataSource = new DataSource(context);
}
return dataSource;
}
public String parseError(Throwable e) {
if(e instanceof SocketTimeoutException) {
return ERROR_TIMEOUT;
}
else if(e instanceof SocketException) {
return ERROR_NO_CONNECTION;
}
else {
return ERROR_SERVER;
}
}
#Override
public DisposableObserver<NewsResponse> getNews(final Callback<NewsResponse> callback) {
return newsService.getNews()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<NewsResponse>() {
#Override
public void onNext(NewsResponse value) {
callback.onSuccess(value);
}
#Override
public void onError(Throwable e) {
callback.onFailure(e);
}
#Override
public void onComplete() {
}
});
}
}
Presenter
public class MainPresenter implements MainContract.Presenter {
private MainContract.View view;
private DataSource dataSource;
private Disposable dispossable;
public MainPresenter(MainContract.View view, DataSource dataSource) {
this.view = view;
this.dataSource = dataSource;
}
#Override
public void onStart() {
getNews();
}
#Override
public void onStop() {
if(dispossable != null && !dispossable.isDisposed()) {
dispossable.dispose();
}
}
#Override
public void getNews() {
view.setLoading(true);
dispossable = dataSource.getNews(new DataSourceContract.Callback<NewsResponse>() {
#Override
public void onSuccess(NewsResponse responseData) {
try {
switch (responseData.getStatus()) {
case API_SUCCESS:
view.setLoading(false);
view.getNewsSuccess(responseData.getArticles());
break;
default:
view.setLoading(false);
view.getNewsFailed(responseData.getStatus());
break;
}
}
catch (Exception e) {
view.setLoading(false);
view.getNewsFailed(ERROR_SERVER);
}
}
#Override
public void onFailure(Throwable e) {
view.setLoading(false);
view.isNetworkFailed(dataSource.parseError(e), false);
}
});
}
}
And this is the test of my presenter
public class MainPresenterTest {
#Mock
DataSource dataSource;
#Mock
MainContract.View view;
MainContract.Presenter presenter;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
presenter = new MainPresenter(view, dataSource);
}
#Test
public void getNews() throws Exception {
List<Article> articleList = new ArrayList<>();
presenter.getNews();
Mockito.verify(view, Mockito.only()).getNewsSuccess(articleList);
}
}
But there is error when I run the test
Wanted but not invoked:
view.getNewsSuccess([]);
-> at com.java.mvp.view.main.MainPresenterTest.getNews(MainPresenterTest.java:37)
I have no problem running this apps on the device, but I can't make it work on testing
Any idea how to fix this presenter test? Am I doing it right?
And how do I test my datasource? I have no idea how to test this one
Thank you
Keep things simple. You are testing your presenter, not the data source. Add new methods to your presenter for the success and error responses. Then add two tests: one for the success and one for the error.
#Override
public void getNews() {
view.setLoading(true);
dispossable = dataSource.getNews(new DataSourceContract.Callback<NewsResponse>() {
#Override
public void onSuccess(NewsResponse responseData) {
onSuccessNewsResponse(responseData);
}
#Override
public void onFailure(Throwable e) {
onErrorNewsResponse(e);
}
});
}
Add #VisibleForTesting annotation to the new methods.
Success test:
#Test
public void getNewsSuccess() {
presenter.onSuccessNewsResponse(your_response);
Mockito.verify(...);
}
Error test:
#Test
public void getNewsError() {
presenter.onErrorNewsResponse(your_error);
Mockito.verify(...);
}
You have to mock also :
dataSource.getNews() using Mockito when :
e.g.
when(dataSource.getNews()).thenReturn(new SuccessCallback());
So you have to lead your test code into the success callback and check there what methods are called.
The same goes with the eroor case.