My requirement is to have a thread that maintains a socket connection between a BlackBerry device and a server and exchanges commands, similar to request and response.
My problem is that I need to have this thread running in the background all the time and keep the UI available to the user. So, when there is a command from the server, this thread parses it and updates the UI and also if there's an action from the BlackBerry user, it sends it to the server and the server in turn handles it.
I developed the same application in Android using AsyncTask
and it's working well. But in BlackBerry, as there's no such class, I used the invokeLater() option. The communication works fine between the server and the BB device, but the UI is frozen on the BlackBerry.
Anyone have any idea how to get this right?
Vishal is on the right track, but a little more is needed to match Android's AsyncTask
. Since enums and generics aren't available with Java 1.3 on BlackBerry, you can't match the Android API perfectly.
But, you could do something like this (not tested ... this is just a starting point for you):
import net.rim.device.api.ui.UiApplication;
public abstract class AsyncTask {
public static final int FINISHED = 0;
public static final int PENDING = 1;
public static final int RUNNING = 2;
private int _status = PENDING;
private boolean _cancelled = false;
private Thread _worker;
/** subclasses MUST implement this method */
public abstract Object doInBackground(Object[] params);
protected void onPreExecute() {
// default implementation does nothing
}
protected void onPostExecute(Object result) {
// default implementation does nothing
}
protected void onProgressUpdate(Object[] values) {
// default implementation does nothing
}
protected void onCancelled() {
// default implementation does nothing
}
protected void onCancelled(Object result) {
onCancelled();
}
public final int getStatus() {
return _status;
}
public final boolean isCancelled() {
return _cancelled;
}
public final boolean cancel(boolean mayInterruptIfRunning) {
if (_status == FINISHED || _cancelled) {
return false;
} else {
_cancelled = true;
if (mayInterruptIfRunning && _status == RUNNING) {
// NOTE: calling Thread.interrupt() usually doesn't work
// well, unless you don't care what state the background
// processing is left in. I'm not 100% sure that this is how
// Android's AsyncTask implements cancel(true), but I
// normally just cancel background tasks by letting the
// doInBackground() method check isCancelled() at multiple
// points in its processing.
_worker.interrupt();
}
return true;
}
}
protected final void publishProgress(final Object[] values) {
// call back onProgressUpdate on the UI thread
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
onProgressUpdate(values);
}
});
}
private void completeTask(final Object result) {
// transmit the result back to the UI thread
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
// TODO: not sure if status should be FINISHED before or after onPostExecute()
_status = FINISHED;
}
});
}
public AsyncTask execute(final Object[] params) throws IllegalStateException {
if (getStatus() != PENDING) {
throw new IllegalStateException("An AsyncTask can only be executed once!");
} else {
try {
onPreExecute();
_worker = new Thread(new Runnable() {
public void run() {
try {
// run background work on this worker thread
final Object result = doInBackground(params);
completeTask(result);
} catch (Exception e) {
// I believe if Thread.interrupt() is called, we'll arrive here
completeTask(null);
}
}
});
_status = RUNNING;
_worker.start();
} catch (Exception e) {
// TODO: handle this exception
}
}
return this;
}
}
Also, it's important to keep in mind the Threading Rules for Android's AsyncTask, which apply to the above implementation, too:
Threading rules There are a few threading rules that must be followed for this class to work properly:
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
You can create a Class that extends my implementation of class AsyncTask
. Good Luck :)
Here the methods onPreExecute
, onPostExecute
are executed on UI thread and doInBackground is called on worker thread. Since onPreExecute
, onPostExecute
are abstract you can override them and provide your implementation like showing and dismissing progress dialog.
The sequence in which methods get's executed is 1) onPreExecute 2) doInBackground 3) onPostExecute
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
public abstract class AsyncTask {
Runnable runnable;
Thread threadToRun;
public abstract void onPreExecute();
public abstract void onPostExecute();
public abstract void doInBackground();
public void execute() {
try {
runnable = new Runnable() {
public void run() {
// TODO Auto-generated method stub
UiApplication.getUiApplication().invokeLater(
new Runnable() {
public void run() {
// TODO Auto-generated method stub
onPreExecute();
}
});
doInBackground();
UiApplication.getUiApplication().invokeLater(
new Runnable() {
public void run() {
// TODO Auto-generated method stub
onPostExecute();
}
});
}
};
threadToRun = new Thread(runnable);
threadToRun.start();
} catch (Exception e) {
// TODO: handle exception
Dialog.alert("Async Error Occured. " + e.toString());
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With