How can I make connection between retrofit and RxJava in different classes? - android

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

Related

RXJAVA ROOM android

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();

How to notify activity when repository class gets the data?

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

onNext not called for PublishSubject in android, rxjava?

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.

How to test presenter on android (MVP)?

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.

How to custom Retrofit with AsyncTask?

I use Retrofit. Sometime I want integrate with AsyncTask for some purpose like Dialog Loading...
Here is my way:
public class RetrofitAsyncTask<T extends ResponseModel> {
public interface OnCompleteListener<T extends ResponseModel> {
public void onComplete(T t);
public void onError(Exception e);
}
public interface JsonConverter<T extends ResponseModel> {
public T getModel();
}
protected OnCompleteListener<T> onCompleteListener = null;
protected JsonConverter<T> jsonConverter;
protected ProgressDialog progressDialog;
protected int requestCode = Integer.MIN_VALUE;
public static RetrofitAsyncTask newInstance() {
return new RetrofitAsyncTask();
}
public RetrofitAsyncTask setOnCompleteListener(OnCompleteListener<T> l) {
onCompleteListener = l;
return this;
}
public RetrofitAsyncTask setJsonConverter(JsonConverter<T> converter) {
jsonConverter = converter;
return this;
}
public RetrofitAsyncTask setProgressDialog(ProgressDialog dlg) {
progressDialog = dlg;
return this;
}
public RetrofitAsyncTask setRequestCode(int reqCode) {
requestCode = reqCode;
return this;
}
public void execute() {
new AsyncTask<Void, Void, Exception>() {
private T result;
#Override
protected ProgressDialog getDialogRunOnPreStart() {
/** Retrun dialog will display. Will process on onPre & onPost. But current I will ignore it.**/
return progressDialog;
}
#Override
protected Exception doInBackground(Void... params) {
if (jsonConverter == null) {
return null;
}
try {
result = jsonConverter.getModel();
result.setRequestCode(requestCode);
} catch (Exception e) {
return e;
}
return null;
}
#Override
protected void onPostExecute(Exception e) {
if (onCompleteListener != null) {
if (e != null || result == null) {
onCompleteListener.onError(e);
} else {
onCompleteListener.onComplete(result);
}
}
}
}.execute();
}
}
In this case class ResponseModel is Empty class.
public class ResponseModel {/** You will custom some filed default here **/}
Next you will define some Service Api.... look like:
public interface MyService {
#GET("/path")
public User getUserInfo(....);
}
(Notes class User Must be extend from ResponseModel).
Then you will custom some RetrofitAdapter...
Finally to use RetrofitAsyncTask you will do something like:
RetrofitAsyncTask.newInstance()
.setJsonConverter(
new RetrofitAsyncTask.JsonConverter<User>() {
#Override
public User getModel() {
return MyService.getUser(...);
}
}
)
.setOnCompleteListener(this)
.setRequestCode(requestCode)
.execute();
That's way I done. But current I feel it not good.
(setJsonConverter get much line :|, If you have any idea to make it better & shorter please comment ! Thanks so so much !)

Categories

Resources