I'm doing an application in which I have to show a sequence of pictures: The sequence is the follow:

A red X has to be shown for more or less 400 milliseconds;
An image called "Screenshot" has to be shown for more or less 500 milliseconds;
An image called "Noise" has to be shown for more or less 50 milliseconds;
The "Noise" image disappear to make space for an EditText.
The EditText is used to get the user data.

Here is my code:

public class Step1Training extends Activity {

    ImageFragment myImageFragment;
    InputFragment myInputFragment;
    Drawable cross;
    ImageView myImageView;
    EditText myEditText;
    int i, length;
    String rating;
    Handler handler;
    boolean continueTask;
    int[] screenshots = {
           R.drawable.googleplaybooks2,
           R.drawable.aldiko1,
           R.drawable.chaton2,
           R.drawable.cinetrailer1,
           R.drawable.fanpage1
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.step1_training);

        handler = new Handler();
        i = 0;
        length = screenshots.length;

        initUI();

        startThread();
    }

    private void initUI(){
        myImageFragment = (ImageFragment)getFragmentManager().findFragmentById(R.id.imageFragment);
        myInputFragment = (InputFragment)getFragmentManager().findFragmentById(R.id.inputFragment);

        myImageView = (ImageView)myImageFragment.getView().findViewById(R.id.screenshotImageView);
        myImageView.setImageResource(R.drawable.cross300x300);

        myEditText = (EditText)myInputFragment.getView().findViewById(R.id.ratingEditText);     
        myEditText.setVisibility(View.GONE);
    }

    private void startThread(){

        while(i<length){
            handler.postDelayed(new TaskScreenshot(i), 250);
            handler.postDelayed(new TaskNoise(), 750);
            handler.postDelayed(new TaskEditText(), 1000);

            myEditText.setOnKeyListener(new View.OnKeyListener(){
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if((keyCode == KeyEvent.KEYCODE_ENTER)) {
                        if(myEditText.getText().toString().equals("")){
                            Toast.makeText(getApplicationContext(), "Inserire un numero da 1 a 9", Toast.LENGTH_SHORT).show();
                            return false;
                        } else if (Integer.parseInt(myEditText.getText().toString()) >= 1 &&
                                Integer.parseInt(myEditText.getText().toString()) <= 9){
                            return true;
                        }
                    }
                    return false;
                }
            });
            System.out.println(i);
            i++;
        }   
    }

    @Override
    public void onBackPressed() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Attenzione")
        .setMessage("Sei sicuro/a di voler uscire dall'applicazione?\n" +
                "Confermando uscirai dall'applicazione e perderai \n" +
                "tutti i dati raccolti finora.")
        .setCancelable(false)
        .setNegativeButton("No",new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
            }
        })
        .setPositiveButton("Si", new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int whichButton)
            {
                Intent intent = new Intent(Intent.ACTION_MAIN);
                intent.addCategory(Intent.CATEGORY_HOME);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
            }
        });
        AlertDialog alert = builder.create();
        alert.show();
    }

    class TaskScreenshot implements Runnable{

        int j;

        public TaskScreenshot(int _i){
            this.j = _i;
        }

        @Override
        public void run() {
            System.out.println("Screenshot");
            myEditText.setVisibility(View.GONE);
            myImageFragment.getView().setVisibility(View.VISIBLE);
            myImageView.setImageResource(screenshots[j]);
            myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT;
            myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT;
        }
    }

    class TaskNoise implements Runnable{

        @Override
        public void run() {
            System.out.println("Noise");
            myImageView.setImageResource(R.drawable.noise);
            myImageView.getLayoutParams().width = LayoutParams.MATCH_PARENT;
            myImageView.getLayoutParams().height = LayoutParams.MATCH_PARENT;
        }
    }

    class TaskEditText implements Runnable{

        @Override
        public void run() {
            System.out.println("EditText");
            myEditText.setVisibility(View.VISIBLE);
            myImageFragment.getView().setVisibility(View.GONE);
        }
    }
}

When I run this activity, it shows the red X, the last screenshot of the array and the Noise image. The Logcat shows this:

0
1
2
3
4
Screenshot
Screenshot
Screenshot
Screenshot
Screenshot
Noise
Noise
Noise
Noise
Noise
EditText
EditText
EditText
EditText
EditText

What am I doing wrong in this loop? And, how can I stop the loop until the user put the data?
Thanks!

Dani AI

Generated

You are posting all of your runnables at almost the same timestamps. Inside the while loop each iteration schedules: Screenshot at now+250ms, Noise at now+750ms, EditText at now+1000ms. They execute in three tight bursts, so the last screenshot update wins and that is what you see in Logcat. In your v2, seeing only the 1st, 3rd, 5th image is because the Enter key fires twice (ACTION_DOWN and ACTION_UP); you call startThread(i+1) on both, so the index jumps by 2. Also, avoid blocking waits on the UI thread; contrary to , sleeping the main thread will freeze input and rendering.

Use one Handler and chain the steps. Advance to the next image only after a valid entry:

final Handler h = new Handler(Looper.getMainLooper());
int idx = 0;

void nextTrial() {
    if (idx >= screenshots.length) return;

    showCross(); // red X
    h.postDelayed(new Runnable() { public void run() {
        showScreenshot(screenshots[idx]);
        h.postDelayed(new Runnable() { public void run() {
            showNoise();
            h.postDelayed(new Runnable() { public void run() {
                showInput(); // EditText visible, ImageView hidden
                clearAndFocus(editText);
            }}, 50);
        }}, 500);
    }}, 400);
}

Handle submit once, and only on a single action:

editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        boolean enter = actionId == EditorInfo.IME_ACTION_DONE
            || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER
                && event.getAction() == KeyEvent.ACTION_UP);
        if (!enter) return false;
        String s = v.getText().toString().trim();
        if (!isValidRating(s)) { toast("Enter a number 1..9"); return true; }
        idx++;
        nextTrial();
        return true; // consume
    }
});

Tips:

  • Set the listener once (not inside each trial) and guard with a boolean if needed.
  • Call h.removeCallbacksAndMessages(null) in onPause/onDestroy to avoid stray updates.
  • Reset editText text/visibility each trial so state is clean.

Recommended Answers

All 2 Replies

I think the problem is that the tasks are running as threads, hence simultaneously. Rather than as runnables they should just be normal functions with a wait at the end of them. Since they are running inside another thread, it should not interfer with other processes/threads running in the environment.

I've updated my code:

private void startThread(final int i){
    if(i < length){

        handler.postDelayed(new TaskScreenshot(i), 250);
        handler.postDelayed(new TaskNoise(), 750);
        handler.postDelayed(new TaskEditText(), 1000);

        myEditText.setOnKeyListener(new View.OnKeyListener(){
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if((keyCode == KeyEvent.KEYCODE_ENTER)) {
                    if(myEditText.getText().toString().equals("")){
                        Toast.makeText(getApplicationContext(), "Inserire un numero da 1 a 9", Toast.LENGTH_SHORT).show();
                        return false;
                    } else if (Integer.parseInt(myEditText.getText().toString()) >= 1 &&
                        Integer.parseInt(myEditText.getText().toString()) <= 9){
                        System.out.println(i);
                        startThread(i+1);
                        return true;
                    }
                }
                return false;
            }
        });

    }   
}

It partially works; I have five pictures and with this code it shows the 1°, 3° and 5° image. Why? Is there something wrong with the index?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.