The doInBackground() method in the AsyncTask gets executed only sometimes - android

I'm using the AsyncTask to render a graph from a list. Sometimes it works alright and the graph is rendered. However in some cases the graph is not being rendered, and the reason for this is that the doInBackground() method is not being triggered. Here's the code of the AsyncTask.
private class HistoryPlotAsync extends AsyncTask<Void, Void, Void> {
boolean isAnalysisMode = false;
List<Byte> listECG;
List<Byte> listHS;
HistoryPlotAsync(List<Byte> listECG, List<Byte> listHS, List<Byte> listMur, boolean isAnalysisMode) {
this.listECG = listECG;
this.listHS = listHS;
this.isAnalysisMode = isAnalysisMode;
HistoryPlot.this.multiHsRenderer.setPanEnabled(false, false);
HistoryPlot.this.multiEcgRenderer.setPanEnabled(false, false);
}
protected Void doInBackground(Void... params) {
if (HistoryPlot.this.pcgPlayer != null) {
HistoryPlot.this.pcgPlayer.start();
} else {
try {
HistoryPlot.this.startSound();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
int i = 0;
int loopCounter = 0;
if (this.listHS != null && this.listHS.size() > 0) {
loopCounter = this.listHS.size();
}
double xValue = 0.0d;
double xValueEcg = 0.0d;
do {
xValueEcg += 0.0015625d;
if (this.listHS != null && i % 2 == 0) {
xValue += 0.0032012d;
hsSeries.add(xValue,listHS.get((i/2)));
}
try {
if (this.listECG != null && i < this.listECG.size()) {
ecgSeries.add(xValueEcg, listECG.get(i));
}
} catch (Exception e) {
try {
Log.d("HistoryPlot -> ", "doInBackground: Exception " + e.getMessage());
} catch (Exception e2) {
Log.e("HistoryPlot -> ", "Error in Analysis mode point conversion");
}
}
if (i > HistoryPlot.this.refRange && i % 94 == 0) {
HistoryPlot.this.xMin = HistoryPlot.this.xMin + 0.15d;
HistoryPlot.this.xMax = HistoryPlot.this.xMax + 0.15d;
HistoryPlot.this.multiHsRenderer.setXAxisMin(HistoryPlot.this.xMin);
HistoryPlot.this.multiHsRenderer.setXAxisMax(HistoryPlot.this.xMax);
HistoryPlot.this.multiEcgRenderer.setXAxisMin(HistoryPlot.this.xMin);
HistoryPlot.this.multiEcgRenderer.setXAxisMax(HistoryPlot.this.xMax);
}
if (i % 16 == 0) {
publishProgress(new Void[0]);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
i++;
if (i >= loopCounter) {
break;
}
} while (!HistoryPlot.this.taskHistoryPlot.isCancelled());
return null;
}
protected void onProgressUpdate(Void... values) {
HistoryPlot.this.mHsChart.repaint();
HistoryPlot.this.mEcgChart.repaint();
}
protected void onPostExecute(Void result) {
HistoryPlot.this.stopSound();
HistoryPlot.this.enableReplay();
HistoryPlot.this.multiHsRenderer.setPanEnabled(true, true);
HistoryPlot.this.multiEcgRenderer.setPanEnabled(true, true);
}
}
The AsyncTask is executed via the following code in the onCreate() method of the Activity.
protected void onCreate(Bundle savedInstance) {
...
this.taskHistoryPlot = new HistoryPlotAsync((List) mapData.get("fileEcg"), (List) mapData.get("fileHs"), (List) mapData.get("fileMur"), isAnalysisMode);
this.taskHistoryPlot.execute();
}
Instead of using the execute() method, I have also tried using the executeOnExecutor(THREAD_POOL_EXECUTOR) method with the same results.

I got the issue resolved using the following code. The problem was that I had simply tried using the execute() method and the executeOnExecutor() method as is. You need to define an Executor and a Blocking Queue variables and define pool sizes for this to work.
static int mCorePoolSize = 60;
static int mMaximumPoolSize = 80;
static int mKeepAliveTime = 10;
static BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(mMaximumPoolSize);
static Executor mCustomThreadPoolExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.SECONDS, workQueue);
this.taskHistoryPlot = new HistoryPlotAsync((List) mapData.get("fileEcg"), (List) mapData.get("fileHs"), (List) mapData.get("fileMur"), isAnalysisMode);
this.taskHistoryPlot.executeOnExecutor(mCustomThreadPoolExecutor);

Asynctask methods will surely run, if you have have call to this class.
Please debug that, the conditions inside doInBackground(), for example
"if (HistoryPlot.this.pcgPlayer != null) "
because it may be possible that condition is not working well, or throws xception and led the function not being called.

If you want that code to execute multiple times, do not use the onCreate function. Create one that you can call everytime you want, onCreate() only runs once in the Activity lifecycle. That can be the cause.
You can call it from the onCreate as well, if you need ;)

Replace these two lines:
this.taskHistoryPlot = new HistoryPlotAsync((List) mapData.get("fileEcg"), (List) mapData.get("fileHs"), (List) mapData.get("fileMur"), isAnalysisMode);
this.taskHistoryPlot.execute();
with:
new HistoryPlotAsync((List) mapData.get("fileEcg"), (List) mapData.get("fileHs"), (List) mapData.get("fileMur"), isAnalysisMode).execute();
You dont need to pass context of activity here "this." will give the context of activity which you dont need it here so apply above mentioned changes.
OnCreate will run it one time only create another method in which you need to run your async task and call that new method wherever you want.You can also call that method in onCreate too.

Related

View not updated from callback method

I am fetching data from database. My views are updating only first time when I open the activity. Then when I again open the activity, my views are not updated.(Activity is starting again, hence onCreate() is called again & all settings are same). If I getText() after setting the text, I am getting proper values in log but nothing is displayed in view.
Here is my code snippet:
//My Call Back method
#Override
public void onRatingDataLoaded(ReviewJsonModel review) {
int ratingCount = 0, ownRating = 0;
String averageRating = "0";
if (review != null) {
ratingCount = review.review_count;
DecimalFormat format = new DecimalFormat("##.00");
averageRating = format.format(review.rating);
if (review.ownreviews != null) {
try {
ownRating = Integer.parseInt(review.ownreviews.rating);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
} else {
// do something
}
mTotalRatingCount.setText(String.format(getResources().getString(R.string.review_count), ratingCount));
mAverageRating.setText(averageRating);
// Log.v("LoggingReview", mTotalRatingCount.getText().toString().trim);
myRating.setRating(ownRating);
}
//Here I am setting listner as well as loading data.
public void loadReviewData(RatingDataLoadListener listener, int destinationId) {
if (mDataLoadListener == null)
mDataLoadListener = listener;
new getReviews().execute(destinationId);
}
Next is my asyntask
private class getReviews extends AsyncTask<Integer, Void, ReviewJsonModel> {
#Override
protected ReviewJsonModel doInBackground(Integer... integers) {
Cursor appCursor = mRatingApi.getDestinationReview(integers[0]);
ReviewJsonModel mReviewData = new ReviewJsonModel();
if (appCursor != null && appCursor.getCount() > 0) {
appCursor.moveToFirst();
while (!appCursor.isAfterLast()) {
mReviewData = getDocument(appCursor);
appCursor.moveToNext();
}
appCursor.close();
}
return mReviewData;
}
#Override
protected void onPostExecute(ReviewJsonModel result) {
super.onPostExecute(result);
if (mDataLoadListener != null)
mDataLoadListener.onRatingDataLoaded(result);
}
}
Can't find cause of problem. Any help is appreciated.
Looks like there is callback issue, can you please try below
public void loadReviewData(RatingDataLoadListener listener, int destinationId) {
mDataLoadListener = listener;
new getReviews().execute(destinationId);
}

Android Calling Multiple methods 1 by 1

I have this function where it checks what are the choices of the users made.
So for example
there is a 4 choices:
InfoOfUp
InfoOfArt
InfoOfParish
InfoOfAteneo.
So when the user selects InfoOfUp and InfoOfArt then on the next activity, i will click a button that contains function : selected() it will check the items that was choosen by the user. if the user choose item InfoOfUp it will run a specific function and if the user choose item InfoOfArt it will also run a specific function
The problem is every item has it's own function and every item have progress dialog that marks if the function is already done or not.
So the user choose 2 items there's an error because there's 2 function being called up at the same time;
I want the function to be call 1by1 where the function waits to the other function to finish.
To avoid confusion, i call methods as function.
public void selected() {
if (InfoOfUp.select == 1) {
if (ayala == 0) {
ayala();
ayala = 1;
} else if (ayala == 1) {
}
}
if (InfoOfArt.select == 1) {
if (art == 0) {
ArtInIsland();
art = 1;
} else if (art == 1) {
}
}
if (InfoOfParish.select == 1) {
if (parish == 0) {
parish();
parish = 1;
} else if (parish == 1) {
}
}
if (InfoOfAteneo.select == 1) {
if (ateneo == 0) {
ateneogallery();
ateneo = 1;
} else if (ateneo == 1) {
}
}
Additionally, if the function calls, it will run an asynctask to get data.
here is my asynctask:
public class connectAsyncTask3 extends AsyncTask<Void, Void, String> {
private ProgressDialog progressDialog;
private traffic traffic;
private boolean displayDestinationDetails;
String url;
boolean launchDestination;
connectAsyncTask3(String urlPass, traffic traffic, boolean displayDestinationDetails) {
this.url = urlPass;
this.traffic = traffic;
this.displayDestinationDetails = displayDestinationDetails;
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
try {
super.onPreExecute();
progressDialog = new ProgressDialog(traffic.this);
progressDialog.setMessage("Fetching route, Please wait...");
progressDialog.setIndeterminate(true);
progressDialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected String doInBackground(Void... params) {
JSONParser jParser = new JSONParser();
String json = jParser.getJSONFromUrl(url);
return json;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.hide();
if (result != null) {
Log.d("momo2", " : " + result);
traffic.drawPath(result);
speakOut();
}
if (displayDestinationDetails) {
Intent i = new Intent(traffic.this, poppers.class);
i.putExtra("currentMarker", traffic.markers.size());
traffic.startActivity(i);
}
}
}
Classic multi threading situation.
Create two threads, each one in the method related, start them and use
thread.join()
to begin second thread only after first finished.
great example here

Android: Main Thread blocked despite using AsyncTask

I have a Activity that contains over 100 complex views (with images, text views etc). Showing up these views is to hard to do it without a Thread that loads the views asynchronously. So I tried to do it with an AsyncTask. I am not sure whether this is the correct way because the "hard staff" is something that HAS to be done in the UI Thread.
Now I've got the problem that the UI freezes though I used the onProgressUpdate for adding the views in the to parent view. I thought that this would result in single loading views that appear successive in the parent view. But this is not the case.
doInBackground fires all publishProgress calls and after that the main thread is blocked (activity frozen, loadbar does not rotate anymore). Is there a way to achieve what I wanted to have? I looked for solutions but alway ended up with ideas of using AsyncTask and no one had to do view-stuff as "hard staff". I am not using "get" in the AsyncTask what seems to be a problem with AsyncTask.
Here is my code for this. If you need any further information please tell me!
Is there any other way to solute this problem? Is my AsyncTask implementation not correct? I am looking for a way to load these complex views asyncronous to the parent view without blocking the main thread.
Thanks in advance!
public class LoadKraut extends AsyncTask<Integer,Kraut,Void> {
private Context context;
private LinearLayout parent;
private HashMap<String,HeadlineAlphabet> headlinesAlphabet = new HashMap<String, HeadlineAlphabet>();
private long time;
private Integer kategorie;
private char letter = 'X';
private int counter = 0;
private ProgressDialog dialog;
public LoadKraut(Context context) {
/**
* Kategorie:
* 1 - A-Z
* 2 - Notiz
* 3 - Favorit
* 4 - Giftig
*/
Log.i("Kraut", "Start thread" + (System.currentTimeMillis()-time) + "ms");
this.context = context;
this.dialog = new ProgressDialog(context);
this.time = System.currentTimeMillis();
}
#Override
protected void onPreExecute() {
dialog.setMessage("Lade Kräuter. Dieser Vorgang kann einen Moment dauern.");
dialog.show();
}
#Override
protected Void doInBackground(Integer... params) {
this.kategorie = params[0];
//Create overview
try {
DatabaseHelper databaseHelper = new DatabaseHelper(context);
Dao<Kraut,Integer> dao = databaseHelper.getKrautDAO();
parent = (LinearLayout) ((Activity) context).findViewById(R.id.ll_conainter_sv_uebersicht_kraeuter);
//setKraeuter(list, linearLayout, giftig)
long test = System.currentTimeMillis();
List<Kraut> list = new ArrayList<>();
switch (kategorie) {
case 1:
list = dao.queryForAll();
break;
case 2:
list = dao.queryBuilder().where().ne("notiz","").query();
break;
case 3:
list = dao.queryBuilder().where().eq("favorit",true).query();
break;
case 4:
list = dao.queryBuilder().where().eq("toedlichBunny",true).query();
break;
}
Log.i("Kraut","Fetching duration: " + String.valueOf(System.currentTimeMillis() - test));
Iterator<Kraut> iterator = list.iterator();
while(iterator.hasNext()) {
Kraut kraut = iterator.next();
Log.i("Kraut","called pp for" + kraut.getName());
publishProgress(kraut);
}
} catch (SQLException e) {
e.printStackTrace();
}
Log.i("Kraut", "End " + (System.currentTimeMillis()-time) + "ms");
return null;
}
#Override
protected void onProgressUpdate(Kraut... value) {
//Set all Krauts and headlines A-Z
long test = System.currentTimeMillis();
Kraut kraut = value[0];
Log.i("Kraut", String.valueOf(counter));
if((kategorie==1 || kategorie==4) && kraut.getName().charAt(0)!=letter) {
letter = kraut.getName().charAt(0);
HeadlineAlphabet letterHeadline = new HeadlineAlphabet(context);
letterHeadline.setText(String.valueOf(kraut.getName().charAt(0)));
headlinesAlphabet.put(String.valueOf(letterHeadline.getText()),letterHeadline);
parent.addView(letterHeadline);
}
KrautView krautView=null;
if(kategorie==1 || kategorie==3) {
krautView = new KrautUebersicht(context,kategorie);
} else if(kategorie==2) {
krautView = new KrautUebersichtNotiz(context);
}
if(krautView!=null) {
krautView.setKraut(kraut);
parent.addView((LinearLayout) krautView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
parent.getRootView().invalidate();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
Log.i("Kraut","Kraut View creation duration: " + String.valueOf(System.currentTimeMillis() - test));
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(kategorie==1) {
//Set Alphabet Column right side
ArrayList<String> anfangsbuchstaben = Kraut.getAnfangsbuchstaben(context);
// Do this with an xml !
for (int i = 1; i <= 26; i++) {
//Log.i("Kraut", String.valueOf(i));
String currentLetter = Helper.getCharForNumber(i);
int id = context.getResources().getIdentifier("tv_"+currentLetter.toLowerCase(),"id",context.getPackageName());
TextView textView = (TextView) ((Activity) context).findViewById(id);
//If no Kraut contains Letter
if (!anfangsbuchstaben.contains(currentLetter)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
textView.setTextColor(context.getResources().getColor(R.color.darkgrey, context.getTheme()));
} else {
textView.setTextColor(context.getResources().getColor(R.color.darkgrey));
}
//Make clickable to jump to A-Z Headlines
} else {
textView.setOnClickListener(new JumpToLetterOnClickListener(headlinesAlphabet));
}
}
}
parent.invalidate();
if(dialog.isShowing()) {
dialog.dismiss();
}
}
}
Note that onProgressView() is called repeatedly as your AsyncTask runs. Therefore, it should be kept as short as possible. This also means that your current code is creating lots of views and adding them to the UI. Instead, you should add the view just once and then update its data in onProgressView().
Also, as Mike M. states in the comments, you should not call Thread.sleep() in onProgressView() since it runs on the UI thread. This is most likely the main reason your app is freezing.

Android: AsyncTask - doesn't seem to run asynchroneously

I'm trying to use AsyncTask to make a tas run apart from the main thread, thus prevent locking the thread while the task is running. Have I misunderstood the use for AsyncTask?
The calling code from the main thread:
public void onClick(View view) {
int input = Integer.parseInt(editInput.getText().toString());
String out = "";
try {
out = new RunAsyncTask().execute(Integer.toString(input)).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
From the AsyncTask class:
protected String doInBackground(String... params) {
long start, stop;
long result;
String out = "";
int input = Integer.parseInt(params[0]);
// Dalvik (Java) - Recursive:
start = System.currentTimeMillis();
result = FibLib.fibJR(input);
stop = System.currentTimeMillis();
out += String.format("Dalvik (Java) recursive: %d (%d msec)", result, stop - start);
// Dalvik (Java) - Iterative:
start = System.currentTimeMillis();
result = FibLib.fibJI(input);
stop = System.currentTimeMillis();
out += String.format("\nDalvik (Java) iterative: %d (%d msec)", result, stop - start);
return out
From the FibLib class (which is called by the AsyncTask):
public class FibLib {
public static long fibJR(long n) { //
if (n <= 0) {
return 0;
}
if (n == 1) {
return 1;
}
return fibJR(n - 1) + fibJR(n - 2);
}
// Java implementation - iterative:
public static long fibJI(long n) { //
long previous = -1;
long result = 1;
for (long i = 0; i <= n; i++) {
long sum = result + previous;
previous = result;
result = sum;
}
return result;
}
However, when running this, the main GUI thread is still locked and crashes if the task is more than just a small, quick one. What am I misunderstanding here?
You're calling the AsyncTask's get() method, which really turns an asynchronous call to synchronous, because it waits for the result of the operation. A better way to return the result of the AsyncTask to the calling Activity is to use a callback interface. Create a simple interface, e.g.:
interface OnTaskCompletedListener {
void onTaskCompleted(Object result);
}
Now implement that interface in your Activity class:
public class MainActivity extends Activity implements OnTaskCompletedListener {}
Now you should pass the MainActivity to the AsyncTask object:
AsyncTask task = new RunAsyncTask(onTaskCompletedListener).execute();
And inside the AsyncTask's onPostExecute() you return the result to the listener:
onTaskCompletedListener.onTaskCompleted(result);
Now you can use the result in your Activity's onTaskCompleted() method.
Hope the explanation was clear enough and it will help you.

ConcurrentModificationException when iterating keys of a HashMap

I have a HashMap of Sound objects
private HashMap<Integer, Sound> sounds;
over which I'm trying to iterate to turn off all the sounds. I used
this answer to create an Iterator, but I'm still getting ConcurrentModificationException, though I'm sure there's no other code calling this at the same time.
public synchronized final void stopAll() {
Iterator<Entry<Integer, Sound>> soundEntries = sounds.entrySet().iterator();
while(soundEntries.hasNext())
{
Entry<Integer, Sound> s = soundEntries.next();
s.getValue().myOnCompletionListener = null;
s.getValue().fadeYourself();
}
sounds.clear();
}
In what way should I rewrite this to keep the ConcurrentModificationException from happening?
This is inside my Sound class:
private class soundFader extends AsyncTask<Sound, Void, Void>
{
#Override
protected Void doInBackground(Sound... arg0) {
arg0[0].fadeOut();
return null;
}
}
private void fadeOut()
{
float STEP_DOWN = (float) 0.10;
float currentVol = myVolume;
float targetVol = 0;
if(isSoundEnabled())
{
while(currentVol > targetVol)
{
currentVol -= STEP_DOWN;
mp.setVolume(currentVol, currentVol);
try {
Thread.sleep(70);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
mp.setVolume(0, 0);
onCompletion(mp);
sounds.remove(resource); // THIS LINE WAS MY ERROR
mp.seekTo(0);
nowPlaying = false;
}
public void fadeYourself()
{
soundFader fader = new soundFader();
fader.execute(this);
}
It is not permissible for one thread to modify a Collection while another thread is iterating over it.
If you want to modify only values (not keys) there is no need to use iterators here.
public synchronized final void stopAll() {
for(Sound s: sounds.values())
{
s.myOnCompletionListener = null;
s.fadeYourself();
}
sounds.clear();
}
Ninja edit:
You are removing items from the Collection while iterating. Hence the CoMo exception.
Since you are doing sounds.clear(); towards the end, you can remove the sounds.remove(resource); line.

Categories

Resources