For the past few days, I've been getting up to speed with concurrent thread execution in Java, namely for Android.
I only just stumbled on to this excellent blog post on the topic. I will therefore organise the rest of this post in reference to the link - do read it!
Threading as per Android Docs.
The developer documentation states,
public class MyActivity extends Activity {
[ . . . ]
// Need handler for callbacks to the UI thread
final Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResultsInUi();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
[ . . . ]
}
protected void startLongRunningOperation() {
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
mResults = doSomethingExpensive();
mHandler.post(mUpdateResults);
}
};
t.start();
}
private void updateResultsInUi() {
// Back in the UI thread -- update our UI elements based on the data in mResults
[ . . . ]
}
}
You'll find a working demo of this with useful debug info posted to LogCat; the raw source will implement as Runnable, which is typically preferred.
FORK IT!: Source @Github
Handler: run the new thread and use the handler to post a runnable which updates the GUI.
The important bits are shown below
final Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
if (msg.what==0){
Log.d(this.getLooper().getThread().getName(), "mHandler");
Toast.makeText(getApplicationContext(), "Whooo: " + msg.what, Toast.LENGTH_LONG).show();
}
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textOutput = (TextView)findViewById(R.id.textOutput);
buttonPush = (Button)findViewById(R.id.buttonPush); // Get button from xml
buttonPush.setOnClickListener(this);
}
public void onClick(View v) {
switch(v.getId()){
case R.id.buttonPush:
startLongRunningOperation();
default:
break;
}
}
protected void startLongRunningOperation() {
// DISPLAYING UR PROGRESS DIALOG
final ProgressDialog backgroundTask = ProgressDialog.show(this, "", "Loading", true);
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
try {
Log.d(this.getName(),"bound to "+mHandler.getLooper().getThread().getName());
mResults = doSomethingExpensive();
// Create runnable for posting
mHandler.post(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
updateResultsInUi(mResults);
}
});
backgroundTask.dismiss();
}catch (Exception e){
//TODO
}
Log.d(this.getName(),"sending message to "+mHandler.getLooper().getThread().getName());
mHandler.sendEmptyMessage(0);
}
};
t.start();
}
private void updateResultsInUi(int mResults) {
// Back in the UI thread -- update our UI elements based on the data in mResults
textOutput.setText("Received: " + mResults);
}
private int doSomethingExpensive(){
try {
Log.d(Thread.currentThread().getName(), "background operation starting");
Thread.sleep(1000);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return(RESULT_OK);
}
}
FORK IT!: Threading 3 @ Github
Looper
Just completed! I should be able to setup the pipeline thread pattern as long as I can hook into the same thread, rather than spawning new threads on each onClick() event.
FORK IT!: Threading 4 @ Github
Pipeline Thread Execution
Pipelining: My Way
This is completely my own work, and was based on Threading 4 above. The idea behind this approach was to instantiate a single thread, and then assign tasks to that thread. On each click, the same thread is used, much rather than spawning new threads. Do notice the much larger code overhead to achieve this pipeline concurrency pattern.
FORK IT!: Threading 5 @ Github
Ivan's Approach: Great for learning!
This example is largely based on Ivan's code; I cut it down into a far more generic model that's easier to digest. It sets up a single pipeline thread.
Ivan's code is setup to span four .java files; I was able to shrink this down to two so far. However, at circa 250 lines of code it still does seem like much to achieve pipelining.
FORK IT!: Threading 2 @ Github