I'm implementing a two-level nested recyclerView and both recycler views make an API call using retrofit. This is the method that makes the synchronous request:
public void loadSectionStories(String sessionKey, CuratedSection section) {
Call<JsonArray> subCall;
subCall = TravelersApi.endpoint().getCuratedSectionTopics(sessionKey, section.id);
try {
Response<JsonArray> response = subCall.execute();
if(response.code() != 200) {
Toast.makeText(getApplicationContext(), "Cannot load page as of the moment.", Toast.LENGTH_SHORT).show();
return;
}
JsonArray rawStories = response.body();
if(rawStories.size() == 0) {
//TODO: show placeholder
return;
}
ArrayList<CuratedSectionItem> stories = new ArrayList<>();
for(int i = 0; i < rawStories.size(); i++) {
JsonObject jStories = rawStories.get(i).getAsJsonObject();
JSONObject temp = new JSONObject(jStories.toString());
JsonObject author = jStories.get("author").getAsJsonObject();
CuratedSectionItem story = new CuratedSectionItem();
story.title = jStories.get("title").getAsString();
story.avatar = author.get("profile_photo").getAsString();
story.displayPhoto = temp.getString("primary_photo");
story.username = author.get("username").getAsString();
story.description = jStories.get("content").getAsString();
story.topicId = jStories.get("id").getAsString();
story.postId = jStories.get("first_post_id").getAsString();
story.hasReacted = false;
story.upvotes = jStories.get("stats").getAsJsonObject().get("upvotes").getAsInt();
stories.add(story);
}
section.stories = stories;
} catch (IOException e) {
Log.d("ERROR!", e.toString());
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
This is the method that makes the asynchronous request and also calls loadSectionStories in a thread:
public void loadCuratedSections(final int start, final int limit) {
SharedPreferences prefs = getSharedPreferences("user_session", MODE_PRIVATE);
final String sessionKey = prefs.getString("session_key", null);
Call<JsonArray> call;
call = TravelersApi.endpoint().getCuratedSections(sessionKey);
call.enqueue(new Callback<JsonArray>() {
#Override
public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {
if(response.code() != 200) {
Toast.makeText(getApplicationContext(), "Cannot load page as of the moment.", Toast.LENGTH_SHORT).show();
return;
}
JsonArray rawSections = response.body();
if(rawSections.size() == 0) {
return;
}
for (int i = start; i < limit; i++) {
JsonObject jSection = rawSections.get(i).getAsJsonObject();
final CuratedSection section = new CuratedSection();
section.id = jSection.get("id").getAsString();
section.header = jSection.get("section_header").getAsString();
section.isShown = jSection.get("is_shown").getAsBoolean();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
loadSectionStories(sessionKey, section);
}
});
thread.start();
curatedSections.add(section);
}
}
#Override
public void onFailure(Call<JsonArray> call, Throwable t) {
Log.d("ERROR!", t.toString());
t.printStackTrace();
}
});
}
Everything is working fine except the fact that section.stories returns null. It doesn't make sense to me because of this statement section.stories = stories inside loadSectionStories.
If you are using section.stories before your synchronous request is completed (which is running in new threads) then it will return null which is currently happening.
so either you have to remove new thread flow if you want to use it after your first asynchronous request is completed,
or you have to reload your recycler view when you stories is updated.
Also why are you executing your synchronous request(loadSectionStories) in new thread, is it not similar to asynchronous request?
Retrofit asyncRetrofit = new Retrofit.Builder()
.baseUrl(URLS.MAIN_SERVER_URL)
// below line create thread for syncrouns request
.callbackExecutor(Executors.newSingleThreadExecutor())
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
this will run your request in asyncronous
Related
I want to WorkManager startWork() to be called every time the user connects to the internet through wifi or 3g/4g/5g.
It calls only one time at the start where I register it.
enqueuing work when a user signs in.
Worker.startWorkManager(SignInActivity.this);
startActivity(new Intent(SignInActivity.this,UsersActivity.class);
it never calls again whenever the user turns Wifi OFF and ON again regardless app is in foreground or background or app is killed through swiped from recent apps.
I want it to be called every time user turned Wifi OFF and ON in every scenario i.e foreground, background, or app is killed.
Worker.class
public class Worker {
public Worker(Context context, WorkerParameters workerParams) {
}
public static void startWorkManager(Context context) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
WorkManager.getInstance(context).enqueueUniqueWork(Constants.TAG_SYNC_DATA, ExistingWorkPolicy.KEEP, new OneTimeWorkRequest.Builder(SyncDataWorker.class)
.addTag(Constants.TAG_SYNC_DATA)
.setConstraints(constraints)
.build());
}
}
SyncDataWorker.class
public class SyncDataWorker extends ListenableWorker {
public SyncDataWorker(
#NonNull Context context,
#NonNull WorkerParameters params) {
super(context, params);
}
#NonNull
#Override
public ListenableFuture<Result> startWork() {
return CallbackToFutureAdapter.getFuture(completer -> {
AsyncCallback callback = new AsyncCallback() {
#Override
public void onFailure(Exception e) {
completer.setException(e);
}
#Override
public void onSuccess() {
completer.set(Result.success());
}
#Override
public void onRetry() {
completer.set(Result.retry());
}
};
new AsyncSyncData(getApplicationContext(), callback).execute();
return callback;
});
}
}
AsyncSynData.class
public class AsyncSyncData extends AsyncTask<Void, Void, Void> {
private final Context context;
ArrayList<message> messageArrayListNotSync;
ArrayList<unread_messages> unreadMessagesArrayList;
String user_id = "";
private AsyncCallback callback = null;
public AsyncSyncData(Context context, AsyncCallback callback) {
this.context = context;
messageArrayListNotSync = new ArrayList<>();
unreadMessagesArrayList = new ArrayList<>();
this.callback = callback;
}
#Override
protected Void doInBackground(Void... voids) {
AppDatabase db = AppDatabase.getAppDatabase(context);
user user = null;
ArrayList<user> userArrayList = new ArrayList<>(db.applicationDao().getAllUsers());
if (userArrayList.size() > 0) {
user = userArrayList.get(0);
}
messageArrayListNotSync = new ArrayList<>(db.applicationDao().getAllMessagesNotSync(!user_id.isEmpty() ? user_id : user.threadId));
unreadMessagesArrayList = new ArrayList<>(db.applicationDao().getUnreadMessageStatus());
System.out.println("messageArrayListNotSync: " + messageArrayListNotSync);
System.out.println("unreadMessagesArrayList: " + unreadMessagesArrayList);
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("user_id", !user_id.isEmpty() ? user_id : user.threadId);
Gson gson = new GsonBuilder().create();
JsonArray json_messages = gson.toJsonTree(messageArrayListNotSync).getAsJsonArray();
JsonArray json_unread_messages = gson.toJsonTree(unreadMessagesArrayList).getAsJsonArray();
jsonObject.put("messages", json_messages);
jsonObject.put("unread_messages", json_unread_messages);
RequestHandler.postRequest("/messages", jsonObject, context, new VolleyCallback() {
#Override
public void onSuccess(JSONObject result) {
final JSONObject finalResult = result;
try {
if (result != null && result.has("success") && result.getBoolean("success")) {
new AsyncDeleteUnreadMessagesList(context, unreadMessagesArrayList, new Callback() {
#Override
public void onCallbackCompleted() {
try {
ArrayList<com.app.amber.internet.DATABASE_OPERATIONS.schema.message> messagesToStore = new ArrayList<>();
JSONObject result = finalResult.getJSONObject("data");
JSONObject last_messages = result.getJSONObject("last_messages");
new AsyncUpdateLastMessage(context, last_messages, true, new Callback() {
#Override
public void onCallbackCompleted() {
try {
JSONArray json_messages_to_store = result.getJSONArray("messages");
JSONArray json_evetns_type_1 = result.getJSONArray("eventsType1");
JSONArray json_evetns_type_2 = result.getJSONArray("eventsType2");
for (int i = 0; i < json_messages_to_store.length(); i++) {
JSONObject data = json_messages_to_store.getJSONObject(i);
String id = data.getString("id"),
sender_id = data.getString("sender_id"),
receiver_id = data.getString("receiver_id"),
msg = data.getString("msg"),
type = data.getString("type"),
path = data.getString("path"),
download_status = data.getString("download"),
group_users = data.getString("group_users"),
group_message_status = data.getString("group_message_status");
boolean is_sender = false;
long data_created = data.getLong("date_created");
int is_read = 0;
com.app.amber.internet.DATABASE_OPERATIONS.schema.message message =
new com.app.amber.internet.DATABASE_OPERATIONS.schema.message(id, sender_id, receiver_id, msg, type, path, is_sender, data_created,
is_read, download_status, sender_id, group_users, group_message_status);
messagesToStore.add(message);
}
ArrayList<String> messageIdsType1 = new ArrayList<>();
ArrayList<String> messageIdsType2 = new ArrayList<>();
for (int i = 0; i < json_evetns_type_1.length(); i++) {
messageIdsType1.add(json_evetns_type_1.getJSONObject(i).getString("id"));
}
for (int i = 0; i < json_evetns_type_2.length(); i++) {
messageIdsType2.add(json_evetns_type_2.getJSONObject(i).getString("id"));
}
new AsyncStoreOldMessagesLocally(context, messagesToStore, new Callback() {
#Override
public void onCallbackCompleted() {
new AsyncUpdateMessageStatus(context, messageIdsType1, 1, new Callback() {
#Override
public void onCallbackCompleted() {
new AsyncUpdateMessageStatus(context, messageIdsType2, 2, new Callback() {
#Override
public void onCallbackCompleted() {
new AsyncUpdateMessageStatusList(context, messageArrayListNotSync, new Callback() {
#Override
public void onCallbackCompleted() {
sendCallBack();
}
}).execute();
}
}).execute();
}
}).execute();
}
}).execute();
} catch (Exception e) {
System.out.println("Exception occurred while getting data from data JSONObject received from service: " + e.toString());
e.printStackTrace();
sendCallBack();
}
}
}).execute();
} catch (Exception e) {
System.out.println("Exception occurred while parsing data JSONObject received from service: " + e.toString());
e.printStackTrace();
sendCallBack();
}
}
}).execute();
} else {
sendCallBack();
}
} catch (Exception e) {
System.out.println("Exception occurred while parsing webservice result: " + e.toString());
sendCallBack();
}
}
});
} catch (Exception e) {
System.out.println("exception occurred while parsing messaging lists: " + e.toString());
sendCallBack();
}
return null;
}
private void sendCallBack() {
if (callback != null) {
callback.onSuccess();
}
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}
"WorkManager startWork() never calls when constraints are met"
"It calls only one time at the start where I register it."
The ListenableWorker can be recreated in some situations, a new instance of ListenableWorker with the same first ListenableWorker.id. But for it be recreated, it can't be finished. Here are some situations:
Some of the constraints do not matches anymore and it matches again
System was rebooted
Now here are some situations where it will be finished:
Some Exception was raised without treatment
completer.set(Result.success()) was called
completer.set(Result.failure()) was called
There are some situations in your code that the worker can be finished.
There are lots of calls to AsyncSyncData.sendCallBack, which can causes the call of completer.set(Result.success()) on the ListenableWorker instance. If it happens the ListenableWorker completes the job, so it will not be recreated anymore.
"I want to WorkManager startWork() to be called every time the user connects to the internet through wifi or 3g/4g/5g."
The WorkManager alone won't create a new instance of the ListenableWork every time the user connects to Internet. The WorkManager is a API to schedule tasks, and the constraints defined in the ListenableWork are used to not start it while them are not matched, after the ListenableWork finishes, how was discussed above, this task is finished, so no more to do.
If you want to listen to some connectivity changes, you should use ConnectivityManager.registerNetworkCallback and then when the user connects to, you do what you want. Here are some examples that could help you
to do it.
I am trying to implement pagination in recyclerview to load more chat messages when the user scrolls to top , this is achieved by sending the last message time i.e coversations[0] time to the API , but when the new list is added the old List gets repeated many times . I think this is because i am not updating the time properly , What is the correct way to achieve this?
This is the code i am using, first time i am setting the flag to false and time as empty.
getConvoData(k, " ", "", false);
private String last_msg_time = " ";
private Boolean flag = false;
rv_convo.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!recyclerView.canScrollVertically(-1)) {
if (conversations != null) {
String time = last_msg_time;
getConvoData(k, " ", time, true);
}
}
}
});
this is the method for fetching conversation Data
private void getConvoData(final String k, final String new_message, final String last_time, final boolean flag) {
final String token1 = Global.shared().tb_token;
final String url = "https://app.aer.media/v2/message_router/_getChat";
final JSONObject jsonBody = new JSONObject();
final ProgressDialog progressDialog = new ProgressDialog(this);
final String mRequestBody = jsonBody.toString();
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new com.android.volley.Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jObj = new JSONObject(response);
final JSONObject data = jObj.getJSONObject("data");
conversations = data.getJSONArray("conversation");
JSONObject for_chat = data.getJSONObject("for_chat");
JSONArray jsonArr_chat = new JSONArray();
jsonArr_chat.put(for_chat);
params = (RelativeLayout.LayoutParams) rv_convo.getLayoutParams();
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
if (!flag) {
convobeans = gson.fromJson(conversations.toString(), convType);
last_msg_time = conversations.getJSONObject(0).getString("time");
Log.d("OldList", convobeans.toString());
adapter = new ChatDetailsAdapter(forChatBeen, convobeans, ChatDetailsActivity.this, forChatBeansList, image, name, initials, new_message, bitmap);
// Collections.reverse(convobeans);
rv_convo.setAdapter(adapter);
rv_convo.smoothScrollToPosition( rv_convo.getAdapter().getItemCount() - 1);
adapter.notifyDataSetChanged();
rv_convo.setNestedScrollingEnabled(true);
} else {
newConvo = gson.fromJson(conversations.toString(), convType);
last_msg_time = conversations.getJSONObject(0).getString("time");
if (newConvo != null && newConvo.size() > 0) {
Log.d("newList", newConvo.toString());
convobeans.addAll(0, newConvo);
adapter.notifyItemChanged(0, newConvo.size());
}
}
}
}
}
Depending on the flag I am updating the list and updating the time as well but the list gets repeated in the RecyclerView due to the previous time being passed , how do I update the time optimally and fetch the new list each time?
This code is used to fetch the data when the user scroll down in a recylerview. Just analyze this code you will get the basic idea.
rvCategory.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) {
visibleItemCount = mLinearLayoutManager.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
pastVisiblesItems = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
loading = false;
fetchData();
}
}
}
}
});
Function FetchData()
private void fetchData() {
String url = EndPoints.location + "getMobileData.php?lastData=" + lastData;
JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
lastData = response.getString("last");
JSONArray jArray = response.getJSONArray("response");
if (jArray.length() == 0) {
//Empty condition
} else {
for (int i = 0; i < jArray.length(); i++) {
//Append the chat with the Dataobject of your modelAnd swap the recylerview view with new data
//Example
}
adapter.swap(rvHomeModel.createHomeList(DataPathsHome, true));
}
} catch (JSONException e) {
e.printStackTrace();
}
loading = true;
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
loading = true;
Toast.makeText(CategoryView.this, "No internet connection", Toast.LENGTH_LONG).show();
}
});
// Add a request (in this example, called stringRequest) to your RequestQueue.
MySingleton.getInstance(this).addToRequestQueue(jsObjRequest);
}
Create a function called swap in your adapter class that accept the new dataset
public void swap(List<rvHomeModel> list) {
//Check your previouse dataset used in adapter is empty or not
if (rvHomeModels!= null) {
rvHomeModels.clear();
rvHomeModels.addAll(list);
} else {
rvHomeModels = list;
}
notifyDataSetChanged();
}
At server
1. Get the previous value
2. Do the database operation and get the chats id < of previous
2. Create a JSON Object contain
{
last:last_chat_id,
response:{
//Your chat
}
}
This is not a perfect solution for this question. But you will get the basic idea about what you are looking for.
I am using retrofit to access API with counter value, i.e. when I
getting first time response calling retrofit method again and again
till the last counter value.I also do after getting response download
image using AsyncTask.
When i first time calling the retrofit method, Showing Progress
Dialog. I want to dismiss dialog when last image downloaded.
visibleProgressBar(getString(R.string.fetch_data_msg));
getMyOxygenInitialSync();
public void getMyOxygenInitialSync() {
if (new CheckConnection(context).isConnectedToInternet()) {
UserPreferences preferences = UserPreferences.getUserPreferences(context);
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
try {
JsonObject params = new JsonObject();
params.addProperty("my_oxygen_user_id", "984");
params.addProperty("action", "fullSync");
params.addProperty("page", String.valueOf(page));
params.addProperty("syncDate", "");
// RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(new JSONObject(params)).toString());
Call<MyOxygenSyncResponseMain> call = apiService.getMyOxygenSycList(params);
call.enqueue(new Callback<MyOxygenSyncResponseMain>() {
#Override
public void onResponse(Call<MyOxygenSyncResponseMain> call, retrofit2.Response<MyOxygenSyncResponseMain> response) {
invisibleProgressDialog();
try {
if (response != null) {
/* MyOxygenSyncResponseMain myOxygenSyncResponseMain = new MyOxygenSyncResponseMain();
myOxygenSyncResponseMain = ((MyOxygenSyncResponseMain)response);*/
totalPage = response.body().getTotalPage();
page++;
if (response.body().getImageDetail() != null && response.body().getImageDetail().size() > 0) {
for (int i = 0; i < response.body().getImageDetail().size(); i++) {
MyOxygen myOxygen = new MyOxygen();
myOxygen.setImageId(response.body().getImageDetail().get(i).getMy_oxygen_image_id());
myOxygen.setImageName(response.body().getImageDetail().get(i).getMy_oxygen_image_name());
myOxygen.setImagePhysicalPath(response.body().getImageDetail().get(i).getMy_oxygen_image_url());
myOxygen.setCategory(response.body().getImageDetail().get(i).getMy_oxygen_image_cat());
myOxygen.setSyncDate(response.body().getImageDetail().get(i).getSyncDate());
// myOxygen.setOrderId(myOxygenSyncResponseMain.getImageDetail().get(i).getOrde());
myOxygen.setIsUpdated(Integer.parseInt(response.body().getImageDetail().get(i).getMy_oxygen_is_deleted()) == 0 ? 1 : 0);
myOxygen.setIsDeleted(response.body().getImageDetail().get(i).getMy_oxygen_is_deleted());
myOxygenDBHelpher.saveMyOxygen(myOxygen);
downloadImage(myOxygen.getImageName(),myOxygen.getImagePhysicalPath(),myOxygen.getImageId());
}
for(page=page;page<=totalPage+1;page++){
getMyOxygenInitialSync();
}
/* if( page== totalPage){
downloadImage();
}*/
}
Log.d("Resp ", response.raw().body().toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<MyOxygenSyncResponseMain> call, Throwable t) {
invisibleProgressDialog();
try {
Log.d("Error ", call.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
I have a fragment called MyRequestFragment, that contains a RecyclerView and binding the data to the RecyclerView using onBindViewHolder() using my adapter class.
Now every ViewHolder I have a button. and for every click on the button a POST request fired to the server and update a value. My problem is, if a success response comes, I need to hide the button on the particular ViewHolder.
The actual problem is the runOnUiThread() is not accept on the onBindViewHolder()
runOnUiThread(new Runnable() {
public void run() {
}
});
How do I call this inside the ViewHolder create / bind method.
My onBindViewHolder() full code is as bellow for reference.
#Override
public void onBindViewHolder(MyServiceViewHolder holder, int position) {
final MyServiceBean myServiceBean = serviceList.get(position);
holder.service_name.setText(myServiceBean.getService_name());
holder.last_updated.setText("Job Updated Date : " +myServiceBean.getDate(myServiceBean.getUpdated_at()));
holder.created_date.setText("Job Created Date : " + myServiceBean.getDate(myServiceBean.getCreated_at()));
holder.status.setText(myServiceBean.getStatus());
holder.service_note.setText("Service Note : " + myServiceBean.getService_note());
if (myServiceBean.getService_note().toString().isEmpty())
holder.service_note.setVisibility(View.GONE);
switch (myServiceBean.getStatus().toString().toLowerCase()) {
case "completed":
holder.status.setBackgroundColor(Color.GREEN);
break;
case "on progress":
holder.status.setBackgroundColor(Color.YELLOW);
break;
case "canceled":
holder.status.setBackgroundColor(Color.RED);
break;
case "rejected":
holder.status.setBackgroundColor(Color.RED);
break;
case "accept":
holder.status.setBackgroundColor(Color.BLUE);
break;
default:
holder.status.setBackgroundColor(Color.GRAY);
break;
}
if(myServiceBean.getEst_amount() != null) {
holder.estimation_region.setVisibility(View.VISIBLE);
holder.est_status.setText("Estimation is Available");
holder.btn_approve.setVisibility(View.VISIBLE);
holder.est_amount.setText("Estimation Amount: " + myServiceBean.getEst_amount());
if(myServiceBean.getEst_note() != null)
holder.est_note.setText("Estimation Note: " + myServiceBean.getEst_note());
if(myServiceBean.getEst_presented_by() != null)
holder.est_presented_by.setText("Estimation Prepared By: " + myServiceBean.getEst_presented_by());
if(myServiceBean.getEst_approved_by_customer() == "true"){
holder.btn_approve.setVisibility(View.GONE);
holder.est_status.setText("Estimation Approved on : " + myServiceBean.getEst_approved_date());
}else{
holder.btn_approve.setVisibility(View.VISIBLE);
}
}else{
holder.estimation_region.setVisibility(View.GONE);
holder.est_status.setText("Estimation on Process");
holder.btn_approve.setVisibility(View.GONE);
}
holder.btn_approve.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
updateRequest();
}
});
}
private void updateRequest() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("est_approved_by_customer", true);
jsonObject.put("est_approved_date", "2017-10-30");
} catch (JSONException e) {
e.printStackTrace();
}
//progress_dialog.show();
OkHttpClient client = new OkHttpClient();
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
okhttp3.RequestBody body = RequestBody.create(JSON, jsonObject.toString());
okhttp3.Request request = new Request.Builder()
.url(ApplicationContants.BASE_URL + ApplicationContants.MY_SERVICE_APPROVE_URL)
.post(body)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, final IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
String responseString = response.body().string();
JSONObject jsonObject = new JSONObject(responseString);
Gson gson = new Gson();
final MyServiceBean myServiceBean = gson.fromJson(jsonObject.toString(), MyServiceBean.class);
runOnUiThread(new Runnable() {
public void run() {
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
runOnUiThread() is a method of Activity.
Either call it on an Activity instance (if you have access to one), or use a Handler to post your Runnable to the message queue of the main thread:
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
// do something
}
});
You should get your activity before calling runOnUiThread:
getActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
/*your code*/
}
});
Hello I am trying to draw polygones on a google map after I get the data for them from an HTTP call. I always get the same error:
FATAL EXCEPTION: OkHttp Dispatcher
Process: com.example.rtuya.secmerev2, PID: 1011
java.lang.IllegalStateException: Not on the main thread
Here is how I do my HTTP call and then how I try to draw my areas:
private void getZones() throws JSONException {
Request request = new Request.Builder().url(getString(R.string.main_url) + "/api/getZones")
.headers(buildStandardHeaders(Stormpath.accessToken()))
.get()
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override public
void onFailure(Call call, IOException e) {
Log.d("DEBUG", "ERROR");
}
#Override public void onResponse(Call call, Response response)throws IOException {
try {
JSONArray responseArray = new JSONArray(response.body().string());
zones = new ArrayList<ZoneData>();
for (int i=0; i < responseArray.length(); i++) {
db.addZone(new ZoneData(responseArray.getJSONObject(i)));
zones.add(new ZoneData(responseArray.getJSONObject(i)));
}
isTrackingServiceRunning = startService(new Intent(ActivityMain.this, ServiceTracking.class));
bindService(new Intent(ActivityMain.this, ServiceTracking.class), trackerServiceConnection, Context.BIND_AUTO_CREATE);
drawAreasOnDashboard();
} catch (JSONException e) {
e.printStackTrace();
};
}
});
}
Below is how I try to draw my Areas and the error always happens on the line that contains areaMap.drawPolygones():
public void drawAreas() {
int polygoneFillingIndex = 1;
if(ActivityMain.zones != null) {
for (ZoneData zone : ActivityMain.zones) {
int color;
if ((polygoneFillingIndex % 2) == 0) {
color = R.color.polygoneFillingBlue;
} else {
color = R.color.polygoneFilingGreen;
}
areasMap.addPolygon(new PolygonOptions()
.add(zone.getP1(), zone.getP2(), zone.getP3(), zone.getP4())
.strokeColor(ResourcesCompat.getColor(getResources(), R.color.polygoneStroke, null))
.fillColor(ResourcesCompat.getColor(getResources(), color, null))
.zIndex(Float.valueOf(zone.getPosititionInArray()))
.clickable(true));
polygoneFillingIndex++;
}
}
}
That error logs says exactly where you are wrong. Android does not allow you to run http requests on the main thread so that it won't be blocked by it.
You have to encapsulate those http requests in AsyncTasks, you can find tons of examples here on SO or anywhere in the web