I have two simple classes:
public class MainActivity extends Activity {
NetworkTask task;
#Override
protected void onCreate(Bundle savedInstanceState) {
[...]
task = new NetworkTask();
task.execute();
}
public void myClickHandler(View view) {
switch(view.getId()) {
case R.id.button1:
// Why this line crash?
task.connection("127.0.0.1");
break;
}
}
}
and
public class NetworkTask extends AsyncTask<String, Void, String> {
Socket sock;
volatile boolean running = true;
public int connection(String url){
try{
sock = new Socket(url, 4567)
}
catch (IOException ex){
Logger.getLogger(NetworkTask.class.getName()).log(Level.SEVERE, null, ex);
return -1;
}
}
public String doInBackground(String... strings) {
// If I do this, it works well
//connection(127.0.0.1);
while(running)
{
[...]
}
return null;
}
}
As I commented when I call connection method from outside of the AsyncTask method, the app crashes more particulary « sock = new Socket(...) » line. But when connection call is done inside the AsynTask method socket is created.
I don't understand why.
What's happening?
Thanks.
It's because when you do
task.connection("127.0.0.1");
You are still working in the main (UI) Thread - you're not using the AsyncTask properly. Instead you're using it like a normal class, and so, you get a NetworkOnMainThreadException on the new Android versions.
However when you call from doInBackground(), it means you started the AsyncTask via execute and the work is done in a separate Thread, letting everything work as it should.
Keep in mind that if you are doing non-network stuff, you can still call from outside. However, I'd recommend keeping your AsyncTask depend on the outside as little as possible, since AsyncTasks only run once. You then have to make a new instance if you want to do more work, which means if you depend on setter methods or similar, you have to make sure you call those methods again, which makes this simple class more complex than needed.
For a good, to the point explanation of how to use an AsyncTask, this is a pretty good source. And of course the official documentation.
Related
I have an Android app from which I receive BLE data (every 62ms via notifications). The app can save data via a BufferedWriter to a file. Upon each onCharacteristicChanged() callback, I call either an AsyncTask, Thread or an IntentService to do a file write if the user enabled file save.
The AsyncTask seems to work fine. But the docs say execute must be invoked on the UI thread, and I'm calling it from the BLE callback. Is that a problem? And how should I fix it?
Using Thread causes this error: GKI_exception out of buffers https://code.google.com/p/android/issues/detail?id=65455 (except my code is not scanning but receiving notifications) and if the file save is long, I need to power cycle the Nexus 7 (the app and BLE become totally unresponsive). Why does the Thread not work and how can I fix it?
The IntentService never goes to the onHandleIntent(). What are the issues here?
Here is some code:
...
_context = this.getApplicationContext();
...
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
...
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
...
int mode = 1;
if (mode==0) // Asynctask
new doFileWriteTask().execute(strBuild.toString());
else if (mode==1) // Thread
{
final String str = strBuild.toString();
new Thread(new Runnable() {
public void run() {
try {
_writer.write(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
else if (mode==2) // intentService
{
Intent mServiceIntent = new Intent(_context, writeFileService.class);
mServiceIntent.putExtra("foo", strBuild.toString());
startService(mServiceIntent);
}
}
...
};
private class doFileWriteTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... strings) {
try {
_writer.write(strings[0]);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private class writeFileService extends IntentService {
public writeFileService() {
super("writeFileService");
}
#Override
protected void onHandleIntent(Intent workIntent) {
String dataString = workIntent.getStringExtra("foo");
try {
_writer.write(dataString);
} catch (Exception e) {
e.printStackTrace();
}
}
}
...
But the docs say execute must be invoked on the UI thread, and I'm calling it from the BLE callback. Is that a problem? And how should I fix it?
The framework triggers the AsyncTask callback methods on the same thread it was called from (presumed to be the main thread). It doesn't really affect the background work, but you could see problems if you started trying to use onPostExecute() and the like. AsyncTask probably isn't the best choice to be called from a thread that you don't have control over.
Why does the Thread not work and how can I fix it?
I can't say exactly why you are still seeing errors, through spawning a series of private unsynchronized threads will probably lead to other headaches. If you want to use a single worker thread, a better choice would be to use a single HandlerThread that you can post to from your event callbacks using a Handler, something like:
…
_workerThread = new HandlerThread("Worker");
_workerThread.start();
_handler = new Handler(_workerThread.getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
String str = (String) msg.obj;
_writer.write(str);
return true;
}
});
…
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
…
Message msg = Message.obtain(_handler, 0, strBuild.toString());
_handler.sendMessage(msg);
…
}
That solution is quite a bit more code, but given the frequency of writes this is probably the most efficient choice.
The IntentService never goes to the onHandleIntent(). What are the issues here?
You should pretty much never implement a top level Android component (activity, service, content provider, receiver) as an inner class, because they have to be declared in your manifest as well (and the XML syntax for inner classes is ugly). If your service does not have a matching entry in the manifest, then you will never see it start. You might want to have a look at the docs on using services.
At a minimum, a Service written as an inner class must be public static to work. Otherwise the framework cannot see it and cannot instantiate it using a default constructor (non-static inner classes mess with the constructor). Unless you are calling startService() inside of a try/catch right now, I'm surprised it isn't crashing when you attempt this.
IntentService is probably the simplest of your three choices because it is the most decoupled and the framework will handle queueing up work and tearing down the threads when all the incoming work is done.
I think this is a quite common problem, but still I didn't find a satisfactory answer so I'm going to ask myself.
This is a piece of code:
// this is insine OnClickView
TextView status = (TextView) findViewById(R.id.status);
status.setText("Trying to connect to the server...");
try {
// this opens a socket and send a login request to the server.
int result = CommunicationManager.login(String email, String password);
switch (result) {
case CommunicationManager.SUCCESS:
// login ok, go on with next screen
break;
case CommunicationManager.WRONG_EMAIL:
status.setTextColor(Color.RED);
status.setText("Wrong Email!");
break;
case CommunicationManager.WRONG_PASSWORD:
status.setTextColor(Color.RED);
status.setText("Wrong Password!");
break;
}
} catch (CommunicationException e) {
status.setTextColor(Color.RED);
status.setText("Unable to estabilish a connection!");
} catch (ProtocolException e) {
status.setTextColor(Color.RED);
status.setText("Protocol error!");
}
This is what I would like to achieve:
User click Send button;
status textview shows "Trying to connect to the server...";
UI "waits" for communications to be over;
status textview shows result accordingly.
But instead when user clicks Send button, UI freezes (oddly before status text appears) until communication is done (I tried to connect to an unknown host).
A quick fix is to set a socket timeout, but I don't like this kind of solution: UI still freezes and which timeout should be set?
My first thought were Thread obviously, but as you can see I need to return a value, thing that in threading environment doesn't make much sense since threads run independently and asynchronously.
So what I need is definitely that UI waits for the service to be executed but without freezing.
By the way it seems to me that waiting for a return value means that UI has to wait for the task to be over, I just would not let it freeze.
I came across AsyncTask but I see two major disadvantages:
it seems to me that is too tightly coupled with UI;
what if I want to execute service with Integer, String and Boolean parameters? Should I extend AsyncTask<Object, Void, Void>?
Both leads to inextensibility.
What can I do to achieve my goal?
Please note that another request to the service will be a request for something that could not be ready yet, so I should automatically repeat request every few time (let's say ten minutes). So probably I'll need something I can use with TimerTask, but I'll still need to return a value to UI every time I execute that service (so I can update the status text and let the user know what's going on).
This is typical use case while dealing through external communication i.e. HTTP calls.
Best way is to use AsyncTask. To give you answers for your concerns for AsyncTask.
it seems to me that is too tightly coupled with UI;
Here good code design will play a role. You can write you own call back mechanism to get rid of tight coupling. Example can be below.
Create your version for request and response you need for WS call. It can be very simple primitive type or complex type parameters.
class Result{
//Define more para.
}
class Request{
//Deinf more para.
}
Write below callback interface.
public interface MyCallBack {
public void onComplete(Result result);}
Create AsyncTask and get above Interface object in constructor, same object can return Result object.
class LongRunningTask extends AsyncTask<Request, Integer, Long>{
private MyCallBack callback;
public LongRunningTask(MyCallBack callback) {
super();
this.callback = callback;
}
#Override
protected Long doInBackground(Request... params) {
// Perform your back ground task.
return null;
}
#Override
protected void onPostExecute(Long result) {
super.onPostExecute(result);
callback.onComplete(new Result()); //Here result is dummy but in real it should be contructred from doInBackground() method
}
}
Now last and important part to implement the interface and call asynctask. I am trying to reuse your code to have better clarity.
public class MainActivity extends Activity implements MyCallBack{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView status = (TextView) findViewById(R.id.status);
status.setText("Trying to connect to the server...");
}
private void onClick(){
//Similer to CommunicationManager.login(String email, String password); in your code.
LongRunningTask longRunningTask = new LongRunningTask(this);
longRunningTask.execute(new Request());
}
#Override
public void onComplete(Result result) {
try {
int result = result.getStatus
switch (result) {
case CommunicationManager.SUCCESS:
// login ok, go on with next screen
break;
case CommunicationManager.WRONG_EMAIL:
status.setTextColor(Color.RED);
status.setText("Wrong Email!");
break;
case CommunicationManager.WRONG_PASSWORD:
status.setTextColor(Color.RED);
status.setText("Wrong Password!");
break;
}
} catch (CommunicationException e) {
status.setTextColor(Color.RED);
status.setText("Unable to estabilish a connection!");
} catch (ProtocolException e) {
status.setTextColor(Color.RED);
status.setText("Protocol error!");
}
}
what if I want to execute service with Integer, String and Boolean parameters? Should I extend AsyncTask?
First Parameter is any user defined para. In case you need to pass multiple parameters then put them in to form of entity (i.e. - Class). Also, you can pass initial configuration parameter in constructor of AsyncTask i.e. - Communication URL.
Hope it will help.
Use multi threading, do all the communication in a different thread
Use worker thread, or AsyncTask for doing long-running operations.
Moreover, from Android Honeycomb, system throws exception, if you perform network operations on UI thread.
As of 15/2/2012 I have yet to find a good explanation to nor a reason why this does not work. The closest to a solution is to use the traditional Thread approach, but then why include a class that does not (seem to) work in the Android SDK?
Evenin' SO!
I have an AsyncTask subclass:
// ParseListener had a callback which was called when an item was parsed in a
// RSS-xml, but as stated further down it is not used at all right now.
private class xmlAsync extends AsyncTask<String, RSSItem, Void> implements ParseListener
That is executed like this:
xmlAsync xmlThread = new xmlAsync();
xmlThread.execute("http://www.nothing.com");
Now this subclass has run into a little error. Previously it did some xml-parsing, but when I noticed that it's doInBackground() wasn't called I stripped it down, line by line, finally ending up with just this:
#Override
protected Void doInBackground(String... params)
{
Log.v(TAG, "doInBackground");
return null;
}
Which, for some reason, logged nothing. However, I added this:
#Override
protected void onPreExecute()
{
Log.v(TAG, "onPreExecute");
super.onPreExecute();
}
And that line is indeed logged when executing the thread. So somehow onPreExecute() is called but not doInBackground(). I have another AsyncTask running in the background at the same time which works just fine.
I'm currently running the app on an emulator, SDK Version 15, Eclipse, Mac OS X 10.7.2, close to the North Pole.
EDIT:
#Override
protected void onProgressUpdate(RSSItem... values) {
if(values[0] == null)
{
// activity function which merely creates a dialog
showInputError();
}
else
{
Log.v(TAG, "adding "+values[0].toString());
_tableManager.addRSSItem(values[0]);
}
super.onProgressUpdate(values);
}
_tableManager.addRSSItem() more or less adds a row to a SQLiteDatabase, initialized with the activity's context. publishProgress() is called by the Interface ParseListener's callback. However, since I don't even do anything except log.v in doInBackground() I first found this unnecessary to even bring up.
EDIT 2:
Alright, just to be perfectly clear, this is the other AsyncTask, executing in the same activity and working perfectly fine.
private class dbAsync extends AsyncTask<Void, RSSItem, Void>
{
Integer prevCount;
boolean run;
#Override
protected void onPreExecute() {
run = true;
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
run = true;
prevCount = 0;
while(run)
{
ArrayList<RSSItem> items = _tableManager.getAllItems();
if(items != null)
{
if(items.size() > prevCount)
{
Log.v("db Thread", "Found new item(s)!");
prevCount = items.size();
RSSItem[] itemsArray = new RSSItem[items.size()];
publishProgress(items.toArray(itemsArray));
}
}
SystemClock.sleep(5000);
}
return null;
}
#Override
protected void onProgressUpdate(RSSItem... values) {
ArrayList<RSSItem> list = new ArrayList<RSSItem>();
for(int i = 0; i < values.length; i++)
{
list.add(i, values[i]);
}
setItemsAndUpdateList(list);
super.onProgressUpdate(values);
}
#Override
protected void onCancelled() {
run = false;
super.onCancelled();
}
}
EDIT 3:
Sigh, sorry I'm bad at asking questions. But here is the initialization of the Tasks.
xmlAsync _xmlParseThread;
dbAsync _dbLookup;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_dbLookup = new dbAsync();
_dbLookup.execute();
_xmlParseThread = new xmlAsync();
_xmlParseThread.execute("http://www.nothing.com", null);
}
You should checkout this answer: https://stackoverflow.com/a/10406894/347565 and the link to google groups it includes.
I had a similar problem as you, still unclear why it is not working, but I changed my code like this and problem is gone:
ASyncTask<Void,Void,Void> my_task = new ASyncTask<Void,Void,Void>() { ... };
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
my_task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
else
my_task.execute((Void[])null);
Matthieu's solution will work fine for most, but some can face problem; unless digging in many links provided here or from web, like Anders Göransson's explanation.
I am trying to summarize some other reads right here and quickly explain solution if executeOnExecutor is still working in single thread...
Behavior of AsyncTask().execute(); has changed through Android versions. Before Donut (Android:1.6 API:4) tasks were executed serially, from Donut to Gingerbread (Android:2.3 API:9) tasks executed paralleled; since Honeycomb (Android:3.0 API:11) execution was switched back to sequential; a new method AsyncTask().executeOnExecutor(Executor) however, was added for parallel execution.
In sequential processing all Async tasks run in a single thread and thus have to wait before the previous task ends. If you need to execute code immediately, you need tasks to be processed in parallel in separate threads.
With AsyncTask serial execution is not available between Donut and Honeycomb versions, while parallel execution is not available before Donut.
For parallel processing after Donut: Check the Build version and based on that use .execute() or .executeOnExecutor() method. Following code can help...
AsyncTask<Void,Void,Void> myTask = new AsyncTask<Void,Void,Void>() { ... }; // ... your AsyncTask code goes here
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
myTask.execute();
NOTE: Function .executeOnExecutor() has checks if targetSdkVersion of project is less than or equal to HONEYCOMB_MR1 (Android:2.1 API:7) then it forces the executor to be THREAD_POOL_EXECUTOR (which runs Tasks sequentially in post Honeycomb).
If you have not defined a targetSdkVersion then minSdkVersion is automatically considered to be the targetSdkVersion.
Hence for running your AsyncTask in parallel on post Honeycomb you cannot leave targetSdkVersion empty.
You can do this by two ways:
Way 1:
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) // Above Api Level 13
{
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else // Below Api Level 13
{
asyncTask.execute();
}
In case of way 1 not works for you try way 2.
Way 2:
int mCorePoolSize = 60;
int mMaximumPoolSize = 80;
int mKeepAliveTime = 10;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(mMaximumPoolSize);
Executor mCustomThreadPoolExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.SECONDS, workQueue);
asyncTask.executeOnExecutor(mCustomThreadPoolExecutor);
Hope this will help you.
I had the same issue : can't a execute a second AsyncTask after i called "execute" on a first one : doInBackground is only called for the first one.
To answer why this happens check this answer (different behavior depending on the SDK)
However, for your case, this obstacle can be avoided using executeOnExecutor (available starting from 3.0 worked for me using 4.0.3 ) but beware of limitations of the Thread pool size and queuing.
Can you try something like this :
xmlAsync _xmlParseThread;
dbAsync _dbLookup;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_dbLookup = new dbAsync();
_dbLookup.execute();
_xmlParseThread = new xmlAsync();
_xmlParseThread.executeOnExecutor(_dbLookup.THREAD_POOL_EXECUTOR
,"http://www.nothing.com", null);
}
For your update question : it is explained in the docs
Basically just to avoid all problems that may come from multithreading like intereference ....
One thing that I would like to know, and it might actually fix your issue, is where are you instantiating the instance of your class and calling the execute() method? If you read the documentation for AsyncTask, both of those operations need to take place on the main UI thread. If you are creating your object and calling execute from some other thread, then onPreExecute might fire, I'm not 100% certain here, but the background thread won't be created and executed.
If you are creating the instance of your AsyncTask from a background thread, or some other operation not taking place on the main UI thread, you could consider using the method:
Activity.runOnUiThread(Runnable)
You would need access to an instance of your running Activity to call that method, but it will allow you to run code on the UI thread from some other code that isn't running on the UI thread.
Hope that makes sense. Let me know if I can help more.
David
Android is Brutal! I can't believe this, what flakey implementation that changes from day to today. One day its a single thread, the next its 5 the other is 128.
Anyways here is a nearly drop in replacement for the stock AsyncTask. You can even call it AsyncTask if you wanted to, but to avoid confusion its called ThreadedAsyncTask. You need to call executeStart() instead of execute because execute() is final.
/**
* #author Kevin Kowalewski
*
*/
public abstract class ThreadedAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
public AsyncTask<Params, Progress, Result> executeStart(Params... params){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
return executePostHoneycomb(params);
}else{
return super.execute(params);
}
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private AsyncTask<Params, Progress, Result> executePostHoneycomb(Params... params){
return super.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
}
I know this may be really late for the thread, but there is a reason why it won't work on later android emulators. When asynctask was introduced android only let you run one at a time, then sometime later, im not sure which version, they allowed you to run multiple asynctasks at once, this caused issues in alot of apps,and so in Honeycomb+ they reverted to only allowing one asynctask to run at a time. Unless you manually change the thread pool.
Hope that clears one or two things up for people.
i think its the sdk. i had the same problem, and after changing target sdk from 15 to 11, everything works perfectly.
with sdk15, even though the AsyncTask.Status is RUNNING, the doInBackground is never called. i do think it has something to do with the ui thread though.
Based on Matthieu's answer, below an helper class to execute your AsyncTask correctly depending of the SDK version in order to avoid to duplicate code in your application:
import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Build;
public class AsyncTaskExecutor<Params, Progress, Result> {
#SuppressLint("NewApi")
public AsyncTask<Params, Progress, Result> execute(final AsyncTask<Params, Progress, Result> asyncTask, final Params... params){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
return asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
} else{
return asyncTask.execute(params);
}
}
}
Example of use:
public class MyTask extends AsyncTask<Void, Void, List<String>> {
...
final MyTask myTask = new MyTask();
new AsyncTaskExecutor<Void, Void, List<String>>().execute(myTask);
I need to perform a series of http requests, each of which may depend on a previous http response. I have been able to achieve this using an AsyncTask "tree" of sorts, but as the decision tree grows, the AsyncTask technique grows more unwieldy.
I think that somehow using a SynchronousQueue (or other type of queue) is the best approach, but I can't seem to find any good guidance or tutorials on how to use a Queue for something like http requests.
Can anyone provide any guidance or point to any good tutorials on using SynchronousQueue or suggest the best kind of Queue?
Use a java.util.concurrent.SingleThreadExecutor and make a Runnable out of each HTTP operation and result-handler. You can submit subsequent tasks to it as you determine whether you need to continue progress.
For example, the HTTP "task" would run and submit the Result "task" on success, or the Error "task" on failure. The Result task would in-turn submit another HTTP task when it was done processing. Using SingleThreadExecutor ensures only one task runs at-a-time.
You could use a ThreadPoolExecutor if you can handle multiple operations in-flight at once.
Take all that, and wrap it in an AsyncTask that manages the top-level "kick-off" and waits for everything to complete. It would probably be useful to have a ConditionVariable or something to synchronize the "end" signal (using a Done "task") so you can safely tear down the Executor.
A SynchronousQueue doesn't do anything helpful for you here, because it leaves you to do all the tread management. If you use an Executor that is all handled and all you deal with is Runnables and Futures. That's probably why you are not finding any tutorials. Anyway, the Executors all use one of those queue implementations underneath!
As requested, here is some skeleton Java code. Unsupported untested as-is. This should get you started. You can use a different synchronization object if you don't like ConditionVariable.
This is a generic technique, not specific to Android, feel free to use it in other contexts.
This functions as a State Machine, with HttpTask et al forming the states, and the transitions are hard-coded by submitting the Next State to the ExecutorService. There's even a "Big Bang at the end, so everyone knows when to clap" in the form of the ConditionVariable.
Some may consider DoneTask and FailedTask overkill, but it keeps the Next State mechanism consistent, and lets Future<? extends ResultTask> function as a somewhat type-safe container for the results, and certainly keeps you from mis-assigning to it.
abstract class BasicTask {
final ExecutorService es;
final ConditionVariable cv;
public BasicTask(ExecutorService es, ConditionVariable cv) {
this.es = es;
this.cv = cv;
}
}
abstract class HttpTask extends BasicTask {
// source omitted.
// you should make a class to prepare e.g. Apache HTTP resources for specific tasks (see below).
}
abstract class ResultTask implements Runnable {
final ConditionVariable cv;
public ResultTask(ConditionVariable cv) {
this.cv = cv;
}
public void run() {
cv.open();
}
}
final class FailedTask extends ResultTask {
final Exception ex;
public FailedTask(ConditionVariable cv, Exception ex) {
super(cv);
this.ex = ex;
}
public Exception getError() { return ex; }
}
final class DoneTask<T> extends ResultTask {
final T results;
public DoneTask(ConditionVariable cv, T results) {
super(cv);
this.results = results;
}
public T getResults() { return results; }
}
class HttpSequence extends AsyncTask<Void,Void,Object> {
// this will capture the ending task
Future<? extends ResultTask> result;
// this is an inner class, in order to set Result. Refactor so these are small.
// if you don't like inner classes, you still need to arrange for capturing the "answer"
final class SomeHttpTask extends HttpTask implements Runnable {
public void run() {
try {
final SomeType thisStep = doTheStuff(lastStep);
if(thisStep.isDone()) {
// we are done here
result = es.submit(new DoneTask<SomeType>(cv, thisStep));
}
else if(thisStep.isFailed()) {
// not done: we can't proceed because of something in the response
throw thisStep.getError();
}
else {
// not done, everything is ok for next step
es.submit(new NextHttpTask(es, cv, thisStep));
}
}
catch(Exception ex) {
result = es.submit(new FailedTask(cv, ex));
}
}
}
final class TheFirstTask extends HttpTask implements Runnable {
// source omitted. just emphasizing you need one of these for each "step".
// if you don't need to set Result, this could be a static inner class.
}
#Override
public Object doInBackground(Void...) {
final ExecutorService es = Executors.newSingleThreadExecutor();
final ConditionVariable cv = new ConditionVariable(false);
try {
es.submit(new TheFirstTask(es, cv));
// you can choose not to timeout at this level and simply block until something happens...
final boolean done = cv.block(timeout);
if(!done) {
// you will need to account for unfinished threads, see finally section!
return new IllegalStateException("timed out waiting on completion!");
}
if(result != null) {
final ResultTask done = result.get();
if(done instanceof DoneTask) {
// pass SomeType to onPostExecute()
return ((DoneTask<SomeTYpe>)done).getResults();
}
else if(done instanceof FailedTask) {
// pass Exception to onPostExecute()
return ((FailedTask)done).getError();
}
else {
// something bad happened, pass it to onPostExecute()
return new IllegalStateException("something unexpected signalled CV!");
}
}
else {
// something bad happened, pass it to onPostExecute()
return new IllegalStateException("something signalled CV without setting result!");
}
}
catch(Exception ex) {
// something outside workflow failed, pass it to onPostExecute()
return ex;
}
finally {
// naive shutdown (doesn't interrupt running tasks): read JavaDoc on ExecutorService for details
es.shutdown();
}
}
#Override
public void onPostExecute(Object result) {
if(result instanceof SomeType) {
// success UI
}
else if(result instanceof Exception) {
// error UI
}
}
}
I can't say for sure without knowing the details of your use case, but you probably want to avoid the SynchronousQueue, as it will block the thread putting things into the queue until the listener thread takes it back out of the queue. If you were putting things in using the UI thread you'd be locking up the UI.
I think a BlockingQueue may suit your needs. The JavaDoc has a good producer-consumer example.
I have listed of products with different category. I have to sort them. Because of the queries, It is taking more time to load. Between two activities, the screen is coming black. I want to run the query in the background. How can I do that and how to use its result in main activity?
private class InsertTask extends AsyncTask {
String cat;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(String... params) {
Boolean success = false;
try {
category(cat);
success = true;
} catch (Exception e) {
if(e.getMessage()!=null)
e.printStackTrace();
}
return success;
}
#Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
}
private void category(String category) {
try{
Cursor1 = mDbHelper.fetchcategory(category);
}catch(Exception e){
Log.v("Excep", ""+e);
}
}
And when called
InsertTask task = new InsertTask();
task.execute();
I have listed the category in buttons. How can I get the values then?
You should use AsyncTask for that. And some more info.
Its good you have thought of AsyncTask. Firstly, you can declare this class as inner in you class activity (if you haven't previously did) and so you are able to access you view class members.
You can do this also by creating thread and one handler that will be used to update your UI components. Remember that if you use threads you'll need to lock/unlock your database object because of the thread safety(if any other thread is accessing the database for any reason). Read more about thread safety of dbs.
I was doing some searching myself, and I came across this read, its rather long but looks extremely helpful, with lots of code examples. (I bookmarked it for myself).
Threads, Async, and Handlers O MY!
But some form of threading is the ticket.
From Android dev.
(My favorite code snippet)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
//Do Work here
}
}).start();
}