I write my first java program for Android which draws some 3D functions (f(x,y)) using OpenGL, and the program is almost done but I experience problems with showing and hiding custom progress bar, developed as LinearLayout (which I created) with some text and progressBar. I need do make progressBarLL visible before and during calculating 3dfunction values. To do this I implemented a handler in Graph3dActivity:
public class Graph3dAct extends Activity {
(...)
static ProgressBar progressBarPB;
static LinearLayout progressBarLL;
public static Handler progressHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.e("HANDLER:",Integer.toString(msg.arg1));
//toneG.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 500);
switch (msg.arg1)
{
case 1: progressBarLL.setVisibility(LinearLayout.VISIBLE);
break;
case 2: progressBarLL.setVisibility(LinearLayout.INVISIBLE);
break;
case 3: progressBarPB.setProgress(msg.arg2);
//to be implemented
break;
default: Log.e("Graph3dAct","Handler misused;");
}
progressBarLL.invalidate();
progressBarPB.invalidate();
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
progressBarPB = (ProgressBar) findViewById(R.id.surface3dPB);
progressBarLL = (LinearLayout) findViewById(R.id.progressLL);
(...)
final Button moreStepsB = (Button) findViewById(R.id.buttonMoreS);
moreStepsB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int max=stepsVals.length-1;
if (stepsIndex<max)
{
stepsIndex++;
steps=stepsVals[stepsIndex];
FuncSurf fs = new FuncSurf(steps);
renderer.funcSurf = fs;
Then I have FuncSurf with its constructor doing long-lasting calculation of surface. I need to show my progressBarLL before calculations:
public class FuncSurf {
public FuncSurf(int steps_) {
Log.e("FuncSurf","CONSTRUCTOR");
Message msg = new Message();
msg.arg1=1; //instruct handler to show progress layout: progressBarLL
Graph3dAct.progressHandler.sendMessage(msg);
(...) HERE GOES LONG-LASTING CALCULATION
msg = new Message();
msg.arg1=2; //instruct handler to hide progress layout: progressBarLL
Graph3dAct.progressHandler.sendMessage(msg);
}
The problem is that when I call function FuncSurf constructor from onClick event implemented in above Activity, then it results in showing progressBarLL for very short time and unfortunatelly after calculation is done, not before. In other words handler handles messages after FuncSurf contructor is finished not simultaneously. This is probably because it is the same thread? But when the FuncSurf() constructor is called from Renderer everything is OK:
class MyOpenGLRenderer implements Renderer {
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
funcSurf = new FuncSurf(steps); //progressBarLL shown OK
My question is how to possibly neatly correct the code so that progressBarLL is shown before calculations in FuncSurf() constructor regardless from where I call this constructor? I cannot directly use progressBarLL.setVisibility in funcSurf because this is not GUI thread when called by onSurfaceChanged(...) above. I'm sorry I couldn't explain the problem clearer. I look forward to your help.
Use
AsyncTask
, it's designed for exactly this case (and takes case of thread interaction without needing messages or anything like that).onPreExecute()
runs in the UI thread, makes the progress bar visible.doInBackground()
runs the long calculation in a background thread. Regularly callspublishProgress()
to notify progress.onProgressUpdate()
runs in the UI thread, and advances the progress bar.onPostExecute()
runs in the UI thread, and makes the progress bar invisible.See the documentation for Keeping your App Responsive, it includes a similar example (in which the long-running task is a network operation).