I'm trying to transform a response from server to my databinding object... I didn't understand too much how i make that with the Transformations of livedata...
I think i'm i need to change few things, but i didnt find what i need to change...
:(
When i call loadSellers(), it dont enter on switchMap function
Can someone help me?
public class SellersViewModel extends BaseViewModel {
private EzGasRepository repository;
private MutableLiveData<List<Seller>> sellers;
#Inject
public SellersViewModel(EzGasRepository repository) {
this.repository = repository;
}
public LiveData<List<Seller>> fetchAllSellers() {
if (sellers == null) {
sellers = new MutableLiveData<>();
loadSellers();
}
return sellers;
}
private LiveData<List<Seller>> loadSellers() {
return Transformations.switchMap(repository.fetchAllSellers(), input -> {
List<Seller> sellerList = new ArrayList<>();
for (SellerResponse sellerResponse: input) {
Seller seller = new Seller();
seller.setSellerName(sellerResponse.getName());
seller.setRating(sellerResponse.getRating());
seller.setProductValue(sellerResponse.getProduct().getValue());
seller.setSellerAddress(sellerResponse.getAddress().getFormattedAddress());
sellerList.add(seller);
}
return sellers;
});
}
}
This is my repository
public LiveData<List<SellerResponse>> fetchAllSellers() {
MutableLiveData<List<SellerResponse>> data = new MutableLiveData<>();
ezGasApi.fetchAllSellers().enqueue(new Callback<List<SellerResponse>>() {
#Override
public void onResponse(Call<List<SellerResponse>> call, Response<List<SellerResponse>> response) {
if(response.isSuccessful()) {
data.setValue(response.body());
} else {
//data.setValue(response.errorBody());
}
}
#Override
public void onFailure(Call<List<SellerResponse>> call, Throwable t) {
//data.setValue(t.getMessage());
Timber.e(t);
}
});
return data;
}
This is my View
viewModel.fetchAllSellers().observe(this, response -> {
});
Related
I am working with MVVM pattern. I have just started it and i have done it successfully.
But I don't understand how to add progress bar for showing and hide as we normally do for API calls.
I am not using data binding. So how can i use progress bar for showing and hide it.
For Login
public class LoginRepository {
private DATAModel dataModel = new DATAModel();
private MutableLiveData<DATAModel> mutableLiveData = new MutableLiveData<>();
private Application application;
public LoginRepository(Application application) {
this.application = application;
}
public MutableLiveData<DATAModel> getMutableLiveData(String username, String password) {
APIRequest apiRequest = RetrofitRequest.getRetrofit().create(APIRequest.class);
JsonLogin jsonLogin = new JsonLogin(Constants.DEVICE_TYPE, Functions.getDeviceId(application.getApplicationContext()), Constants.APP_VERSION, Constants.API_VERSION, Functions.getTimeStamp(), Functions.getDeviceModel(), Build.VERSION.RELEASE, username, password);
Call<APIResponseLogin> call = apiRequest.getUsersDetails(jsonLogin);
call.enqueue(new Callback<APIResponseLogin>() {
#Override
public void onResponse(Call<APIResponseLogin> call, Response<APIResponseLogin> response) {
APIResponseLogin apiResponse = response.body();
if (apiResponse != null && apiResponse.getStatuscode() == 0) {
if (apiResponse.getDataModel() != null) {
dataModel = apiResponse.getDataModel();
mutableLiveData.setValue(dataModel);
}
} else if (apiResponse != null && apiResponse.getStatuscode() == 1) {
Log.v("AAAAAAAAA", apiResponse.getStatusmessage());
}
}
#Override
public void onFailure(Call<APIResponseLogin> call, Throwable t) {
Log.v("ErrorResponse", t.getMessage() + " : " + call.request().toString());
}
});
return mutableLiveData;
}
Activity Code
void loginCall() {
loginViewModel.getUserDetails(editTextUsername.getText().toString().trim(), editTextPassword.getText().toString().trim()).observe(this, new Observer<DATAModel>() {
#Override
public void onChanged(#Nullable DATAModel dataModel) {
if (dataModel != null) {
Userdetails userdetails = dataModel.getUserdetails();
List<ContactTypes> contactTypes = dataModel.getContactTypes();
if (userdetails != null) {
MySharedPreferences.setCustomPreference(LoginActivity.this, Constants.SHAREDPREFERENCE_USERDETAILS, userdetails);
MySharedPreferences.setStringPreference(LoginActivity.this, Constants.SHAREDPREFERENCE_USER_ID, userdetails.getUserId());
}
if (contactTypes != null) {
MySharedPreferences.setCustomArrayList(LoginActivity.this, Constants.SHAREDPREFERENCE_CONTACTTYPES, contactTypes);
}
Intent i = new Intent(LoginActivity.this, MainActivity.class);
startActivity(i);
finish();
}
}
});
}
Advanced help would be appreciated!
When you call api that time you have to take one live variable which shows your api is in loading mode or not and after success or failure you have to update that variable.
After observe that variable in your activity or fragment class and show or hide your progress.
public class LoginRepository {
private DATAModel dataModel = new DATAModel();
private MutableLiveData<DATAModel> mutableLiveData = new MutableLiveData<>();
private Application application;
private MutableLiveData<Boolean> progressbarObservable;
public LoginRepository(Application application) {
this.application = application;
}
public MutableLiveData<DATAModel> getMutableLiveData(String username, String password) {
// add below line
progressbarObservable.value = true
APIRequest apiRequest = RetrofitRequest.getRetrofit().create(APIRequest.class);
JsonLogin jsonLogin = new JsonLogin(Constants.DEVICE_TYPE, Functions.getDeviceId(application.getApplicationContext()), Constants.APP_VERSION, Constants.API_VERSION, Functions.getTimeStamp(), Functions.getDeviceModel(), Build.VERSION.RELEASE, username, password);
Call<APIResponseLogin> call = apiRequest.getUsersDetails(jsonLogin);
call.enqueue(new Callback<APIResponseLogin>() {
#Override
public void onResponse(Call<APIResponseLogin> call, Response<APIResponseLogin> response) {
// add below line
progressbarObservable.value = false
APIResponseLogin apiResponse = response.body();
if (apiResponse != null && apiResponse.getStatuscode() == 0) {
if (apiResponse.getDataModel() != null) {
dataModel = apiResponse.getDataModel();
mutableLiveData.setValue(dataModel);
}
} else if (apiResponse != null && apiResponse.getStatuscode() == 1) {
Log.v("AAAAAAAAA", apiResponse.getStatusmessage());
}
}
#Override
public void onFailure(Call<APIResponseLogin> call, Throwable t) {
// add below line
progressbarObservable.value = false
Log.v("ErrorResponse", t.getMessage() + " : " + call.request().toString());
}
});
return mutableLiveData;
}
}
Now, observe above variable in activity or fragment and based on that value hide or show your progress bar
public class LoginActivity extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
observeLogin();
}
#Override
public void onClick(View view)
{
switch (view.getId()) {
case R.id.button_login:
// Do something
loginCall();
}
}
private void observeLogin() {
loginViewModel.progressbarObservable().observe(this, new Observer<Boolean>() {
#Override
public void onChanged(final Boolean progressObserve) {
if(progressObserve){
show your progress
}
else {
hide your progress
}
}
});
}
void loginCall() {
loginViewModel.getUserDetails(editTextUsername.getText().toString().trim(), editTextPassword.getText().toString().trim()).observe(this, new Observer<DATAModel>() {
#Override
public void onChanged(#Nullable DATAModel dataModel) {
if (dataModel != null) {
Userdetails userdetails = dataModel.getUserdetails();
List<ContactTypes> contactTypes = dataModel.getContactTypes();
if (userdetails != null) {
MySharedPreferences.setCustomPreference(LoginActivity.this, Constants.SHAREDPREFERENCE_USERDETAILS, userdetails);
MySharedPreferences.setStringPreference(LoginActivity.this, Constants.SHAREDPREFERENCE_USER_ID, userdetails.getUserId());
}
if (contactTypes != null) {
MySharedPreferences.setCustomArrayList(LoginActivity.this, Constants.SHAREDPREFERENCE_CONTACTTYPES, contactTypes);
}
Intent i = new Intent(LoginActivity.this, MainActivity.class);
startActivity(i);
finish();
}
}
});
}
}
I find it easier to write my own callback interface in this situation. Just not that this will be done synchronously so all will wait until your api call responds. But in such a case, a progress dialog would be havin the similar effect.
1.Create inteface:
public interface ProgressCallback{
void onDone(String message);
void onFail(String message);
}
Now in your method where you call the API
loginUser(String name, String password, ProgressCallback
progressCallback){
call.enqueue(new Callback<LoginData>() {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onResponse(Call<LoginData> call, Response<LoginData> response) {
progressCallBack.onSuccess(response.message());
}
#Override
public void onFailure(Call<LoginData> call, Throwable t) {
progressCallBack.onFail(t.getMessage());
}
});
Now when you call the method
loginUser("John#doe.com", "applesgravity", new ProgressCallBack() {
#Override
public void onSuccess(String message) {
progressBar.setVisibility(View.INVISIBLE);
}
#Override
public void onFail(String message) {
progressBar.setVisibility(View.INVISIBLE);
}
});
I checked this article but observe the response changes in MainActivity.
Here is my code for LoginRepo
public MutableLiveData<LoginResponseModel> checkLogin(LoginRequestModel loginRequestModel) {
final MutableLiveData<LoginResponseModel> data = new MutableLiveData<>();
Map<String, String> params = new HashMap<>();
params.put("email", loginRequestModel.getEmail());
params.put("password", loginRequestModel.getPassword());
apiService.checkLogin(params)
.enqueue(new Callback<LoginResponseModel>() {
#Override
public void onResponse(Call<LoginResponseModel> call, Response<LoginResponseModel> response) {
if (response.isSuccessful()) {
data.setValue(response.body());
Log.i("Response ", response.body().getMessage());
}
}
#Override
public void onFailure(Call<LoginResponseModel> call, Throwable t) {
data.setValue(null);
}
});
return data;
}
Here is my Code LoginViewModel
public class LoginViewModel extends ViewModel {
public MutableLiveData<String> emailAddress = new MutableLiveData<>();
public MutableLiveData<String> password = new MutableLiveData<>();
Map<String, String> params = new HashMap<>();
LoginRepo loginRepo;
private MutableLiveData<LoginResponseModel> loginResponseModelMutableLiveData;
public LiveData<LoginResponseModel> getUser() {
if (loginResponseModelMutableLiveData == null) {
loginResponseModelMutableLiveData = new MutableLiveData<>();
loginRepo = LoginRepo.getInstance();
}
return loginResponseModelMutableLiveData;
}
//This method is using Retrofit to get the JSON data from URL
private void checkLogin(LoginRequestModel loginRequestModel) {
loginResponseModelMutableLiveData = loginRepo.checkLogin(loginRequestModel);
}
public void onLoginClick(View view) {
LoginRequestModel loginRequestModel = new LoginRequestModel();
loginRequestModel.setEmail(emailAddress.getValue());
loginRequestModel.setPassword(password.getValue());
params.put("email", loginRequestModel.getEmail());
params.put("password", loginRequestModel.getPassword());
checkLogin(loginRequestModel);
}
}
Here is my code for LoginActivity
private LoginViewModel loginViewModel;
private ActivityMainBinding binding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loginViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
binding = DataBindingUtil.setContentView(LoginActivity.this, R.layout.activity_main);
binding.setLifecycleOwner(this);
binding.setLoginViewModel(loginViewModel);
loginViewModel.getUser().observe(this, new Observer<LoginResponseModel>() {
#Override
public void onChanged(#Nullable LoginResponseModel loginUser) {
if (loginUser != null) {
binding.lblEmailAnswer.setText(loginUser.getUser().getId());
Toast.makeText(getApplicationContext(), loginUser.getUser().getId(), Toast.LENGTH_SHORT).show();
}
}
});
}
onLoginClick method used in LoginViewModel is using LiveData.
The Response coming from api is okay. But onchange() it is not shown, how to use LiveData using MVVM pattern in simple Login Example. Please help!
Here is what i have tried using your classes just altering retrofit to background thread to wait 5 seconds and then setting the data (you need to confirm the response being successful as you don't change the data if it's failing and hence if the loginResponseModel is null then it will enter the onChanged Method but it won't do anything as you don't have a condition if it is equals to null) here is what i did
in Main Activity -> onCreate() i just created the viewmodel and observed on the mutableLiveData
myViewModel.onLoginClick(null);
myViewModel.simpleModelMutableLiveData.observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
if(s==null)
Log.v("testinggg","test - onChanged --- Null " );
else
Log.v("testinggg","test - onChanged --- s -> "+s );
}
});
Then here is the ViewModel -> in which you will have the MutableLiveData itself named simpleModelMutableLiveData
MutableLiveData<String> simpleModelMutableLiveData;
public LiveData<String> getUser() {
if (simpleModelMutableLiveData == null) {
simpleModelMutableLiveData = new MutableLiveData<>();
}
return simpleModelMutableLiveData;
}
// this method will return Object of MutableLiveData<String> and let the simpleModelMutableLiveData be the returned object
private void checkLogin(String placeholder) {
simpleModelMutableLiveData = MyRepo.checkLogin(placeholder);
}
public void onLoginClick(View view) {
checkLogin("test");
}
and at last the Repo method in which i will return the MutableLiveData and let the simpleModelMutableLiveData to be the return and initiate a background thread using runnable that will wait 5 seconds before it sets the value using a handler (in your case you will need to set the value of the data after enqueue inside the Overridden Methods onResponse and onFailure)
as follows
public static MutableLiveData<String> checkLogin(String test) {
final MutableLiveData<String> data = new MutableLiveData<>();
Runnable r = new Runnable() {
public void run() {
runYourBackgroundTaskHere(data);
}
};
new Thread(r).start();
return data;
}
private static void runYourBackgroundTaskHere(final MutableLiveData<String> data) {
try {
Thread.sleep(5000);
// Handler handler = new Handler();
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// things to do on the main thread
/* Here i set the data to sss and then null and when
you check the logcat and type the keyword used for
logging which is "testinggg"
you will find it show sss and then null which means
it has entered the onChanged and showed you the log */
data.setValue("sss");
data.setValue(null);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I'm trying to build an app to fetch list of feed from server and display in Recyclerview. I am trying out basic implementation of LiveData like this.
I have set up an observer in my Fragment as follows:
viewModel = ViewModelProviders.of(getActivity()).get(SellViewModel.class);
viewModel.getSellItemList(19).observe(this, new Observer<List<LambdaSellRequestClass>>() {
#Override
public void onChanged(#Nullable List<LambdaSellRequestClass> sellItems) {
adapter.setSellEntities(sellItems);
}
});
My SellViewModel clas like this:
public class SellViewModel extends AndroidViewModel {
private SellRepository repository;
private MutableLiveData<List<LambdaSellRequestClass>> sellItems;
public SellViewModel(#NonNull Application application) {
super(application);
repository = new SellRepository(application);
try {
if (sellItems == null) {
sellItems = new MutableLiveData<>();
sellItems.postValue(repository.getSellItemList(user_id));
}
}catch (Exception e) {
Log.d("SELLFRAGMENT", "Error: " + e.getLocalizedMessage());
}
}
public MutableLiveData<List<LambdaSellRequestClass>> getSellItemList(int userId) throws ExecutionException, InterruptedException {
return sellItems;
}
}
My SellRepository like this:
public class SellRepository {
public SellRepository(Application application) {
}
public List<LambdaSellRequestClass> getSellItemList(int userId) throws ExecutionException, InterruptedException {
return new SellRepository.GetSellItemListAsync(SellRepository.this).execute(userId).get();
}
private static class GetSellItemListAsync extends AsyncTask<Integer, Void, List<LambdaSellRequestClass>> {
List<LambdaSellRequestClass> list = new ArrayList<>();
public GetSellItemListAsync() {
}
#Override
protected List<LambdaSellRequestClass> doInBackground(Integer... integers) {
final int userID = integers[0];
list =
lambdaFunctionsCalls.getSellItemByUser_lambda(requestClass).getSellItems();
return list;
}
}
My problem is when I add new sell items to database its not update mobile app.
I am trying to call the web service to fetch the data and storing it into database using following code. I have created a separate class to perform following operation.
Now , the issue is i want to notify my activity when i successfully fetch and store data in database. if some error occurs then i want to show that on UI itself.
somehow i am able to write a code to fetch the data using pagination but not sure how would i notify UI where i can subscribe catch the update related to progress and error if any.
public Flowable<Response> getFitnessData() {
Request request = new Request();
request.setAccess_token("d80fa6bd6f78cc704104d61146c599bc94b82ca225349ee68762fc6c70d2dcf0");
Flowable<Response> fitnessFlowable = new WebRequest()
.getRemoteClient()
.create(FitnessApi.class)
.getFitnessData("5b238abb4d3590001d9b94a8",request.toMap());
fitnessFlowable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.takeUntil(response->response.getSummary().getNext()!=null)
.subscribe(new Subscriber<Response>() {
#Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
#Override
public void onNext(Response response) {
Log.e(TAG, "onNext" );
if(response !=null){
if(response.getFitness()!=null && response.getFitness().size()!=0){
Realm realm = Realm.getDefaultInstance();
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(response.getFitness());
}
}, new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess() {
Log.i(TAG, "onSuccess , fitness data saved");
}
}, new Realm.Transaction.OnError() {
#Override
public void onError(Throwable error) {
Log.i(TAG, "onError , fitness data failed to save"+error.getMessage() );
}
});
}else{
Log.i(TAG, "onError , no fitness data available" );
}
}else{
Log.i(TAG, "onError , response is null" );
}
}
#Override
public void onError(Throwable t) {
Log.e(TAG, "onError" +t.getMessage());
}
#Override
public void onComplete() {
Log.e(TAG, "onComplete");
}
});;
return null;
}
Updated
Created RxBus to propagate events and error on UI
public class RxBus {
private static final RxBus INSTANCE = new RxBus();
private RxBus(){}
private PublishSubject<Object> bus = PublishSubject.create();
public static RxBus getInstance() {
return INSTANCE;
}
public void send(Object o) {
bus.onNext(o);
}
public void error(Throwable e){bus.onError(e);}
public Observable<Object> toObservable() {
return bus;
}
}
in activity
FitnessRepo fitnessRepo = new FitnessRepo();
fitnessRepo.getFitnessData();
RxBus.getInstance().toObservable().subscribe(new Observer<Object>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Object o) {
if(o instanceof RealmList ){
RealmList<Fitness> realmList = (RealmList<Fitness>) o;
Log.e(TAG,"Fitness data size "+realmList.size());
}
}
#Override
public void onError(Throwable e) {
Log.e(TAG,e.getMessage()+ "");
if (e instanceof HttpException) {
ResponseBody body = ((HttpException) e).response().errorBody();
try {
Response response= LoganSquare.parse(body.byteStream(),Response.class);
if(response.getErrors() !=null)
if(response.getErrors().size() > 0)
Log.e(TAG, "Error "+response.getErrors().get(0).getErrors());
} catch (IOException t) {
t.printStackTrace();
}
}
}
#Override
public void onComplete() {
}
});
in a web service call
public void getFitnessData() {
Request request = new Request();
request.setAccess_token("d80fa6bd6f78cc704104d61146c599bc94b82ca225349ee68762fc6c70d2dcf0");
request.setEnd_date("2018-07-01T00:00:00");
Flowable<Response> fitnessFlowable = new WebRequest()
.getRemoteClient()
.create(FitnessApi.class)
.getFitnessData("5b238abb4d3590001d9b94a8",request.toMap());
fitnessFlowable.subscribeOn(Schedulers.io())
.takeUntil(response->response.getSummary().getNext()!=null)
.doOnNext((response) -> {
if(response ==null || response.getFitness() == null || response.getFitness().isEmpty()) {
Log.e(TAG, " Error ");
return;
}
RxBus.getInstance().send(response.getFitness());
try(Realm r = Realm.getDefaultInstance()) {
r.executeTransaction((realm) -> {
realm.copyToRealmOrUpdate(response.getFitness());
});
}
}).subscribe(item ->{
},
error ->{
RxBus.getInstance().error(error);
});
}
I have good news for you! You can delete almost all of that code and just make it generally better as a result!
public void fetchFitnessData() {
Request request = new Request();
request.setAccess_token("d80fa6bd6f78cc704104d61146c599bc94b82ca225349ee68762fc6c70d2dcf0");
Flowable<Response> fitnessFlowable = new WebRequest()
.getRemoteClient()
.create(FitnessApi.class)
.getFitnessData("5b238abb4d3590001d9b94a8",request.toMap());
fitnessFlowable.subscribeOn(Schedulers.io())
.takeUntil(response->response.getSummary().getNext()!=null)
.doOnNext((response) -> {
if(response ==null || response.getFitness() == null || response.getFitness().isEmpty()) return;
try(Realm r = Realm.getDefaultInstance()) {
r.executeTransaction((realm) -> {
realm.insertOrUpdate(response.getFitness());
});
}
}
}).subscribe();
}
This method is on a background thread now and returns void, so the way to emit stuff out of this method would be to use either a PublishSubject (one for success, one for failure) or an EventBus.
private PublishSubject<Object> fitnessResults;
public Observable<Object> observeFitnessResults() {
return fitnessResults;
}
public static class Success {
public Success(List<Fitness> data) {
this.data = data;
}
public List<Fitness> data;
}
public static class Failure {
public Failure(Exception exception) {
this.exception = exception;
}
public Exception exception;
}
public void fetchFitnessData() {
...
fitnessResults.onNext(new Success(data));
} catch(Exception e) {
fitnessResults.onNext(new Failure(e));
And then
errors = observeFitnessResults().ofType(Error.class);
success = observeFitnessResults().ofType(Success.class);
There are different ways to achieve this. I will never handle the subscriptions on my own out of a lifecycle scope as it creates a possibility of memory leak. In your case it seems that both success and failure is bound to the UI so you can simply do this.
public Completable fetchFitnessData() {
Request request = new Request();
request.setAccess_token("d80fa6bd6f78cc704104d61146c599bc94b82ca225349ee68762fc6c70d2dcf0");
Flowable<Response> fitnessFlowable = new WebRequest()
.getRemoteClient()
.create(FitnessApi.class)
.getFitnessData("5b238abb4d3590001d9b94a8",request.toMap());
return fitnessFlowable.subscribeOn(Schedulers.io())
.takeUntil(response->response.getSummary().getNext()!=null)
.doOnNext((response) -> {
if(response ==null || response.getFitness() == null || response.getFitness().isEmpty()) return;
try(Realm r = Realm.getDefaultInstance()) {
r.executeTransaction((realm) -> {
realm.insertOrUpdate(response.getFitness());
});
}
}
}).ignoreElements();
}
At UI level, you can just handle your subscription with both success and failure. In case you need success model can replace Completable with Single or Flowable.
fetchFitnessData.subscrible(Functions.EMPTY_ACTION, Timber::d);
The major advantage with this approach is that you handle your subscription lifecycles.
i triying to do a simple MVP in Android using AndroidAnnotations and Retrofit2,
But I never get the information.
Code Presenter:
public class ListHomePresenter {
private List<Post> mPost;
Client client;
int error_code = 0;
String error_msg = "";
/**
* TODO: get all post
* */
public List<Post> getPost() throws SampleExceptions{
RestService restService;
client = new Client();
restService = client.getApi();
Call<List<Post>> task = restService.downloadPost();
task.enqueue(new Callback<List<Post>>() {
#Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
mPost = response.body();
}
#Override
public void onFailure(Call<List<Post>> call, Throwable t) {
mPost = null;
error_code = 1; // error
error_msg = t.getMessage(); // message
}
});
if(error_code == 1 )
throw new SampleExceptions(error_code, "Error");
return mPost;
}
}
Code Activity
#EActivity(R.layout.activity_home)
public class HomeActivity extends AppCompatActivity {
#ViewById(R.id.rvPosts)
RecyclerView mRvPost;
PostAdapter mPostAdapter;
ListHomePresenter mListHomePresenter;
private StaggeredGridLayoutManager gaggeredGridLayoutManager;
#AfterViews
void setupHome(){
downloadPost();
}
#UiThread(propagation = Propagation.REUSE)
void downloadPost(){
try{
mListHomePresenter = new ListHomePresenter();
gaggeredGridLayoutManager = new StaggeredGridLayoutManager(2, 1);
mRvPost.setLayoutManager(gaggeredGridLayoutManager);
mPostAdapter = new PostAdapter(HomeActivity.this, mListHomePresenter.getPost());
mRvPost.setAdapter( mPostAdapter );
}catch (SampleExceptions e){
}
}
}
but, ever i getting the null data.
Help Me!
Here an example:
Presenter:
public class ListHomePresenter {
private List<Post> mPost;
Client client;
int error_code = 0;
String error_msg = "";
HomeView view;
public ListHomePresenter(HomeView view) {
this.view = view;
}
/**
* TODO: get all post
* */
public void loadPost() throws SampleExceptions{
RestService restService;
client = new Client();
restService = client.getApi();
Call<List<Post>> task = restService.downloadPost();
task.enqueue(new Callback<List<Post>>() {
#Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
view.retrieveData(response.body());
}
#Override
public void onFailure(Call<List<Post>> call, Throwable t) {
mPost = null;
error_code = 1; // error
error_msg = t.getMessage(); // message
}
});
if(error_code == 1 )
throw new SampleExceptions(error_code, "Error");
}
}
Activity:
#ViewById(R.id.rvPosts)
RecyclerView mRvPost;
PostAdapter mPostAdapter;
ListHomePresenter mListHomePresenter;
private StaggeredGridLayoutManager gaggeredGridLayoutManager;
#AfterViews
void setupHome() {
downloadPost();
}
#UiThread(propagation = Propagation.REUSE)
void downloadPost() {
try {
mListHomePresenter = new ListHomePresenter(this);
mListHomePresenter.loadPost()
} catch (SampleExceptions e) {
}
}
// Method implemented from view interface
#Override
void retrieveData(List<Post> postList) {
gaggeredGridLayoutManager = new StaggeredGridLayoutManager(2, 1);
mRvPost.setLayoutManager(gaggeredGridLayoutManager);
mPostAdapter = new PostAdapter(HomeActivity.this, postList);
mRvPost.setAdapter(mPostAdapter);
}
Only you needs implement an interface view to interacts between two classes
You have a race condition on your getPost method, when return mPost, the callback has not yet returned the response.
I recommend that the getPost method does not return anything, and once you pass onResponse, you call a view method that fills the adapter.
This ensures that you will always have data.