I am working on a task that calls my AsyncTask , once the async task is executed , I wait for 20 seconds to get the data from server , if it is still loading I am cancelling it (handling timeout)
public void handleServerTimeOut() {
getStore = new GetStore();
getStore.execute();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (getStore != null && getStore.getStatus() != AsyncTask.Status.FINISHED) {
boolean result = getStore.cancel(true);
Log.e(TAG, " handleServerTimeOut() reached 20 seconds");
Log.e(TAG, "" + result);
}
}
}, 20000);
}
AsyncTask
class GetStore extends AsyncTask<Void, Void, String> {
String status, message;
JSONArray jsonArray;
String buildingIdGuest, buildingIdUser, finalBuildingID;
#Override
protected void onPreExecute() {
super.onPreExecute();
if (isCancelled()) {
return;
} else {
buildingIdUser = utilClass.getSharePerefernce(getActivity(), KEY_BUILDING_ID_USER, "");
buildingIdGuest = utilClass.getSharePerefernce(getActivity(), KEY_BUILDING_ID_GUEST, "");
if (buildingIdUser.equals("0") || buildingIdUser.equals("")) {
finalBuildingID = buildingIdGuest;
} else {
finalBuildingID = buildingIdUser;
}
error_flag = 0;
gridView.setVisibility(View.VISIBLE);
error_layout.setVisibility(View.INVISIBLE);
img_no_internet.setVisibility(View.INVISIBLE);
img_no_results.setVisibility(View.INVISIBLE);
img_server_error.setVisibility(View.INVISIBLE);
progressDialog.setMessage("Getting nearby stores ...");
progressDialog.setIndeterminate(true);
progressDialog.setCancelable(true);
progressDialog.show();
}
}
#Override
protected String doInBackground(Void... params) {
if (NetworkCheck.isNetworkAvailable(getActivity())) {
try {
jsonObj = userFunction.getStores(OS, MAKE, MODEL, finalBuildingID);
Log.e(TAG, jsonObj.toString());
status = jsonObj.getString("status");
message = jsonObj.getString("message");
if (status.equalsIgnoreCase("success")) {
jsonArray = jsonObj.getJSONArray("response");
for (int i = 0; i < jsonArray.length(); i++) {
gridModel = new GridModel();
gridModel.setId(jsonArray.getJSONObject(i).getString("id"));
gridModel.setStore_name(jsonArray.getJSONObject(i).getString("name"));
gridModel.setImage_name(jsonArray.getJSONObject(i).getString("image_name"));
gridListData.add(gridModel);
}
Log.e(TAG, "****** = " + gridListData.toString());
} else if (status.equalsIgnoreCase("invalid parameters")) {
error_flag = 2;
Log.e(TAG, "invalid parameters");
} else if (status.equalsIgnoreCase("no stores")) {
error_flag = 3;
Log.e(TAG, "No Data");
}
Log.e(TAG, "****** status " + status);
return String.valueOf(jsonObj);
} catch (Exception e) {
error_flag = 1; // Handling server timeout.
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
progressDialog.dismiss();
return;
}
});
Log.e(TAG, e.toString());
}
} else {
Log.e(TAG, "Network Error");
error_flag = 1;
}
return null;
}
#Override
protected void onPostExecute(String response) {
super.onPostExecute(response);
Log.e(TAG, " **** error **** " + error_flag);
if (error_flag == 1) {
gridView.setVisibility(View.GONE);
error_layout.setVisibility(View.VISIBLE);
img_no_internet.setVisibility(View.VISIBLE);
} else if (error_flag == 2) {
gridView.setVisibility(View.GONE);
error_layout.setVisibility(View.VISIBLE);
img_server_error.setVisibility(View.VISIBLE);
txtError.setVisibility(View.VISIBLE);
txtError.setText(message);
} else if (error_flag == 3) {
gridView.setVisibility(View.GONE);
error_layout.setVisibility(View.VISIBLE);
img_no_results.setVisibility(View.VISIBLE);
}
gridAdapter = new GridAdapter(getActivity(), gridListData);
gridView.setAdapter(gridAdapter);
if ((progressDialog != null) && progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
}
I also wanted to cancel my AsyncTask when the user cancels the ProgressDialog
You are checking isCancelled() only once in your AsyncTask - in the onPreExecute() method. At the time you call cancel() on your task instance, this check has already been evaluated and this is why the async task is still completing and updating the UI.
To deal with the issue, I suggest you include more checks for cancellation, using the isCancelled() method. One obvious place to include such a check is in the onPostExecute() method, right before you update the UI. You could also include a check before making the actual request to the server, after receiving the response, etc.
Related
I have three fragments in a FragmentPagerAdapter, and each of them would fetch a list of frames/data from a server using Volley. This data would later be used to update the Fragment's RecyclerView Adapter as a Cursor.
VolleyRestClientUtils.get(getString(R.string.PATH_SHOP), LOG_TAG, params, true, false, new JsonHttpResponseHandler() {
public void onSuccess(JSONObject response) {
Log.d(LOG_TAG, "request Response : " + response.toString());
try {
String status = response.getString("status");
if (RestClientUtils.STATUS_OK.equals(status)) {
final JSONArray frames = response.getJSONArray("items");
Log.d(LOG_TAG, "request Response : " + frames.length());
if (frames != null && frames.length() > 0) {
new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... voids) {
List<ContentValues> listShopFrame = ShopFrame.fromJSONArray(frames, sort);
if (listShopFrame.size() > 0 && isActivityActive()) {
ContentResolver cr = getActivity().getContentResolver();
if (!isRequestMore) {
cr.delete(ShopFrame.CONTENT_URI, ShopFrame.COLUMN_CATEGORY + "=?",
new String[]{sort});
paramSkip = frames.length();
} else {
paramSkip += frames.length();
}
ArrayList<ContentProviderOperation> operations = new ArrayList<>();
String log = listShopFrame.size()+" ";
for (int i = 0; i < listShopFrame.size(); i++) {
operations.add(ContentProviderOperation
.newInsert(ShopFrame.CONTENT_URI)
.withValues(listShopFrame.get(i))
.build());
log += listShopFrame.get(i).toString()+"\n";
}
Log.i("loader_callback_"+sort, log);
//cr.applyBatch(ShopFrame.CONTENT_AUTHORITY, operations);
ContentValues[] opsAsArray = new ContentValues[listShopFrame.size()];
listShopFrame.toArray(opsAsArray);
cr.bulkInsert(ShopFrame.CONTENT_URI, opsAsArray);
//return true;
}
return true;
}
#Override
protected void onPostExecute(Boolean result) {
dataRefreshed = true;
Log.i("loader_callback_"+sort, "response post execute");
if (result) {
loadSucceed();
PicMixApp.getInstance().setRefreshed(ShopFrameFragment.this.getClass().getName());
} else {
loadFailed(null);
}
}
}.execute();
} else {
//TODO
//Handle error
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
} else if (VolleyRestClientUtils.STATUS_RESOURCE_NOT_FOUND.equals(status)) {
hasMore = false;
loadSucceed();
} else {
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
} catch (Exception e) {
Log.e(LOG_TAG, "Exception:" + e.getMessage());
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
}
#Override
public void onJSONError(String responseString) {
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
#Override
public void onFailure(String errMessage, int statusCode, Map<String, String> headers, byte[] responseBytes) {
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
});
Whereas loadSucceed() has this following code:
if (this.recyclerView != null) {
final RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter != null) {
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onChanged() {
super.onChanged();
Log.i(DefaultRecyclerFragment.this.getClass().getName(), "onChanged");
adapter.unregisterAdapterDataObserver(this);
isLoading = false;
}
public void onItemRangeRemoved(int positionStart, int itemCount) {
Log.i(DefaultRecyclerFragment.this.getClass().getName(), "onItemRangeRemoved:" + positionStart + ", itemcount:" + itemCount);
adapter.unregisterAdapterDataObserver(this);
isLoading = false;
}
});
if (adapter instanceof CursorRecyclerAdapter && loadMoreView != null) {
((CursorRecyclerAdapter) adapter).removeFooter(loadMoreView);
}
}
}
I've put the code to initialize the loader in the onResume() method of each fragment:
int id = 100+Integer.valueOf(sort);
Loader l = getLoaderManager().getLoader(id);
Log.i("loader_callback_"+sort, "success loading volley "+l);
if(l == null) {
getLoaderManager().restartLoader(id, null, this);
}
My problem is that there seems to be some sort of race condition happening, that the currently viewed fragment's adapter seem to be updated twice, and sometimes thrice. The initial cursor fetched by the Fragment's Loader has 10 rows, sure, but after the update, most of the time it only has 7 of the 21 rows expected to be put in.
I thought all the ContentResolvers' operations are synchronous (can only be done one after another, not simultaneously). What's going on here?
EDIT: Should I just put the loader init code in the loadSuccess() callback?
EDIT2: I should note that these Fragments extend android.support.v4.app.Fragment, and I'm using the version 27.1.1 of the Support Library.
I have a chat application. I have to send a message only once whereas I am using while(true). Because of this loop message is sending again and again. How can I break the while loop when the message is sent only once? That message should not be sent again and again.
Here is my code:
while (true) {
String[] jobsNumbers = numbers.toArray(new String[numbers.size()]);
new SendMessage().execute(jobsNumbers);
}
and here is my sendMessage Asynctask:
private class sendMessage extends AsyncTask<String, Integer, Integer> {
#Override
protected Integer doInBackground(String[] toNumbers) {
totalNumbers = toNumbers.length;
for (i = 0; i < toNumbers.length; i++) {
toNumber = toNumbers[i];
if (countMessagePerDay() >= Integer.parseInt(MaxNoOfMessagePerDay)) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
sendSMS(toNumber);
this.publishProgress(1);
}
if (randomNo != 0 && isSent) {
databaseHelperClass.updateJobMessageStatus(JobId);
}
}
return toNumbers.length;
}
#Override
protected void onProgressUpdate(Integer... values) {
Toast.makeText(getApplicationContext(), i + "/" + totalNumbers + " :: to " + toNumber, Toast.LENGTH_SHORT).show();
super.onProgressUpdate(values);
}
#Override
protected void onCancelled(Integer integer) {
super.onCancelled(integer);
}
#Override
protected void onPostExecute(Integer integer) {
Toast.makeText(getApplicationContext(), "Message sent!", Toast.LENGTH_LONG).show();
super.onPostExecute(integer);
}
}
You can use break; for this,like:
while (true) {
String[] jobsNumbers = numbers.toArray(new String[numbers.size()]);
new SendMessage().execute(jobsNumbers);
Boolean destroy= true;
if(destroy == true){
break;
}
}
int i = 0;
while (i<1)
{
String[] jobsNumbers = numbers.toArray(new String[numbers.size()]);
new SendMessage().execute(jobsNumbers);
i++;
}
I have same stock item , I want to send local database to ApiService, But when I send also I want to update ProgressBar message. I tried the code below but it just shows when all proccessing is finishing.
ProgressDialog progress= new ProgressDialog(this);
progress.setTitle(getResources().getString(R.string.progress_exporting));
progress.setMessage("0/0");
when click button I call below method
public void Export() {
runOnUiThread(new Runnable() {
#Override
public void run() {
findViewById(R.id.btnExportOnlineWithStocktaking).setEnabled(false);
progress.show();
}
});
UpdateUI(send, total);
try {
switch (_stocktakingType) {
case Division: {
switch (_onlineExportType) {
case Item: {
isExport = ExportDivisionStocktakingItems(stocktakingId);
}
break;
}
} catch (Exception ex) {
}
}
// ExportDivisionStocktaking method
public boolean ExportCustomStocktakingItems(int stocktakingId) {
result = Boolean.parseBoolean(SendCustomStocktakingItems(stocktakingId,countResults).responseString);
}
My call back method
public ResponseModel SendCustomStocktakingItems(int selectedDivision, List<ExtensionServiceStocktakingItem> countResults) throws ExecutionException, InterruptedException {
return new SendCustomStocktakingItemsService(flag -> true).execute(String.valueOf(selectedDivision), countResults.toString()).get();
}
//AsyncTask method
public class SendDivisionStocktakingItemsService extends AsyncTask<String, Void, ResponseModel> {
public AsyncResponseSendDivisionStocktakingItems delegate = null;
public SendDivisionStocktakingItemsService(AsyncResponseSendDivisionStocktakingItems delegate) {
this.delegate = delegate;
}
#Override
protected ResponseModel doInBackground(String... parameters) {
RequestHandler requestHandler = new RequestHandler();
JSONObject params = new JSONObject();
try {
params.put("stocktakingItems", parameters[1]);
} catch (JSONException e) {
e.printStackTrace();
}
ResponseModel responseModel = requestHandler.getRequestPostString(UHFApplication.getInstance().apiUrl
+ "/api/MobileService/SendDivisionStocktakingItemsPost?stocktakingID="
+ parameters[0],
parameters[1]);
return responseModel;
}
#Override
protected void onPreExecute() {
UpdateUI(send,total);
super.onPreExecute();
}
#Override
protected void onPostExecute(ResponseModel responseModel) {
super.onPostExecute(responseModel);
if (HttpURLConnection.HTTP_OK == responseModel.httpStatus) {
delegate.processFinish(true);
} else {
delegate.processFinish(false);
}
}
}
//UICalled method
public void UpdateUI(int send, int total) {
runOnUiThread(() -> {
progress.setMessage(send + "/" + total);
Log.d("Send Data : ", send + "/" + total);
if (send == total) {
progress.dismiss();
Toast.makeText(getApplicationContext(), "Succsess", Toast.LENGTH_SHORT).show();
}
});
}
//Update
//Ok I have a simle example how can I use. Below code when I click button I wan to open progress firstly and after that for loop is working and update progres message. I try it but not working.
Firstly For loop is working and after that progres opened.
public void ExportTry(){
UpdateUI(send,total);
runOnUiThread(new Runnable() {
#Override
public void run() {
btnExport.setEnabled(false);
progress.show();
}
});
for(int i=0;i<1000000;i++){
UpdateUI(i,1000000);
}
}
You are missing the part of AsyncTask that will allow you to show progress messages while doInBackground is running. Take a look at onProgressUpdate and publishProgress on the same page.
publishProgress
void publishProgress (Progress... values)
This method can be invoked from doInBackground(Params...) to publish updates on the UI thread while the background computation is still running. Each call to this method will trigger the execution of onProgressUpdate(Progress...) on the UI thread. onProgressUpdate(Progress...) will not be called if the task has been canceled.
I start my progress dialog in oncreate method of fragment before is initiate my web request call. In the web request call, if I fetch the response and if its success I call the notifydatasetchanged method to refresh the adapter . But the dialog gets dismissed lot before the view is updated . Please help .
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pd = ProgressDialog.show(getActivity(), "Loading...", "Please Wait...");
getProducts(highPrice, lowPrice, isLowtoHigh);
}
private void getProducts(String highPrice,String lowPrice,String isLowtoHigh) {
// loadingDialog.loading();
APIRequst.getProductsCategory(getActivity().getApplicationContext(), isLowtoHigh, lowPrice, highPrice, new APIRequestListner() {
#Override
public void onSuccess(String response) {
if (response == null || response.isEmpty()) {
Log.e("orderhistory", "success but empty");
} else {
Log.e("products", response);
try {
JSONObject mainObj = new JSONObject(response);
boolean result = mainObj.has("is_success") && mainObj.getBoolean("is_success");
String resultMessage = mainObj.getString("message");
if (resultMessage.equalsIgnoreCase("Success")) {
if (result) {
productItems.clear();
adptProductItems.clear();
JSONArray jsonOrderList = mainObj.has("categories") ? mainObj.getJSONArray("categories") : null;
if (jsonOrderList != null) {
for (int i = 0; i < jsonOrderList.length(); i++) {
JSONObject jsonObj = jsonOrderList.getJSONObject(i);
ProductListItem newItem = (new Gson()).fromJson(jsonObj.toString(), ProductListItem.class);
productItems.add(newItem);
}
adptProductItems.notifyDataSetChanged();
pd.dismiss();
}
}
} else {
if (resultMessage.equalsIgnoreCase("No Value")) {
if (pd.isShowing())
pd.dismiss();
productItems.clear();
adptProductItems.notifyDataSetChanged();
Toast.makeText(getActivity(), "Sorry no prducts to display", Toast.LENGTH_SHORT).show();
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
// adapter.notifyDataSetChanged();
}
#Override
public void onFailure() {
if (pd.isShowing())
pd.dismiss();
// loadingDialog.dismissDialog();
}
});
}
try to move " pd.dismiss();" below onFailure()
#Override
public void onFailure() {
if (pd.isShowing())
pd.dismiss();
// loadingDialog.dismissDialog();
}
pd.dismiss();
and
adptProductItems.notifyDataSetChanged();
//pd.dismiss(); remove fromhere
may it will help as I did in my case..
I'm writting an application which use Android phone like client and connect to java server via TCP Socket.
My problem is: I used a service to send/receiver message to java server with asynctask to keep connection, but when i need to send request and wait for respone from server, i use another asynctask to do this, but the second asynctask can not run.
Here my code
Asynctask in Server (Connect - Keep receiver message)
public class connectTask extends AsyncTask<String,String,TCPClient> {
#Override
protected TCPClient doInBackground(String... message) {
Log.d(TAG1,"connectTask - in asycn task- 3");
//we create a TCPClient object and
mmTcpClient = new TCPClient(new TCPClient.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
//this method calls the onProgressUpdate
Log.d(TAG1,"connectTask - in asycn task- 4");
publishProgress(message);
}
});
if (LocalData.isConnectsuccess == false)
{
try {
Log.d(TAG1,"connectTask - in asycn task- 5");
mmTcpClient.run("172.16.10.37", 44444);
Log.d(TAG1,"Services started - in asycn task- 6");
}
catch (Exception e)
{
Log.e(TAG1,""+e);
}
}
return null;
}
#Override
protected void onProgressUpdate(final String... values) {
super.onProgressUpdate(values);
Log.e(TAG1,"Onprogressupdate" + values[0]);
LocalData.strreceiver = values[0];
Intent intt = new Intent(ConnectService.this, Customdialog.class);
intt.putExtra("mess", LocalData.strreceiver);
intt.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intt);
}
}
And the second asynctask which use for Login Activity
class ASlogin extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(SigninActivity.this);
pDialog.setMessage("Logging in");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
Log.d(Tag2, "pdialog show");
}
/**
* getting All products from url
* */
protected String doInBackground(String... message) {
// Building Parameters
Log.d(Tag2, "Doinbackground");
try {
if (LocalData.isConnectsuccess == true) {
Log.d(Tag2, "Send-1");
JSONObject jslogin = new JSONObject();
try {
jslogin.put("tag","login");
jslogin.put("email", edtEmailSignIn.getText().toString());
jslogin.put("password", edtPasswordSignIn.getText()
.toString());
Log.d(Tag2, "Put Json-2");
} catch (JSONException e) {
Log.e(Tag2, "JSON failed" + e);
}
mTcpClient.sendMessage(jslogin.toString());
Log.d(Tag2, "JsonString: " + jslogin.toString());
}
else {
Log.e(Tag2, "Connect not success" + LocalData.isConnectsuccess);
}
} catch (Exception e) {
Log.e(Tag2, "Fail parse Json" + e);
}
return null;
}
#Override
protected void onProgressUpdate(String... message) {
super.onProgressUpdate(message);
pDialog.dismiss();
OJResponsive strreturn = new OJResponsive();
try{
strreturn = JSonparse.getrespon(LocalData.strreceiver);
}
catch (Exception e)
{
alertmess("Login fail" + e);
Log.e(Tag2,"Json parse failed"+e);
}
if (strreturn.getResult()=="success")
{
Toast.makeText(SigninActivity.this, "Login success", Toast.LENGTH_SHORT).show();
Intent inhctr = new Intent(SigninActivity.this,HomeControlActivity.class);
startActivity(inhctr);
finish();
}
else alertmess("Login fail");
Log.e(Tag2,"Login fail"+e);
}
}
the Second asycntask just run at onPreExecute() and stop at showprocessdialog.
So any help for me ? or any better solutions in this case ?
Thanks you.
Try to use
AsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
instead
AsyncTask execution is handled differently in different versions of android.
Have a look a this answer: fetching data in parallel