Asynctask taking ridiculous amount of time - android

My problem is that I had a program working before, without threading, and it took a long time to process info (16 seconds to get XML data and display it). Now I've gotten the whole threading and async thing down, but for some reason it is making my program SLOWER (in the emulator, device is not available right now), is there anything I've done that could have caused this, the UI thread is fine, but my async thread takes a minute and a half to execute. (when I had it in the UI thread used to take only 16 seconds, but froze the UI thread)
Here is the code for my thread, it sits inside of the main class:
private class TeamSearchTask extends AsyncTask<String,Void,String> {
CharSequence nfo;
String [] matches;
String [] data;
String teamNum;
ProgressDialog loading;
protected void onPreExecute()
{
//Show the 'loading' dialog
loading = new ProgressDialog(SapphireAlliance.this);
loading.setMessage("Loading, please wait...");
loading.show();
}
protected String doInBackground(String... teamNumber)
{
try
{
//Team information ------------------------------------------------------------------------------------
teamNum = teamNumber[0];
//Array of team data
data = APIconnection.getTeams(teamNum, "");
//Display basic team info
nfo = ("\nFormal Team Name:\n" + data[1] +
"\n\nLocation:\n" + data [3] + ", " + data[4] + ", " + data[5] +
"\n\nRookie Year:\n" + data[6] +
"\n\nRobot Name:\n" + data[7] +
"\n\nWebsite:\n" + data[8] + "\n\n\n\n\n\n\n\n\n");
//Make match archive --------------------------------------------------------------------------------------
String [] events = APIconnection.getEventIdsByYear(year1);
ArrayList<String> matches = new ArrayList<String>();
for (int i = 0; i<events.length; i++)
{
String [] add = APIconnection.getMatches2(teamNum, events[i] ,"","");
for(int j = 0; j<add.length; j++)
matches.add(add[j]);
}
String [] out = new String [matches.size()];
matches.toArray(out);
return "";
}
catch(Exception e)
{
return e.toString();
}
}
protected void onPostExecute(String result) {
if(result.equals(""))
{
info.setText(nfo);
matchArchive(matches);
//title
CharSequence ttl = "Team " + teamNum;
titlets.setText(ttl.toString());
loading.dismiss();
}
else
{
alert.setMessage(result);
alert.show();
}
}
}
Anything in there that could be causing this? :|

It may be that your thread priority may not be set very high. I remember the default is rather low. However, for what you're doing, it shouldn't be taking more than a couple seconds. I would think that the real problem lies in APIconnection going to the network and doing something that takes a long time. Particularly, that for loop that does the event fetching would be doing a lot of work if each call opens a new socket, assuming that this is for FIRST matches. :P

I am having the same issue, doing nothing more than a file copy with simple DES decryption... the whole thing ran in a few seconds on the UI thread, but when moved into an ASYNCTASK it is now taking MINUTES to accomplish. Unbelievable.

Related

Divide long TextView into small parts and make a cardview around these parts | Android

I have a question: Is it possible to divide a very long text, which the app gets from the Internet in a Json-data, into small parts of the text? Then these parts should be shown in single cardviews.
If it's possible, can somebody show me how? I tried a very long time and didn't get it. Thanks for help!
EDIT
That's the jsonRequest and it builds the TextView.
jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, "http://example.com/document.json",
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray("data1");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject obj = jsonArray.getJSONObject(i);
String a = obj.getString("a");
String b = obj.getString("b");
String c = obj.getString("c");
String d = obj.getString("d");
textView.append(Html.fromHtml("<p><b>" + a + "</b><br>" + b + "<br>" + c + "<br>" + d + "</p>"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY", error.toString());
}
}
);
requestQueue.add(jsonObjectRequest);
;
Now the TextView should be divided into small parts. In every part should be the Strings a, b, c and d. And around these small parts should be a cardview.
One attempt would be :
Break the text parts with something unique like , and then you can use
StringTokenizer tokens = new StringTokenizer(comma_string_here, ",");
String first_text = tokens.nextToken();
String second_text = tokens.nextToken();
You can loop through and set background as you desire for those text.
you can split text based on any special character or space if you provide me sample data, so I can give you proper solutions.
First let me say I think there must be a better approach to do what you want to do, but if you want to really cut a string in pieces to show it different cardviews, another way of doing it is to cut it based on a fixed number of characters.
This function will take the text and the fixed limit. And it will return an array. In the first position it will have the thext that has been cut out and in the second position the remaining text.
The cut part may fall in the middle of a word. If you don't want that, you can add some more logic using rtn[0].lastIndexOf(" ") to search for the last blank space and adjust the results accordingly.
public static String[] limitToNChars(String text, int limit){
String rtn[] = new String[2];
if(text.length() <= limit){
rtn[0] = text;
rtn[1] = "";
}else{
rtn[0] = text.substring(0,limit);
rtn[1] = text.substring(limit);
}
return rtn;
}
You can call this function in a loop pasing the result's second position as the first parameter of the function until the second position is an empty string to get all the substrings from the initial string.

AsyncTask takes too much time the first time it executes

The first time the Asynctask executes takes 30 or more seconds. It happens when I enter the activity. After that, subsequents call to the Asyntask(when I enter the activity again from the previous activity) takes only 4 or 5 seconds, which I consider to be "acceptable".
Here is the code where I execute the AsyncTask
#Override
public void onLocationChanged(Location location) {
if (location!=null) {
mlastLocation=location;
double latitud=Double.parseDouble(getIntent().getStringExtra("latitud").replace("Latitud:", ""));
double longitud=Double.parseDouble(getIntent().getStringExtra("longitud").replace("Longitud:", ""));
LatLng origen= new LatLng(latitud,longitud);
LatLng destino=new LatLng(mlastLocation.getLatitude(),mlastLocation.getLongitude());
if (mCount==0) {
FillVariablesAsyncTask tareaAsincrona = new FillVariablesAsyncTask();
tareaAsincrona.execute(origen, destino);
mCount++;
}
}
}
And here the code of the AsyncTask, where onPostExecute updates members variables and update the UI.
private class FillVariablesAsyncTask extends AsyncTask<LatLng,Void,Document>{
#Override
protected Document doInBackground(LatLng... params) {
md=new GMapV2Direction();
LatLng origen=new LatLng(params[0].latitude,params[0].longitude);
LatLng destino=new LatLng(params[1].latitude,params[1].longitude);
Document doc = md.getDocument(origen, destino, GMapV2Direction.MODE_WALKING);
/*mUbicacionActual = md.getStartAddress(doc);
mDuration=md.getDurationText(doc);
mDistancia=md.getDistanceText(doc);*/
return doc;
}
#Override
protected void onPostExecute(Document doc) {
super.onPostExecute(doc);
mUbicacionActual = md.getStartAddress(doc);
mDuration=md.getDurationText(doc);
mDistancia=md.getDistanceText(doc);
if (mUbicacionActual!=null && mDistancia!=null && mDuration!=null) {
progressBar.setVisibility(View.GONE);
btnIr.setEnabled(true);
tvOrigenLatitud.setText("Latitud:"+String.valueOf(mlastLocation.getLatitude()));
tvOrigenLongitud.setText("Longitud"+String.valueOf(mlastLocation.getLongitude()));
tvDestino.setText("Destino:" + getIntent().getStringExtra("info").replace("Info:", ""));
tvDestinoLatitud.setText("Latitud:" + getIntent().getStringExtra("latitud").replace("Latitud:", ""));
tvDestinoLongitud.setText("Longitud:" + getIntent().getStringExtra("longitud").replace("Longitud:", ""));
tvOrigen.setText("Origen:" + mUbicacionActual);
tvDistancia.setText("Distancia:"+mDistancia);
tvTiempo.setText("Tiempo:" + mDuration);
}
}
}
I've tried out .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) but the app crashes. I've tried out also with a handler but it shows the same Behaviour, the first time takes 30 seconds or so, while the subsequents takes only a few.
Edit to show to points where i added log:
if (mCount==0) {
FillVariablesAsyncTask tareaAsincrona = new FillVariablesAsyncTask();
mStart=System.currentTimeMillis();
Log.i("START_BEFORE_EXECUTE", mStart + "");
tareaAsincrona.execute(origen, destino);
long end=System.currentTimeMillis();
Log.i("ELAPSED_EXECUTE", ((end-mStart)/1000) + "");
mCount++;
}
Here :
protected Document doInBackground(LatLng... params) {
long end;
end =System.currentTimeMillis();
Log.i("ELAPSE_PRE_BACKGROUND",((end- mStart)/1000)+"");
md=new GMapV2Direction();
end=System.currentTimeMillis();
Log.i("ELAPSED_POS_GMAPV2DIR",((end- mStart)/1000)+"");
LatLng origen=new LatLng(params[0].latitude,params[0].longitude);
LatLng destino=new LatLng(params[1].latitude,params[1].longitude);
end=System.currentTimeMillis();
Log.i("ELAPSED_PRE_GETDOCUMENT",((end- mStart)/1000)+"");
Document doc = md.getDocument(origen, destino, GMapV2Direction.MODE_WALKING);
end=System.currentTimeMillis();
Log.i("ELAPSED_POS_BACKGROUND",((end- mStart)/1000)+"");
/*mUbicacionActual = md.getStartAddress(doc);
mDuration=md.getDurationText(doc);
mDistancia=md.getDistanceText(doc);*/
return doc;
}
and here:
long end=System.currentTimeMillis();
Log.i("ELAPSED_onPostExecute",((end-mStart)/1000)+"");
mUbicacionActual = md.getStartAddress(doc);
mDuration=md.getDurationText(doc);
mDistancia=md.getDistanceText(doc);
end=System.currentTimeMillis();
Log.i("ELAPSED_POST_FILLVARS",((end-mStart)/1000)+"");
if (mUbicacionActual!=null && mDistancia!=null && mDuration!=null) {
progressBar.setVisibility(View.GONE);
btnIr.setEnabled(true);
tvOrigenLatitud.setText("Latitud:" + String.valueOf(mlastLocation.getLatitude()));
tvOrigenLongitud.setText("Longitud" + String.valueOf(mlastLocation.getLongitude()));
tvDestino.setText("Destino:" + getIntent().getStringExtra("info").replace("Info:", ""));
tvDestinoLatitud.setText("Latitud:" + getIntent().getStringExtra("latitud").replace("Latitud:", ""));
tvDestinoLongitud.setText("Longitud:" + getIntent().getStringExtra("longitud").replace("Longitud:", ""));
tvOrigen.setText("Origen:" + mUbicacionActual);
tvDistancia.setText("Distancia:"+mDistancia);
tvTiempo.setText("Tiempo:" + mDuration);
end=System.currentTimeMillis();
Log.i("ELAPSED_POS_onPostExecute", ((end - mStart) / 1000) + "");
}
this image shows the log output, it shows 3 but in reality is 30 or more.
[IMG]http://i61.tinypic.com/95o1ef.png[/IMG]
The time is taking have absolutely nothing to do with AsyncTask or Thread or Handler or Executor
The issue is that library you're using really takes that long to make calls to a server, or to process the information and I don't believe there's much you can do about it. It's only the 1st time because I'm guessing the library caches the result, but it still have nothing to do with the threading model you use.
The main point of my answer is that you're asking the wrong question. The correct question is:
Why this library is taking that long to process and what can you do to shorten it?
Unfortunately the only possible way to answer it is by analysing the source code of it or talking directly with the library developer.
edit:
to help you measure the executions:
public static class TimeMeasure {
private final DecimalFormat format;
private final double start;
private final String tag;
public TimeMeasure(String tag) {
this.format = new DecimalFormat("0.0");
this.start = System.currentTimeMillis();
this.tag = tag;
log("start);
}
public void log(String message) {
double elapsed = ((double) (System.currentTimeMillis() - start)) / 1000.0;
Log.d(tag, format.format(elapsed) + ": " + message);
}
}
then during doInBackground
protected Document doInBackground(LatLng... params) {
TimeMeasure tm = new TimeMeasure("Carlos");
// execute something:
tm.log("action 1");
// execute next
tm.log("action 2);
// etc...
}
I can't comment yet so here you go: you can use your IDE's debugger after you place breakpoints on every line in the two given blocks of code to see which line takes the most to execute. Then post your findings.
As the above answer mentioned it is actually the library that takes too much time.
I had a similar problem a while ago, I remember that after debugging what causes the problem was distance and duration and also if you were getting some kind of an address, it will contribute to the delay
(For Example) getting street name, city name and country etc..
I didn't really find any better API or library to deal with this but what i did was something to improve the user experience:
1-start another AsyncTask from onPostExecute() that will get duration and distance.
2- while the app is getting duration and distance don't block the user interface with a progress dialog or progress bar, just put loading... as an default value of your TextView then when the app receives the data setText to the actual value.
3-Do all of you data manipulation later after setting important data.
Hope this will help.

GreenDAO clears cache randomly

I´ve got two buttons in an Android activity with these two methods attached. One of them loads data and another just retrive it. Of course, the first time I execute the second method it gets data from cache and consumed time is very low, but further calls to this method always becomes in bigger times (as bigs as the consumed by the load data method), in other words, it seems that cache clears "randomly".
daoSession is an static attribute and I just call several times the getDataFromCacheById method (press the same button repeteadly, nothing else). Why does it clears cache? Is there any way to keep the cache data in memory always?
Best regards
public void onMyLoadButtonClick(View view) {
listaIds.clear();
List<String> lTexto = new ArrayList<String>();
Date iniTime = new Date();
LibroDao libroDao = daoSession.getLibroDao();
for (Libro tempLibro : libroDao.loadAll()) {
for (Nota tempNota : tempLibro.getNotaList()) {
lTexto.add(tempNota.getText());
listaIds.add(tempNota.getId());
}
}
Date finTime = new Date();
long tiempoTotal = finTime.getTime() - iniTime.getTime();
Log.v(LOG_TAG, "Overall time = " + tiempoTotal + " lTextoSize = " + lTexto.size());
}
public void getDataFromCacheById(View view) {
List<String> lTexto2 = new ArrayList<String>();
Date iniTime2 = new Date();
for (Long tempId : listaIds) {
lTexto2.add(noteDao.load(tempId).getText());
}
Date finTime2 = new Date();
long tiempoTotal2 = finTime2.getTime() - iniTime2.getTime();
Log.v(LOG_TAG, "Tiempo total de la operación Prueba Caché = " + tiempoTotal2 + " lTextoSize = " + lTexto2.size());
}

Android trouble comparing strings with RecognitionListener

The thing that bugs me the most about this is; I have another activity that uses a different approach (using startActivityForResult(intent....) vs a listener class implementing RecognitionListener, and one works the other doesnt'. I'm certain I'm doing something stupidly wrong, but I sure can't figure out what.
I'm getting the speech recog results back using onResults, using a listener class that implements RecognitionListener.
public void onResults(Bundle results) {
Log.d("Speech", "onResults");
ArrayList strlist = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
for (int i = 0; i < strlist.size(); i++) {
String matchstring = matchpair[1].toString().toLowerCase();
String speechstring = strlist.get(i).toString().toLowerCase();
Log.d("Speech", "result=" + speechstring);
if (checkResult(matchstring, speechstring)) {
System.out.println("Phonetic match: " + speechstring + " = " + matchstring);
} else System.out.println("NO match: " + speechstring + " = " + matchstring);
}
}
The checkresult is simple, just a boolean compare:
public boolean checkResult(String result, String checkmatch) {
if (result.equals(checkmatch))
{
return true;
}
return false;
}
Looking at the debug info, the results appear to compare - but the boolean is returning false.
It's driving me nuts. I'm going this route so I can use the recognition functionality without having the Google dialog pop on every recognition attempt. In the activity I began with, the compare is working perfectly.
I welcome someone pointing out whatever very stupid thing I am overlooking.

How to make threads synchronize in a loop statement?

I am new to threads. I am trying to load a small array of photos. Right now I am using Async tasks/ threads, but how do I make the outcome sequential? Below is an illustration:
What I want:
a[0] = photo1;
a[1] = photo2;
a[2] = photo3;
a[3] = photo4
What my program gives me instead. Note that the order changes and is random:
a[0] = photo[2];
a[1] = photo[1];
a[2] = etc
Here's a snippet of my code:
...
for (int i = 0; i < mNoOfContacts; i++) {
String stringContactUri = storeSettings.getString("contactUri"+i, "");
if (stringContactUri != ""){
Uri contactUri = Uri.parse(stringContactUri);
loadContactInfo(contactUri);
}
...
private void loadContactInfo(Uri contactUri) {
AsyncTask<Uri, Void, ContactInfo> task = new AsyncTask<Uri, Void, ContactInfo>() {
#Override
protected ContactInfo doInBackground(Uri... uris) {
return mContactAccessor.loadContact(getContentResolver(), uris[0]);
}
#Override
protected void onPostExecute(ContactInfo result) {
Contacts[mNoOfContacts] = result;
Toast.makeText(getApplicationContext(), mNoOfContacts+"Picked Contact"+Contacts[mNoOfContacts].getDisplayName(), Toast.LENGTH_SHORT).show();
mNoOfContacts++;
}
};
task.execute(contactUri);
}
...
My code is a modification of the Google Android demo app - Business Cards.
Please help! Thanks!
What might be the easiest thing to do is make the onPostExecute method call a routine that does the sorting: pass both the ContactInfo and the Uri and then compare the Uri with the original and put it in the proper place.
Alternatively modify your AsyncTask so instead of launching one per Uri you launch one you pass all the Uris at once and then go from there.
I would think that, by definition, "Asynchronous Tasks" are not synchronized...Asynchronous literally means "not synchronized." If you want it synchronized, just load them the old fashioned way by doing a URI call, get your photo and do it again once the last photo was loaded.

Categories

Resources