Should I launch a Thread to parse some xml? - android

I'm kinda new to android development, but i'm trying to make a xml parser. I've been using android.sax library, following some tutos, and this works great.
One thing that is making me sceptical, is that I don't actually launch the parser in a separate thread, I just use a handlers to communicate between my parser and my main activity.
Should I parse in a Thread ?
Here's my main activity code :
tv = (TextView)findViewById(R.id.tv);
try {
URL url = new URL("https://www.googleapis.com/shopping/search/v1/public/products?key=AAAAABBBBBCCCCDDDEEEEFFF&country=FR&restrictBy=gtin=5030999075254&alt=atom");
XMLHandler xHandler = new XMLHandler();
Feed feed = xHandler.parse(url.openStream());
if(feed.getTotalResults()==0 || feed.getItems() == null || feed.getItems().isEmpty()) {
Log.w("XMLPARSENull", "No items
}
else {
tv.setText(feed.getTotalResults()+" " + feed.getItemsPerPage() + " " + feed.getStartIndex() + " " + feed.getTitle());
Iterator<Product> it = feed.getItems().iterator();
while(it.hasNext()) {
Log.w("XMLPARSEFeed",it.next().getName());
}
}
} catch(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("XMLPARSEException", "ERROR",e);
}

I don't think that it's the parsing so much as the network operation, as any network request should not be performed in the UI thread. You can either spawn a new Thread or an AsyncTask to perform your network request. Here are some links to help:
AsyncTask
Painless threading
Expensive operations
Designing for responsiveness
Thread documentation
Handler documentation

A simple answer:
If you have connections in your main ( UI ) thread, the user interface will become frozen whilst the thread is used to download the information and parse it. It takes some time for a connection so it may appear to freeze.
Apart from that, android 4.0 now does not actually allow you to call HTTP requests from this thread, it will throw an error which will be seen in logcat before crashing.
It is best practise to use an Async Task here, here is some more information on that.
Information on Async Tasks!

Yes, it is imperative that you move your parsing into a background thread, particularly if your XML is being streamed across the network; otherwise your app is likely to be killed off by the system for blocking the main thread.
You don't have to use a raw Thread, though; Android provides things like ASyncTask to make it a bit easier.

Everything which isn't related to direct interaction with GUI should be moved to separate thread, prefferably AsyncTask if you need interaction with GUI from that thread since Android won't allow accessing GUI from regular Thread class.
http://developer.android.com/reference/android/os/AsyncTask.html

Related

Android application doing too much work on main thread

I call function processImage() on a button click and could't get the exact output needed.
processImage() function,
private void processImage() {
TextRecognizer textRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
if (textRecognizer.isOperational()) {
Log.d("IMAGE-PROCESS", "started");
Frame frame = new Frame.Builder().setBitmap(bitmap).build();
final SparseArray<TextBlock> items = textRecognizer.detect(frame);
runOnUiThread(new Runnable(){
public void run() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < items.size(); i++) {
TextBlock textBlock = items.valueAt(i);
stringBuilder.append(textBlock.getValue());
stringBuilder.append("\n");
}
try {
Log.d("IMAGE-PROCESS", "finished");
Log.d("OUTPUT", stringBuilder.toString());
textView.setText(stringBuilder.toString());
} catch (final Exception ex) {
Log.i("EXC","Exception in thread");
}
}
});
} else {
Log.d("IMAGE-PROCESS", "not operational");
}
}
It logs
I/Choreographer: Skipped 86 frames! The application may be doing too much work on its main thread.
Do I need to change anything in my function?
Help me to fix this
You need to make sure that the processImage method runs on a background (non-ui) thread. It is probably running on the UI thread now, and you get the warning because it is blocking the UI thread.
There are a number of ways to do work on a background thread, from simply spawning a new thread to creating a service - you will need to research this, and decide on the best method for your particular situation. Just remember that when your background processing is complete, you need to transfer the data to the UI thread, and update the UI from the UI thread, as attempting an update from another thread will cause a crash.
My only specific advice is to not use an AsyncTask. They sound great in theory, but unless you really know how they work, they can get you into a lot of trouble. And if you really know how they work, you're fully capable of doing something more reliable.
Where is the posted code located?
Usually, even if the hard work is done on the UI thread, the screen will freeze/stutter, but eventually, the desired output is produced. I'd guess 86 skipped frames is ~1.25 s of freezing.
If your processImage() method is inside a Runnable, Callable<>, or the like, then one could understand the use of Activity.runOnUiThread(), but..
Since you are getting this message, and you did not mention this imporant detail, I'll assume that your code runs on the UI thread.
Image processing is an expensive task, and should be carried out on a background thread.
To do an kind of background work, you should use some of the ready-made classes (e.g. AsyncTask, Service, etc.), or create ones on your own (with the help of Executors or the like).
Find out how to do that here

Should I use AsyncTask to establish an XMPP connection?

I am connecting to an XMPP server in Android using Smack. Here is my code:
static void openConnection() {
try {
if (null == connection || !connection.isAuthenticated()) {
XMPPTCPConnectionConfiguration.Builder configuration = XMPPTCPConnectionConfiguration.builder();
configuration.setHost(SERVER_HOST);
configuration.setPort(SERVER_PORT);
configuration.setServiceName(SERVICE_NAME);
configuration.setUsernameAndPassword(new TinyDB(context.getApplicationContext()).getString("username"), new TinyDB(context.getApplicationContext()).getString("password"));
configuration.setDebuggerEnabled(true);
connection = new XMPPTCPConnection(configuration.build());
connection.setUseStreamManagement(true);
connection.setUseStreamManagementResumption(true);
ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
reconnectionManager.enableAutomaticReconnection();
reconnectionManager.setReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
connection.connect();
connection.login();
}
} catch (XMPPException xe) {
xe.printStackTrace();
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
So when I call openConnection() should I do that in an AsyncTask or is that not necessary? I am a little confused.
You should manage your XMPP(TCP)Connection within an Android Service. The service state (running/stopped) should reassemble the connection state: When the service is running the connection should be established or the service should try to establish the connection (if data connectivity is available). If the service stops, then also disconnect the connection.
When i call openConnection() should i do that in an asynctask or that is not neccesary?
Shortly, YES. Everything related with networking should be moved to another thread to avoid blocking main thread. Hence doInBackground() of AsyncTask runs on another thread, which is where you should call that function.
Yes, as the official documentation points it out:
AsyncTask enables proper and easy use of the UI thread. This class
allows to perform background operations and publish results on the UI
thread without having to manipulate threads and/or handlers.
I chose not to use AsyncTask for my smack project after searching around.
its threading model have been quite different between Android version and need to take care about, also after honeycomb, it is single thread, long blocking this will cause issue on the whole device that also use AsyncTask , xmpp and bosh can cause long blocking up to seconds/minutes
AsyncTask has implicit reference to activity and such a long operation will cause memory issues, or easy memory leakage when exception handling is not proper
AsyncTask 's result will be lost if reference activity got reset, but activity in Android can be reset as easy as a simple device rotation or network configuration change, too many save and restore instance to make this usable as every xmpp operation may be long task

Alternative for retrieving Data From WebServices Using AyncTasks

I have an Android application that uses AsyncTasks to make get and post calls to send and retrieve data from server. All works fine but sometimes the async task takes a lot of time to execute and thus other async tasks have to wait (if more than 5 async tasks is there) so what will be the best alternative or how to increase the thread pool if it is safe to do so.
Asynctask are implemented behind the scene using threadpool, the default pool size for asynctasks is 1(so you can't run 2 asynctasks in parallel).
In newer versions of android the default Asynctask pool size is 5.
It's possible to change it but not recommended.
You can just create thread like in the sample I attached before:
Thread thread = new Thread() {
#Override
public void run() {
try {
//Do http request here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();

Emulate Web Workers in Android pre- Kitkat

Since Webworkers is only implemented from Android 4.4 onwards, is it possible to have a wrapper in the application code that provides this functionality to the contained WebView?
An example on how to solve this would really help.
Thanks,
Rajath
I guess you are talking about running a javascript code block in the background, i.e. different thread. Had tried doing that using RhinoJS on Android. Tested on Android 2.2 and above
https://github.com/devthon/SilentJSAndroid
The main features are
Execute Javascript code without browser context
Execute Javascript code from a script file
Load other JS files in the same context
Execute a method in the background thread and return a result
Execute a Object.Method() call
Execute a prototype method call
Run long running script in the background after app is closed.
May not be a full fledged Web worker as such, since it doesn't have API to check the status in between. But that can be still added to the interface I believe.
If this is the direction you are looking for, I can explain more on how it is done.
How much of the Worker spec do you need to implement, and how flexible does the implementation need to be? You could probably get basic functionality up and running using a JavaScript interface[1] and spawning threads natively from Java. However this will get complex quite quickly.
Perhaps if you can describe what you are using workers for I might be able to offer a different/better suggestion.
[1] http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)
--
Adding some pseudo code
In JavaScript spawn a Java worker thread:
var worker_id = window.Android.spawnWorker();
In JavaScript, run a task on that worker:
var task_id = window.Android.doAdditionOnWorker(2,2, worker_id);
Handle the result in JavaScript
function onReceiveResultForWorkerTask(task_id, result) {
alert("the answer was " + result);
}
Java side:
public int spawnWorker() {
HandlerThread worker = new HandlerThread();
worker.start();
Handler h = new Handler(worker.getLooper()) {
#Override
handleMessage(Message msg) {
switch(msg.what)
case ADD:
// calculate the answer and send back to JS via UI thread
// Unpack parameters and task id from Message
mWebView.post(new Runnable(
public void run() {
mWebView.loadUrl("javascript:onReceiveResultForWorkerTask(task_id, " + (a+b) +");");
}
)
}
};
mWorkerMap.put(mWorkerId++, h);
return mWorkerId;
}
public int doAdditionOnWorker(int a, int b, int worker_id) {
Handler h = mWorkerMap.get(worker_id);
Bundle b = new Bundle();
int task_id = mTaskId++;
// pack arguments and task_id into the bundle
h.postMessage(Message.obtain(h, ADD, b);
return task_id;
}
Don't forget to go through and tear down all the worker threads that you spawn when the app doesn't need them anymore. Depending on how many workers you need you might also prefer to use a thread pool rather than creating new threads every time.

Need an example showing how to do async HTTP requests

Im using a web service, so I want to use an async thread for the HTTP authentication request and another thread later to make additional service requests while my main thread runs.
Would like to see a good example of how to do this and how to show busy messages somehow in main app. How does the main app know when the thread finished? And what if my thread encounters exceptions, how do I deal with that?
HTTP requests are sent later, use the same cookies setup up by the first auth request, so will the later requests pick up the same cookies and just work?
Even better look here for the async part: Is there an accepted best-practice on making asynchronous HTTP requests in Android?
Look at here How to execute web request in its own thread?
AndroidAsync library I wrote to handle this automatically, it will run in the background and reinvoke onto the UI thread:
https://github.com/koush/AndroidAsync
// url is the URL to download. The callback will be invoked on the UI thread
// once the download is complete.
AsyncHttpClient.getDefaultInstance().get(url, new AsyncHttpClient.StringCallback() {
// Callback is invoked with any exceptions/errors, and the result, if available.
#Override
public void onCompleted(Exception e, String result) {
if (e != null) {
e.printStackTrace();
return;
}
System.out.println("I got a string: " + result);
}
});

Categories

Resources