Display and hide progress bar using MVVM pattern - android

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

Related

While fetching data and storing it into sqlite db the UI of my app freezes

Hello My app is freezes ui for some seconds while it is fetching data from network and stores it in db and then shows it in recyclerview. For fetching data from network I am using retrofit and for storing it and fetching form db Room library. Both with the help of MVVM pattern. Is there a way to remoove the UI freeze?
Here is my code:
In the Mainactivity when clicking download btn
downloadBtn.setOnClickListener(v ->
eventsViewModel.insertEvents(this));
Viewmodel class:
public void insertEvents(Context context){
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String token = preferences.getString("token", "");
final Map<String,String> queryData = new HashMap<>();
queryData.put("token", token);
Call<EventsResponse> call = RetrofitClient.getmInstance().getApi().getEvents(queryData);
call.enqueue(new Callback<EventsResponse>() {
#Override
public void onResponse(Call<EventsResponse> call, Response<EventsResponse> response) {
if (response.code() == 401){
String email = preferences.getString("email", "");
String password = preferences.getString("password", "");
Call<LoginResponse> call1 = RetrofitClient.getmInstance().getApi().loginuser(email, password);
call1.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if (response.code() == 200){
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context); // 0 - for private mode
SharedPreferences.Editor editor = pref.edit();
editor.putString("token", response.body().getToken());
editor.apply();
insertEvents(context);
}
else {
}
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
}
if (response.code() == 200){
eventList = response.body().getData();
EventsTable eventsTable = new EventsTable();
TicketDatesTable ticketDatesTable = new TicketDatesTable();
for (int i = 0; i < eventList.size(); i++) {
eventsTable.setEvent_id(eventList.get(i).getId());
eventsTable.setTitle_tk(eventList.get(i).getTitle_tk());
eventsTable.setTitle_ru(eventList.get(i).getTitle_ru());
eventsTable.setImageURL("https://bilettm.com/" + eventList.get(i).getImage_url());
eventsTable.setStart_date(eventList.get(i).getStart_date());
eventsTable.setEnd_date(eventList.get(i).getEnd_date());
eventsTable.setSales_volume(eventList.get(i).getEnd_date());
eventsTable.setOrganiser_fees_volume(eventList.get(i).getOrganiser_fees_volume());
eventsTable.setViews(eventList.get(i).getViews());
eventsTable.setSales_volume(eventList.get(i).getSales_volume());
eventsTable.setIs_live(eventList.get(i).getIs_live());
if (!eventList.get(i).getTicket_dates().isEmpty()) {
showTimeList = eventList.get(i).getTicket_dates();
int b = 0;
while (b < showTimeList.size()) {
ticketDatesTable.setEvent_id(showTimeList.get(b).getEvent_id());
ticketDatesTable.setTicket_date(showTimeList.get(b).getTicket_date());
insertTicketDates(ticketDatesTable);
try {
Thread.sleep(150);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
b++;
}
}
insert(eventsTable);
try {
Thread.sleep(150);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
#Override
public void onFailure(Call<EventsResponse> call, Throwable t) {
}
});
}
public void insert(EventsTable data){
repository.insertEvents(data);
}
public void insertTicketDates(TicketDatesTable ticketDatesTable){
repository.insertTicketDates(ticketDatesTable);
Here is my repository :
public void insertEvents(EventsTable data){
new EventInsertion(eventsDAO).execute(data);
}
private static class EventInsertion extends AsyncTask<EventsTable, Void, Void> {
private EventsDAO eventsDAO;
private EventInsertion(EventsDAO eventsDAO) {
this.eventsDAO = eventsDAO;
}
#Override
protected Void doInBackground(EventsTable... eventsTables) {
eventsDAO.insertEvents(eventsTables[0]);
return null;
}
}
public void insertTicketDates(TicketDatesTable data){
new TicketDatesInsertion(eventsDAO).execute(data);
}
private static class TicketDatesInsertion extends AsyncTask<TicketDatesTable, Void, Void> {
private EventsDAO eventsDAO;
private TicketDatesInsertion(EventsDAO eventsDAO) {
this.eventsDAO = eventsDAO;
}
#Override
protected Void doInBackground(TicketDatesTable... ticketDatesTables) {
eventsDAO.insertTicketDates(ticketDatesTables[0]);
return null;
}
}
Here is my DAO:
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insertEvents(EventsTable data);
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insertTicketDates(TicketDatesTable datesTable);
I think it freezes when it is storing it into sqlite db
I found my problem. It was initializing entity before starting for loop:
BEFORE:
EventsTable eventsTable = new EventsTable();
for (int i = 0; i < eventList.size(); i++) {
INSERT();
}
AFTER:
for (int i = 0; i < eventList.size(); i++) {
EventsTable eventsTable = new EventsTable();
INSERT();
}
A better solution would be to collect all your required objects in an ArrayList and then pass it on to the AsyncTask and from there to DAO for bulk insertion.
And remove all Thread.sleep(150) statements as they serve no purpose.
why you are using this Thread.sleep(150);Call is already a background task in retrofit

How to cancel retrofit request in model while using mvp pattern

enter image description herei want to cancel request in model implementation using mvp pattern in android
iam using retrofit2 .in this method i sent file path and state to check on it because button action make (upload,cancel)in the same function.
this snipet of class
{public class ModelImpl implements UploadInterface.Interactor, ProgressRequestBody.UploadCallbacks {enter image description here
//another way we can use retrofit call here to upload file and
//return result in OnFinishedListener interface inside model interface
//we use here service to upload to run in background service
// this way we can cancel request and retry
//but using intent service in service difficult to stop because it designed to
//run long task and stop it self with caller.
private OnProgressListener listener;
public ModelImpl(OnProgressListener listener) {
this.listener = listener;
}
#Override
public void uploadImage(String status, String filePath, OnFinishedListener onFinishedListener) {
// call servce to start upload throw service
/*Intent mIntent = new Intent(context, FileUploadService.class);
mIntent.putExtra("mFilePath", filePath);
FileUploadService.enqueueWork(context, mIntent);*/
// starting http service upload
if (!filePath.isEmpty()) {
File file = new File(filePath.trim());
ProgressRequestBody fileBody = new ProgressRequestBody(file, "image", this);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("fileUpload", file.getName(), fileBody);
RestApiService apiService = RetrofitInstance.getApiService();
Call<PojoResponse> callUpload = apiService.onFileUpload2(filePart);
if (status.equals("upload")) {
callUpload.enqueue(new Callback<PojoResponse>() {
#Override
public void onResponse(Call<PojoResponse> call, Response<PojoResponse> response) {
Log.d("ResponseData", "" + response.body().getUrl());
onFinishedListener.onFinished(response.body());
}
#Override
public void onFailure(Call<PojoResponse> call, Throwable t) {
if (call != null && !call.isCanceled()) {
// Call is not cancelled, Handle network failure
onFinishedListener.onFailure(call, t);
} else if (call != null && call.isCanceled()) {
// Call is CANCELLED. IGNORE THIS SINCE IT WAS CANCELLED.
onFinishedListener.onFailure(call, t);
}
//onFinishedListener.onFailure(call, t);
}
});
} else {
if (callUpload != null && callUpload.isExecuted()) {
callUpload.cancel();
}
}
}
}
}
package com.example.mvp2.ui.main.model;
import android.util.Log;
import com.example.mvp2.ui.main.network.RestApiService;
import com.example.mvp2.ui.main.network.RetrofitInstance;
import com.example.mvp2.ui.main.utils.ProgressRequestBody;
import com.example.mvp2.ui.main.views.upload.UploadInterface;
import java.io.File;
import okhttp3.MultipartBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ModelImpl implements UploadInterface.Interactor, ProgressRequestBody.UploadCallbacks {
//another way we can use retrofit call here to upload file and
//return result in OnFinishedListener interface inside model interface
//we use here service to upload to run in background service
// this way we can cancel request and retry
//but using intent service in service difficult to stop because it designed to
//run long task and stop it self with caller.
private OnProgressListener listener;
private Call < PojoResponse > callUpload;
public ModelImpl(OnProgressListener listener) {
this.listener = listener;
}
#Override
public void uploadImage(String status, String filePath, OnFinishedListener onFinishedListener) {
if (!filePath.isEmpty()) {
File file = new File(filePath.trim());
ProgressRequestBody fileBody = new ProgressRequestBody(file,
"image", this);
MultipartBody.Part filePart =
MultipartBody.Part.createFormData("fileUpload", file.getName(), fileBody);
RestApiService apiService = RetrofitInstance.getApiService();
callUpload = apiService.onFileUpload2(filePart);
// if (status.equals("upload")) {
callUpload.enqueue(new Callback < PojoResponse > () {
#Override
public void onResponse(Call < PojoResponse > call, Response < PojoResponse > response) {
Log.d("ResponseData", "" + response.body().getUrl());
onFinishedListener.onFinished(response.body());
}
#Override
public void onFailure(Call < PojoResponse > call, Throwable t) {
if (call != null && !call.isCanceled()) {
// Call is not cancelled, Handle network failure
onFinishedListener.onFailure(call, t);
} else if (call != null && call.isCanceled()) {
// Call is CANCELLED. IGNORE THIS SINCE IT WAS CANCELLED.
onFinishedListener.onFailure(call, t);
}
}
});
// }
/* else {
if (callUpload != null && callUpload.isExecuted()) {
callUpload.cancel();
// this will go to presenter
onFinishedListener.onCancel();
}
}*/
}
}
public void cancelUpload() {
if (callUpload != null && callUpload.isExecuted()) {
callUpload.cancel();
// this will go to presenter
onFinishedListener.onCancel();
}
}
#Override
public void onProgressUpdate(int percentage) {
Log.d("percent", "" + percentage);
listener.onProgressChange(percentage);
}
#Override
public void onError() {
}
#Override
public void onFinish() {
Log.d("percent", "" + "finishedddddd");
listener.onProgressFinished();
}
}
UploadActivityPresenter .java
package com.example.mvp2.ui.main.views.upload;
import android.util.Log;
import com.example.mvp2.ui.main.model.ModelImpl;
import com.example.mvp2.ui.main.model.PojoResponse;
import retrofit2.Call;
public class UploadActivityPresenter implements UploadInterface.Presenter, UploadInterface.Interactor.OnFinishedListener, UploadInterface.Interactor.OnProgressListener {
private UploadInterface.View view;
private UploadInterface.Interactor model;
public UploadActivityPresenter(UploadInterface.View view) {
this.view = view;
model = new ModelImpl(this);
}
#Override
public void uploadBtnClicked(String status, String filePath) {
// this interface call method upload without know about logic about it
// model = new ModelImpl(this);
if (view != null) {
if (filePath.length() > 0) {
Log.d("filepath", "" + filePath.trim());
view.setStatus(status);
if (model != null) {
if (status.equals("upload")) {
model.uploadImage(status, filePath, this);
} else {
model.cancelUpload()
}
}
Log.d("ss", "ssssss");
} else {
view.selectFileFirst();
}
}
}
#Override
public void imageClicked() {
if (view != null) {
view.showFullImageInFragment();
}
}
#Override
public void onFinished(PojoResponse obj) {
if (view != null) {
view.getResponse(obj);
view.setStatus("Done");
}
}
#Override
public void onFailure(Call < PojoResponse > call, Throwable t) {
if (view != null) {
view.errorUploading(call, t);
}
}
#Override
public void onCancel() {
if (view != null) {
}
}
#Override
public void onProgressChange(int percent) {
Log.d("aaaaa", "" + percent);
if (view != null) {
view.setProgressPercent(percent);
}
}
#Override
public void onProgressFinished() {
if (view != null) {
view.setProgressFinished();
}
}
}
this should work , u were creating new Model object everytime you upload image or cancel upload image in presenter ,similarly in modelImpl call object was instantiated on every call .
Make sure your presenter class is instantiated one time only .

Android custom listner callback to a different place

I have a general custom listener/callback question.
In my code, I have the following interface and LocalDB class that read room database:
# Custom interface
public interface MyInterface {
void OnSuccess();
void OnFailure();
}
# Class LocalDB
public class LocalDB {
private MyInterface myInterface;
public static PIMUserLocalDataSource getInstance(#NonNull Context context)
{
if (INSTANCE == null) {
synchronized (PIMUserLocalDataSource.class) {
INSTANCE = new PIMUserLocalDataSource(context);
}
}
return INSTANCE;
}
public void setCustomListener(CustomListener customListener) {
this.customListener = customListener;
}
private void queryA() {
Runnable runnable = new Runnable() {
result = appDatabase.myDao().getQueryA();
if (result != null) {
if (customListener != null) {
customListener.onSuccess();
} else {
customListener.onFailure();
}
}
}
}
private void queryB() {
Runnable runnable = new Runnable() {
result = appDatabase.myDao().getQueryB();
if (result != null) {
if (customListener != null) {
customListener.onSuccess();
} else {
customListener.onFailure();
}
}
}
}
}
# Fragment / Activity
LocalDB myDB = LocalDB.getInstance(context)
myDB.setCustomListener(new CustomListener) {
#Override
public void OnSuccess() {
Log.e(logTag, "Success queryA");
}
#Override
public void OnFailure() {
Log.e(logTag, "Failed queryA");
}
}
myDB.queryA()
myDB.setCustomListener(new CustomListener) {
#Override
public void OnSuccess() {
Log.e(logTag, "Success queryB");
}
#Override
public void OnFailure() {
Log.e(logTag, "Failed queryB");
}
}
myDB.queryB()
Problem
These works fine most of the time, however, there is sometimes that queryA is slow and queryB is done before queryA, queryB callback to queryB no problem, but when queryA is done, it callback to queryB listener. I think because the listener of B overwritten A? How should I avoid this kind of problem?
when you call queryA or queryB. pass the listener.
# Custom interface
public interface MyInterface {
void OnSuccess();
void OnFailure();
}
# Class LocalDB
public class LocalDB {
boolean successA,successB;
public static PIMUserLocalDataSource getInstance(#NonNull Context context)
{
if (INSTANCE == null) {
synchronized (PIMUserLocalDataSource.class) {
INSTANCE = new PIMUserLocalDataSource(context);
}
}
return INSTANCE;
}
private void queryA(CustomListener customListener) {
Runnable runnable = new Runnable() {
result = appDatabase.myDao().getQueryA();
if (result != null) {
if (customListener != null) {
customListener.onSuccess();
} else {
customListener.onFailure();
}
}
}
}
private void queryB(CustomListener customListener) {
Runnable runnable = new Runnable() {
result = appDatabase.myDao().getQueryB();
if (result != null) {
if (customListener != null) {
customListener.onSuccess();
} else {
customListener.onFailure();
}
}
}
}
}
# Fragment / Activity
LocalDB myDB_A = LocalDB.getInstance(context)
myDB.setCustomListener(new CustomListener) {
#Override
public void OnSuccess() {
successA=true;
checkIfTwoFinishedExcutecode();
Log.e(logTag, "Success queryA");
}
#Override
public void OnFailure() {
Log.e(logTag, "Failed queryA");
}
}
myDB.queryA(myDB_A )
LocalDB myDB_B = LocalDB.getInstance(context)
#Override
public void OnSuccess() {
successB=true;
checkIfTwoFinishedExcutecode();
Log.e(logTag, "Success queryB");
}
#Override
public void OnFailure() {
Log.e(logTag, "Failed queryB");
}
}
myDB.queryB(myDB_B)
void checkIfTwoFinishedExcutecode(){
if(successA&&successB){
// the two is finished. write your code
}
}

AWS AppSync Android NullPointerException

public void queryData(){
if(mAWSAppSyncClient == null){
mAWSAppSyncClient = ClientFactory.getInstance(this);
}
mAWSAppSyncClient.query(GetCounterDataQuery.builder().build())
.responseFetcher(AppSyncResponseFetchers.CACHE_AND_NETWORK)
.enqueue(postsCallback);
}
public GraphQLCall.Callback<GetCounterDataQuery.Data> postsCallback = new GraphQLCall.Callback<GetCounterDataQuery.Data>() {
#Override
public void onResponse(#Nonnull final Response<GetCounterDataQuery.Data> response) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(response.data()!=null) {
TextView value = (TextView) findViewById(R.id.counterValue);
value.setText(response.data().getCounterData().counterData);
TextView Name = (TextView) findViewById(R.id.counterName);
Name.setText(response.data().getCounterData().counterName);
}
}
});
}
In the GraphQL Callback method, response.data() I am getting NullPointerException.(Even though I am using if condition to check null ) How to resolve?
Thanks for the replies,
Now its working fine with this solution, In response callback I have added some value if the response is NULL, it wouldn't be null in my case.
public void queryData(String id){
if(mAWSAppSyncClient == null){
mAWSAppSyncClient = ClientFactory.getInstance(this);
}
mAWSAppSyncClient.query(GetCounterQuery.builder().id(id).build())
.responseFetcher(AppSyncResponseFetchers.CACHE_AND_NETWORK)
.enqueue(postsCallback);
}
public GraphQLCall.Callback<GetCounterQuery.Data> postsCallback = new GraphQLCall.Callback<GetCounterQuery.Data>() {
#Override
public void onResponse(#Nonnull final Response<GetCounterQuery.Data> response) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(response != null) {
String valuestr = (response.data().getCounter().counterNumber != NULL ) ? (response.data().getCounter().counterNumber).toString() : "66";
TextView value = (TextView) findViewById(R.id.counterValue);
value.setText(valuestr);
String nameStr= (response.data().getCounter().counterName).isEmpty() ? "HAHAHA" : response.data().getCounter().counterName;
TextView Name = (TextView) findViewById(R.id.counterName);
Name.setText(nameStr);
}
}
});
}
#Override
public void onFailure(#Nonnull ApolloException e) {
}
};

How can I wait for an object filled asynchronously in Android UI thread without blocking it?

I have a singleton to handle the registration and elimination of an entity Profilo ( a Profile).
This entity is set by passing an identifier and gathering information on the server in an async way.
My problem is that when I have to return my instance of profilo if it's not still loaded it will return null.
public class AccountHandler {
private static AccountHandler istanza = null;
Context context;
private boolean logged;
private Profilo profilo;
private AccountHandler(Context context) {
this.context = context;
//initialization
//setting logged properly
assignField(this.getName());
}
}
public static AccountHandler getAccountHandler(Context context) {
if (istanza == null) {
synchronized (AccountHandler.class) {
if (istanza == null) {
istanza = new AccountHandler(context);
}
}
}
return istanza;
}
public void setAccount(String nickname, String accessingCode) {
logged = true;
assignField(nickname);
}
//other methods
private void assignField(String nickname) {
ProfiloClient profiloClient = new ProfiloClient();
profiloClient.addParam(Profilo.FIELDS[0], nickname);
profiloClient.get(new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode,
Header[] headers,
JSONArray response) {
JSONObject objson = null;
try {
objson = (JSONObject) response.getJSONObject(0);
} catch (JSONException e) {
e.printStackTrace();
}
AccountHandler accountHandler = AccountHandler.getAccountHandler(context);
// Profilo is created with a JSONObject
// **setProfilo is called in async**
**accountHandler.setProfilo(new Profilo(objson));**
}
});
}
private void setProfilo(Profilo profilo) {
this.profilo = profilo;
}
public Profilo getProfilo() {
if( logged && profilo == null)
//How can I wait that profilo is loaded by the JsonHttpResponseHandler before to return it
return this.profilo;
}
}
Instead of calling getProfilo you could use a callback mechanism in which the AccountHandler class notifies the caller when the profile has been loaded. e.g.
public void setAccount(String nickname, String accessingCode, MyCallback cb) {
assignField(nickname, cb);
}
private void assignField(String nickname, MyCallback cb) {
....
accountHandler.setProfilo(new Profilo(objson));
cb.onSuccess(this.profilo);
}
Create an inner Interface MyCallback (rename it) in your AccountHandler class
public class AccountHandler {
public interface MyCallback {
void onSuccess(Profilo profile);
}
}
Now whenever you call setAccount you will pass the callback and get notified when the profile is available e.g.
accountHandler.setAccount("Test", "Test", new AccountHandler.MyCallback() {
void onSuccess(Profilio profile) {
// do something with the profile
}
}
I added, as #Murat K. suggested, an interface to my Class that will provide a method to be call with the object when it is ready to be used.
public class AccountHandler {
public interface Callback {
void profiloReady(Profilo profilo);
}
}
This method is called in getProfilo in a Handler that makes recursive calls to getProfilo until profilo is ready to be used, then it call the callback method which class is passed as argument of getProfilo.
public void getProfilo(final Callback Callback) {
if( logged && (profilo == null || !profilo.isReady() ) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
getProfilo(Callback);
}
}, 500);
}else
Callback.profiloReady(profilo);
}
Example of getProfilo call
public class ProfiloCall implements AccountHandler.MyCallback {
#Override
public void profiloReady(Profilo profilo) {
//Use profilo as needed
//EXECUTED ONLY WHEN PROFILO IS READY
}
public void callerMethod() {
//useful code
accountHandler.getProfilo(this);
//other useful code
}
}

Categories

Resources