Android for循环和延迟不同步

时间:2016-05-15 04:01:47

标签: android

简短摘要

我有一个活动游戏。用户将点击图片:

First level of game

Second level of game

用户有5秒钟的时间点击并选择正确的一个。 5秒后,正确的图像视图将以不同方式显示以引起注意,并在5秒后再次显示,用户将看到下一级别。

用户无需等待5秒即可点击,因此点击后应立即进入下一级别。

我正在动态创建视图和图像视图。图像视图从本地数据库sqlite作为字节进行编译。

我的方法是在oncreate方法中创建。我使用for或while循环。每次迭代都是一个游戏级别。每个级别都有不同的图像视图和不同的图像视图数。

为了延迟5 + 5秒,我不得不使用处理程序,线程,倒数计时器。每一个都造成了问题。

在使用处理程序时,当用户在5秒之前点击时,我无法终止当前会话。

我不知道这是否正确。

您可以在下面看到我的代码:

长期解释和代码

定时器:

nCreate() {
            for (int i = 0; i < 2; i++) {
                handler.postDelayed(new Runnable() {
                    public void run() {

                        imageAnswer.setImageBitmap(bmp);

                        imageAnswer.setId(R.id.imgAnswer);
                        //adding image to screen
                        finalRLayout.removeAllViews();
                        finalRLayout.addView(imageAnswer, rLayParams);

                        //starting timer, if no answer in 5 seconds, run again timer
                        startTimer();

                        //clicklisterner
                        imageAnswer.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                //if clicks true, cancel timer and go to next iteration of for loop
                                if (view == findViewById(R.id.imgAnswer)) {
                                    Log.d(TAG, "clicked");
                                    //PUT IN CODE HERE TO GET NEXT IMAGE
                                    cancelTimer();

                                } else { //if not true, run again timer for last chance
                                    Log.d(TAG, "nonclick");
                                    cancelTimer();
                                    startTimer();

                                }
                            }
                        });
                    }
                }, 2000 * i);


            } //for end

        } //oncreate end

    //start timer function
    void startTimer() {
        cTimer = new CountDownTimer(5000, 1000) {
            public void onTick(long millisUntilFinished) {
                Log.d(TAG, "ontick");
            }
            public void onFinish() {
                Log.d(TAG, "timer onfinish");
            }
        };
        cTimer.start();
    }


    //cancel timer
    void cancelTimer() {
        Log.d(TAG, "canceltimer");
        if (cTimer != null)
            cTimer.cancel();
    }

3个不同的线程操作但没有工作。其中一个屏幕进入黑屏。其他两个并没有阻止循环。

runnable version






    for ( int i = 0; i< 20 ; i++) {
            Log.d(TAG, "for i2="+ i);
            final int finalI = i;
            final RelativeLayout finalRLayout = rLayout;



            final Runnable r=new Runnable() {

                @Override
                public void run() {
                    Log.d(TAG, "for finali2="+ finalI);
                    TrainingObject trainingObject = new TrainingObject();
                    trainingObject = trainingObjectList.get(finalI);
                    objectCount = 2;
//test icin
                    Log.d(TAG,"testicin trainingobjectid: "+trainingObject.getTrainingobjectID());
                    object = dbHandler.getObjectObject(trainingObject.getTrainingobjectAnswer());




                    RelativeLayout.LayoutParams rLayParams = new RelativeLayout.LayoutParams(140,140);

                    rLayParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
                    rLayParams.addRule(RelativeLayout.CENTER_IN_PARENT);

                    imgBytes = object.getObjectImageBlob();
                    bmp = BitmapFactory.decodeByteArray(imgBytes, 0, imgBytes.length);

                    imageAnswer.setImageBitmap(bmp);
                    imageAnswer.setTag(trainingObject.getTrainingobjectAnswer());
                    imageAnswer.setId(R.id.imgAnswer);
                    finalRLayout.removeAllViews();
                    finalRLayout.addView(imageAnswer,rLayParams);

                }
            };
            Log.d(TAG, "3000i2 sonrasi");

            handler.postDelayed(r, 6000 * i);
            imageAnswer.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (view == findViewById(R.id.imgAnswer)) {
                        Log.d(TAG, "clicked");handler.removeCallbacks(r); handler.postDelayed(r, 0);
                        //PUT IN CODE HERE TO GET NEXT IMAGE

                    }
                    else{
                        Log.d(TAG, "nonclick");
                        handler.removeCallbacks(r);  handler.postDelayed(r, 6000);

                    }
                }
            });

        }//for end

2 个答案:

答案 0 :(得分:3)

你可以简单地使用handler来实现你的目的,你应该做的是创建一个runnable并在处理程序之外声明它然后在postDelayed处理程序中使用它的名字,如果用户点击了,只需删除所有处理程序回调:

// first create runnable
Runnable r = new Runnable{
    public void run(){
         //do what you need to do after 5 seconds
    }
}

// then create handler
Handler mHandler = new Handler();

// then in your onCreate method
nCreate() {
        for (int i = 0; i < 2; i++) {
            handler.postDelayed(new Runnable() {
                public void run() {

                    imageAnswer.setImageBitmap(bmp);

                    imageAnswer.setId(R.id.imgAnswer);
                    //adding image to screen
                    finalRLayout.removeAllViews();
                    finalRLayout.addView(imageAnswer, rLayParams);

                    //starting handler, if no answer in 5 seconds, run again timer
                    mHandler.postDelayed(r, 5000);

                    //clicklisterner
                    imageAnswer.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            //if clicks true, cancel timer and go to next iteration of for loop
                            if (view == findViewById(R.id.imgAnswer)) {
                                Log.d(TAG, "clicked");
                                //PUT IN CODE HERE TO GET NEXT IMAGE
                                myHandler.removeCallbacks(r);

                            } else { //if not true, run again timer for last chance
                                Log.d(TAG, "nonclick");
                                // stop the handler
                                myHandler.removeCallbacks(r);
                                // run a new one
                                mHandler.postDelayed(r, 5000);

                            }
                        }
                    });
                }
            }, 2000 * i);


        } //for end

    } //oncreate end

答案 1 :(得分:2)

对于游戏开发,您应该使用更专业的东西来实现您的游戏,我建议您阅读本书Beginning Android Games 2nd Edition它具有2D和3D游戏的基础知识,您可以从中学习各种选项。 现在为您的代码我建议您在外部线程上跟踪时间,并使其回调到您在主游戏活动中实现的界面 示例:

<强> TimeThread.java

import android.util.Log;

public class TimeThread implements Runnable {
    Thread thread = null;

    TimeTickListener listener;
    volatile boolean running = false;

    public TimeThread(TimeTickListener listener) {
        this.listener = listener;

    }

    public void resume() {

        thread = new Thread(this);
        running = true;
        if (thread != null)
            thread.start();
    }

    @Override
    public void run() {

        while (running) {
            // sending callbacks to the mainActivity 
            listener.onTimeTick();

        }
    }

    public void pause() {
        running = false;
        while (true) {
            try {
                thread.join();
                Log.v("my", "joined ");
                break;
            } catch (InterruptedException e) {
                Log.v("my", "not joined cause : " + e.getMessage());

            }

        }

    }

}

我们使用的界面:

public interface TimeTickListener {
public void onTimeTick();
}

以下是mainActivity的示例:

<强> MainActivity.java

public class MainActivity extends Activity implements TimeTickListener {

    long startTime = System.nanoTime();
    // the interface  method that we implemented 
    @Override
    public void onTimeTick() {
         // keep trace of the time untill it sums up to 1 sec then do an action
         // in your situation you can make it to count 5 sec 
         // and make your action here
        if ((System.nanoTime() - startTime) / 1000000000 >= 1) {

            totalTime += 1;

            // this handler is because you should change the textView from its
            // original thread
            // and it is not allowed to be edited from another thread
            // in your case you should change the imageViews like this in the main thread 
            mainHandler.post(new Runnable() {

                @Override
                public void run() {
                    text.setText(totalTime + " seconds passed ");
                }
            });

            startTime = System.nanoTime();

//          and this is how to terminate the thread manually (optional)
            if (totalTime >= 10) {

                timeThread.pause();
            }

        }

    }

    Handler mainHandler;
    TextView text;
    float totalTime = 0;
    TimeThread timeThread;
    TimeTickListener listener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        text = new TextView(this);
        text.setText("wait...");
        setContentView(text);
// initializing the handler with the main activity looper 
        mainHandler = new Handler(getMainLooper());
//getting our implemented listener to pass it to the timeThread for the callbacks
        listener = (TimeTickListener) this;
        timeThread = new TimeThread(listener);
        // resume method will launch the thread and make it start calling the interface method (onTimeTick)
        timeThread.resume();

    }

    @Override
    protected void onPause() {      

//      don't forget to pause the thread here 
        timeThread.pause();
        super.onPause();
    }
}

此代码已经过测试并取得了巨大成功,时间准确且同步得很好。

然而,它有点复杂,占用资源,因为第二个线程中的while循环有很多优点,可以让你正确控制你的应用程序。

这个答案是为了获得准确的时间,如何处理时间跟踪线程以及在何处进行操作但是如果您遇到游戏逻辑问题或者很难隐藏并在这种情况下向用户显示图像不是你想要的答案所以告诉我,我会尽力帮助你。