Question

Basically I have created a Blackjack app that uses several methods that get called and pass a long the information that is needed (about cards and actions). I have 2 buttons displayed on screen that are click able (hit and stand). Now I have a method called player turn... and this is when I (through static ints) have if a button is selected, things will happen. However I did this with an infinite while loop thinking it will just keep checking to see if a button is pressed and then only do action when a button is pressed. This isn't working as my screen is not refreshing after each textview or imageview change thus as soon as I hit start game the game appears to "freeze" (being due to the method never ending) and I am therefore unable to click said buttons. Is there a way to call something similar to keyboard listener in java (Which pauses activity and waits for user input), in android? If not, what would you suggest the workaround be? Lastly (though not as currently important) how would I properly refresh everything after each change (I believe I need to use invalidate.. though I'm not sure what to have before invalidate so it refreshes the whole thing)? Thanks a bunch in advance.

Was it helpful?

Solution

Android will run an event loop for you - so you don't have to loop around waiting for input yourself.

You can hook into the loop in a number of ways. From 1.6 onwards the easiest way to do this is to specify the hook in your XML, e.g:

<Button android:onClick="myClickHandler" />

Alternatively you can do this in code by calling setOnClickListener.

Take a look at http://android-developers.blogspot.com/2009/10/ui-framework-changes-in-android-16.html for some examples (read the section headed "Easier click listeners")

If you can invalidate on your view then the Android event loop will take care of re-drawing the screen, including any layout changes. If you have custom View's their onDraw() will be called as appropriate.

Hope this helps.

OTHER TIPS

Looks like a new Activity (invoked by startActivityForResult), and a Handler (called from the onActivityResult) could solve your problem.

Take a look at the design-snippet bellow:

activity interactions

Let's say the method you are willing to 'sleep' is the doSomething from the MainActivity class. I assume this is invoked from some event handler implementation. You should move all the calls from that method into the BackgroundActivity activity, - which should show a ProgressDialog and/or nothing else -.
In your doSomething method you should start an activity by an intent pointing to the BackgroundActivity with

this.startActivityForResult(new Intent(this, BackgroundActivity.class), 
    BG_ACTIVITY_ID);

where BG_ACTIVITY_ID is your unique identifier for the started activity, so when it finishes, you can handle it.

Inside the processBackgroundData (or when the background activity is finished processing), you should set the result before calling finish():

final Intent intent = new Intent();
intent.putExtra(KEY_FOR_DATA_YOU_NEED, dataYouNeed);
setResult(Activity.RESULT_OK, intent);
finish();

In your MainActivity you should also override the onActivityResult method, to retrieve the necessary information from the finished BackgroundActivity task:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);
    //you might also want to check if the resultCode is `Activity.RESULT_OK`...
    switch (requestCode)
    {
        case BG_ACTIVITY_ID:
            //get the data you need 
            final String dataYouNeed = data.getStringExtra(KEY_FOR_DATA_YOU_NEED);
            //process the data...
            //if necessary (threads!), call your backgroundHandler's 
            //sendMessage with the retrieved informations as obj.parameters
        [...]
            break;
        default:
            [...]
            break;
    }
}

And inside your BackgroundHandler's handleMessage method (since you are back to the ui thread: the thread in which your main application is running) you can do all the necessary ui modifications, and also listen forward for the user events.

This way you are getting rid of the infinite loop, and can always be aware of user interactions.

The Activity Callback Routines WAIT for the last Event Listener... Could this be an Easy Solution??

This "wait for user input" question is a question that comes up regularly, has puzzled me as well, and I haven't as yet seen what looks to me like a real clean solution.

I came up with an idea, recently, but I'm pretty green at the Android game and I want to see how it holds up to scrutiny.

The technique is based on the idea that the activity callback routines do not complete as long as there is an event listener that continues to listen. As a result, the callback routine executes the last statement, and then does nothing but does not end. (IOW, "you can check out any time you want, but you can never leave....until the event listeners let you." Yuk.)

This seems to fit the requirements. The UI is not frozen and there is no infinite loop. The only demand on the UI is that it sustain the event listner. When the user supplies the input, the event callback routine, i.e. onKey, handles the input, and then does ALL THE STEPS REQUIRED BEFORE THE NEXT user input is needed. Then the event callback routine sets a new listener and returns, releasing the old listener, and leaving the UI with one task -- sustain the new listener. This continues iteratively until the activity callback routine is completed.

Here is some code I tested:

@Override   
    public void onCreate(Bundle savedInstanceState) {       
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main);
    }

         public void onStart() {
           super.onStart();

        final EditText et = (EditText) findViewById(R.id.edittext);
        et.setOnKeyListener(new OnKeyListener() {    
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                    boolean tf = checKey(keyCode, event);
                    if(tf==false)return false;
                    gotPW();
                    return true;
            }
        });
    }


         gotPW(){
               ...do ALL the stuff you want to do before you need more user input
               ...set ANOTHER event listener that is connected to another 
                  event callback method

               ...return, releasing the first event listener, and putting the onStart 
                  routine back in its same state -- nothing to do except to attend to 
                  an event listener.
         }



         //this checks to see if the enter key has been hit
         public boolean checKey(int keyCode, KeyEvent event){   
       if ((event.getAction() == KeyEvent.ACTION_DOWN) && 
                (keyCode == KeyEvent.KEYCODE_ENTER)) 
    {          
        return true;        
    }        
    return false;    
}

The foregoing code seems to do what is required...onStart waited for my input.

Is this a good technique?

Are there problems I haven't identified?

Has everybody been doing this all along, and only newbies like myself think they are on to something?

Hm I might have the wrong interpretation but it seems that doing setOnClickListener has it so that when that certain part of the code is reached, the button becomes clickable and actions are taken when the button is clicked? I already have it so that when a button is clicked and it's Player's turn, actions will occur. However what I need to know is how to have the program literally wait or pause until one of the buttons are pressed.

Similar to when you incite a keyboard and java waits for keyboard input to be made.

Do Not Poll to see if your button has been pressed. Just do whatever it is you want done in the OnClickHandler.

Here's an example of what your code might look like (The Wrong Way):

while(1) {
  if (buttonHitClicked()) {
    doHit();
  } else if (buttonStandClicked()) {
    doStand();
  }
  //sleep(); // won't help
}

And here's the right way:

OnClickListener hitListener = new OnClickListener() {
  public void onClick(View v) { doHit(); }
};
OnClickListener standListener = new OnClickListener() {
  public void onClick(View v) { doStand(); }
};

protected void OnCreate(Bundle savedValues) {
  ...

  Button hitButton = (Button)findViewById(R.id.hitButton);
  button.setOnClickListener(hitListener);

  Button standButton = (Button)findViewById(R.id.standButton);
  button.setOnClickListener(standListener);

  ...
}

Yes, the Right Way involves a bit more typing... but it also works. And if you look at the link Collin posted, there's a less "type-y" way to do it that involves adding stuff to your AndroidManifest file. You just point it at a functions in your class with the right signature (public void funcName(View v) as I recall), and Android handles all the listener stuff for you.

As far as "making your program wait", it already is. Your program code isn't running until some call is made to one of your classes' entry points. Until then, execution is floating around in Android's UI handler code in your process, passing messages to and fro. As soon as one of those messages ends up in your app, (onCreate, a click listener, etc) your code does it's thing and returns, allowing that UI thread to go back to handling all the input for your app's process.

And if your app takes longer than 5 seconds or so to respond to a message, it'll be killed by the system, with an "ANR"... App Not Responding.

Another handy Google IO video entitled "Writing Zippy Android Apps".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top