Как заставить метод приостановить и ждать ввода с Android?

По сути, я создал приложение Blackjack, которое использует несколько методов, которые вызываются и передают длинную информацию, которая необходима (о картах и ​​действиях). У меня есть 2 кнопки, отображаемые на экране, которые можно нажимать (нажимать и стоять). Теперь у меня есть метод под названием Player Turn... и это когда у меня (через статические целые) есть, если кнопка нажата, вещи будут происходить. Однако я сделал это с бесконечным циклом, думая, что он будет просто проверять, нажата ли кнопка, а затем выполнять действия только при нажатии кнопки. Это не работает, так как мой экран не обновляется после каждого изменения текстового представления или изображения, поэтому, как только я нажимаю стартовую игру, игра "зависает" (из-за того, что метод не заканчивается), и поэтому я не могу нажать на указанные кнопки., Есть ли способ вызвать что-то похожее на прослушиватель клавиатуры в Java (который приостанавливает активность и ждет ввода пользователя), в Android? Если нет, что бы вы предложили в качестве обходного пути? И наконец (хотя и не так важно, как сейчас), как бы я правильно обновлял все после каждого изменения (я считаю, что мне нужно использовать аннулировать... хотя я не уверен, что нужно иметь до аннулирования, чтобы оно обновляло все)? Большое спасибо заранее.

5 ответов

Решение

Android запустит цикл обработки событий для вас, так что вам не придется зацикливаться на ожидании ввода самостоятельно.

Вы можете подключиться к циклу несколькими способами. Начиная с версии 1.6, самый простой способ сделать это - указать хук в вашем XML, например:

Подпрограммы обратного вызова Activity ждут последнего прослушивателя событий... Может ли это быть простым решением?

Этот вопрос "ожидания ввода пользователя" - это вопрос, который регулярно возникает, меня также озадачивает, и я еще не видел, что мне кажется реальным чистым решением.

Недавно у меня возникла идея, но я довольно зелен в игре для Android и хочу посмотреть, насколько она выдерживает проверку.

Техника основана на идее, что подпрограммы обратного вызова активности не завершаются, пока есть прослушиватель событий, который продолжает слушать. В результате подпрограмма обратного вызова выполняет последний оператор, а затем ничего не делает, но не завершается. (IOW, "вы можете проверить в любое время, когда захотите, но вы никогда не сможете уйти… пока слушатели событий не позволят вам". Юк.)

Это, кажется, соответствует требованиям. Пользовательский интерфейс не заморожен и нет бесконечного цикла. Единственным требованием к интерфейсу пользователя является поддержка списка событий. Когда пользователь вводит данные, процедура обратного вызова события, то есть onKey, обрабатывает ввод, а затем выполняет ВСЕ ШАГИ, ТРЕБУЮЩИЕ ПЕРЕД СЛЕДУЮЩИМ пользовательским вводом. Затем процедура обратного вызова события устанавливает нового слушателя и возвращает его, освобождая старого слушателя и оставляя пользовательский интерфейс с одной задачей - поддерживать нового слушателя. Это продолжается итеративно, пока не будет завершена процедура обратного вызова активности.

Вот код, который я протестировал:

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

Вышеупомянутый код, кажется, делает то, что требуется...onStart ждал моего ввода.

Это хорошая техника?

Есть ли проблемы, которые я не определил?

Все ли этим занимались все время, и только новички вроде меня думают, что они к чему-то?

Выглядит как новый Activity (вызывается startActivityForResult) и Handler (вызывается из onActivityResult) может решить вашу проблему.

Взгляните на дизайн-фрагмент ниже:

взаимодействия деятельности

Скажем, метод, который вы хотите "спать", это doSomething от MainActivity учебный класс. Я предполагаю, что это вызывается из некоторой реализации обработчика событий. Вы должны переместить все вызовы из этого метода в BackgroundActivity активность, - которая должна показывать ProgressDialog и / или ничего другого -.
В вашем методе doSomething вы должны начать действие с намерения, указывающего на BackgroundActivity с

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

где BG_ACTIVITY_ID - ваш уникальный идентификатор запущенного действия, поэтому, когда оно заканчивается, вы можете его обработать.

Внутри processBackgroundData (или когда фоновая активность завершена), вы должны установить результат перед вызовом finish():

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

В вашей MainActivity вы также должны переопределить onActivityResult метод, чтобы получить необходимую информацию из законченной задачи BackgroundActivity:

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

И внутри вашего BackgroundHandler"s handleMessage Метод (поскольку вы вернулись к потоку пользовательского интерфейса: потоку, в котором работает ваше основное приложение), вы можете выполнить все необходимые изменения пользовательского интерфейса, а также прослушивать события пользователя.

Таким образом, вы избавляетесь от бесконечного цикла и всегда можете быть в курсе взаимодействия с пользователем.

Хм, у меня может быть неправильная интерпретация, но кажется, что выполнение setOnClickListener имеет его так, что, когда достигается определенная часть кода, кнопка становится доступной для нажатия и действия выполняются при нажатии кнопки? У меня уже есть так, что когда нажата кнопка и наступает ход игрока, действия будут происходить. Однако мне нужно знать, как заставить программу буквально ждать или останавливаться, пока не будет нажата одна из кнопок.

Аналогично тому, когда вы настраиваете клавиатуру, а Java ждет ввода с клавиатуры.

Не опрашивать, чтобы увидеть, была ли нажата ваша кнопка. Просто делайте все, что хотите, в OnClickHandler.

Вот пример того, как может выглядеть ваш код (The Wrong Way):

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

И вот правильный путь:

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

  ...
}

Да, "Правильный путь" включает в себя немного больше печатания... но это также работает. И если вы посмотрите на ссылку, опубликованную Коллином, есть менее "тип-у" способ сделать это, который включает добавление материала в ваш файл AndroidManifest. Вы просто указываете на функции в вашем классе с правильной подписью (public void funcName(View v) насколько я помню), а Android обрабатывает все слушатели за вас.

Что касается "ожидания вашей программы", то это уже так. Код вашей программы не будет запущен, пока не будет сделан какой-либо вызов в одну из точек входа ваших классов. До тех пор выполнение в вашем процессе обрабатывается кодом обработчика пользовательского интерфейса Android, передавая сообщения туда и обратно. Как только одно из этих сообщений попадает в ваше приложение (onCreate, прослушиватель кликов и т. Д.), Ваш код делает свое дело и возвращает его, позволяя потоку пользовательского интерфейса вернуться к обработке всего ввода для процесса вашего приложения.

И если вашему приложению потребуется более 5 секунд, чтобы ответить на сообщение, оно будет убито системой с "ANR"... Приложение не отвечает.

Еще одно удобное видео от Google IO под названием "Написание приложений для Android Zippy".

Другие вопросы по тегам