0

我为 Android 编写了我的第一个 java 程序,它使用 OpenGL 绘制了一些 3D 函数 (f(x,y)),程序几乎完成了,但是我在显示和隐藏自定义进度条时遇到了问题,开发为 LinearLayout(我创建的)带有一些文本和进度条。我需要在计算 3dfunction 值之前和期间让 progressBarLL 可见。为此,我在 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;

然后我让 FuncSurf 及其构造函数进行表面的持久计算。我需要在计算之前显示我的 progressBarLL:

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);    
    }

问题是,当我从上面 Activity 中实现的 onClick 事件中调用函数 FuncSurf 构造函数时,它会导致在很短的时间内显示 progressBarLL,不幸的是在计算完成之后,而不是之前。换句话说,处理程序在 FuncSurf 构造函数未同时完成后处理消息。这可能是因为它是同一个线程?但是当从 Renderer 调用 FuncSurf() 构造函数时,一切正常:

class MyOpenGLRenderer implements Renderer {
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            funcSurf = new FuncSurf(steps); //progressBarLL shown OK

我的问题是如何可能巧妙地更正代码,以便在 FuncSurf() 构造函数中计算之前显示progressBarLL,无论我从哪里调用这个构造函数?我不能直接在 funcSurf 中使用 progressBarLL.setVisibility,因为当上面的 onSurfaceChanged(...) 调用时这不是 GUI 线程。对不起,我无法更清楚地解释问题。我期待着你的帮助。

4

2 回答 2

1

使用AsyncTask,它正是为这种情况而设计的(并且需要线程交互而不需要消息或类似的东西)。

  • onPreExecute()在 UI 线程中运行,使进度条可见。
  • doInBackground()在后台线程中运行长计算。定期打电话publishProgress()通知进度。
  • onProgressUpdate()在 UI 线程中运行,并推进进度条。
  • onPostExecute()在 UI 线程中运行,并使进度条不可见。

请参阅Keeping your App Responsive的文档,其中包含一个类似的示例(其中长时间运行的任务是网络操作)。

于 2014-06-02T16:24:14.820 回答
0

同时我找到了“线程构造”,它现在解决了这个问题。它强制在单独的线程中执行“长时间任务”,允许 GUI 线程继续并通过 Handler 刷新 GUI。对第一段代码和程序的小修改现在似乎可以正常工作:

Runnable run = new Runnable() 
{
    @Override
    public void run() {
        FuncSurf fs = new FuncSurf(steps);
        renderer.funcSurf =  fs;
    }
};       
Thread thr = new Thread(run);
thr.start();
于 2014-06-03T09:54:21.107 回答