【问题标题】:How to have a method pause and wait for input with Android?如何让方法暂停并等待 Android 输入?
【发布时间】:2011-04-30 18:04:25
【问题描述】:

基本上,我已经创建了一个 Blackjack 应用程序,该应用程序使用了几种方法,这些方法被调用并长时间传递所需的信息(关于卡片和操作)。我在屏幕上显示了 2 个可点击的按钮(点击和站立)。现在我有一个名为 player turn...但是,我使用无限循环执行此操作,认为它只会继续检查是否按下按钮,然后仅在按下按钮时执行操作。这不起作用,因为我的屏幕在每次 textview 或 imageview 更改后没有刷新,因此一旦我点击开始游戏,游戏就会出现“冻结”(由于方法永无止境),因此我无法点击所述按钮.有没有办法在android中调用类似于java中的键盘监听器(暂停活动并等待用户输入)?如果不是,您建议的解决方法是什么?最后(虽然目前不重要)我将如何在每次更改后正确刷新所有内容(我相信我需要使用 invalidate.. 虽然我不确定在 invalidate 之前有什么所以它会刷新整个事情)?提前致谢。

【问题讨论】:

  • 啊,我也有这个问题,还没想明白..

标签: java android onclick buttonclick blackjack


【解决方案1】:

看起来像一个新的Activity(由startActivityForResult 调用)和一个Handler(从onActivityResult 调用)可以解决您的问题。

看看下面的design-sn-p:

假设您愿意“睡眠”的方法是来自MainActivity 类的doSomething。我假设这是从某个事件处理程序实现中调用的。您应该将该方法中的所有调用移至BackgroundActivity 活动中, - 应该显示 ProgressDialog 和/或没有其他内容 -。
在您的 doSomething 方法中,您应该通过使用

指向 BackgroundActivity 的意图来启动活动
this.startActivityForResult(new Intent(this, BackgroundActivity.class), 
    BG_ACTIVITY_ID);

其中 BG_ACTIVITY_ID 是您启动活动的唯一标识符,因此当它完成时,您可以处理它。

processBackgroundData里面(或者后台activity处理完毕的时候),你应该在调用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;
    }
}

在你的BackgroundHandlerhandleMessage 方法中(因为你回到了ui线程:你的主应用程序正在运行的线程)你可以做所有必要的ui修改,也可以监听用户事件。

这样您就可以摆脱无限循环,并且可以始终了解用户交互。

【讨论】:

    【解决方案2】:

    活动回调例程等待最后一个事件监听器... 这可能是一个简单的解决方案吗??

    这个“等待用户输入”问题是一个经常出现的问题,也让我感到困惑,而且我还没有看到在我看来是一个真正干净的解决方案。

    我最近想出了一个想法,但我对 Android 游戏还很陌生,我想看看它如何经得起审查。

    该技术基于这样一种思想,即只要有事件侦听器继续侦听,活动回调例程就不会完成。结果,回调例程执行最后一条语句,然后什么也不做,但没有结束。 (IOW,“你可以随时查看,但你永远不能离开......直到事件监听器允许你。”Yuk。)

    这似乎符合要求。 UI 没有冻结,也没有无限循环。对 UI 的唯一要求是它支持事件侦听器。当用户提供输入时,事件回调例程(即 onKey)会处理输入,然后在需要下一个用户输入之前执行所有必需的步骤。然后事件回调例程设置一个新的侦听器并返回,释放旧的侦听器,并让 UI 完成一项任务——维持新的侦听器。这会不断迭代,直到活动回调例程完成。

    这是我测试的一些代码:

    @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 等待我的输入。

    这是个好方法吗?

    是否有我没有发现的问题?

    大家一直都在这样做吗, 只有像我这样的新手才认为他们正在做某事?

    【讨论】:

      【解决方案3】:

      Android 将为您运行一个事件循环 - 因此您不必自己循环等待输入。

      您可以通过多种方式进入循环。从 1.6 开始,最简单的方法是在 XML 中指定钩子,例如:

      您也可以通过调用 setOnClickListener 在代码中执行此操作。

      查看http://android-developers.blogspot.com/2009/10/ui-framework-changes-in-android-16.html 中的一些示例(阅读标题为“更轻松的点击侦听器”的部分)

      如果您可以使视图无效,那么 Android 事件循环将负责重新绘制屏幕,​​包括任何布局更改。如果您有自定义视图,他们的 onDraw() 将被适当地调用。

      希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        嗯,我可能有错误的解释,但似乎在执行 setOnClickListener 时,当到达代码的特定部分时,按钮变为可点击并在点击按钮时采取行动?我已经有了它,这样当点击一个按钮并且轮到玩家时,就会发生动作。但是我需要知道的是如何让程序真正等待或暂停,直到按下其中一个按钮。

        类似于你激活键盘,java 等待键盘输入。

        【讨论】:

        • 一个 Android 应用程序,不应该停止等待,阻止所有其他操作。通常有许多线程在运行,其中一个主线程或 UI 线程会注意到您的按钮已被单击并跳转以执行 clickListener 上的代码。
        • 那么设置无限while循环或者for循环基本上是不可能的?
        【解决方案5】:

        不要轮询以查看您的按钮是否已被按下。只需在 OnClickHandler 中做任何你想做的事情。

        这是您的代码可能看起来的示例(错误的方式):

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

        是的,正确的方法需要更多的输入......但它也有效。而且,如果您查看 Collin 发布的链接,就会发现有一种不太“type-y”的方法,它涉及将内容添加到您的 AndroidManifest 文件中。您只需将它指向您类中具有正确签名的函数(我记得public void funcName(View v)),Android 就会为您处理所有侦听器的内容。

        就“让你的程序等待”而言,它已经是了。在对您的某个类的入口点进行某些调用之前,您的程序代码不会运行。在那之前,执行是在你的进程中的 Android 的 UI 处理程序代码中浮动的,来回传递消息。一旦这些消息之一最终出现在您的应用中,(onCreate、点击侦听器等)您的代码就会执行它并返回,从而允许该 UI 线程返回处理应用进程的所有输入。

        如果您的应用响应消息的时间超过 5 秒左右,它将被系统杀死,并显示“ANR”...应用无响应。

        Another handy Google IO video 题为“编写 Zippy Android 应用程序”。

        【讨论】:

        • 我最终将代码扔到一个线程中,并且执行 while 循环的方式错误。但它有效,因为它在一个线程中:P
        • 该死的,你的正确方法的巨大问题是它会杀死方法......并且方法必须始终存在才能保存套牌数据
        • 有很多方法可以解决这个问题...您可以将信息存储在 Application 类中,您可以在 OnPause 期间将其保存在 Bundle 中,然后在 OnCreate 中将其取回(我知道这很时髦)。将数据保存到磁盘...有很多选择...但是 The Wrong Way 就是这样...所以...错了!
        • 但它仍然有效:P...并且目前没有滞后:P...现在我需要弄清楚远程视图或者任何正确的方法是改变视图在游戏引擎类的播放屏幕类的布局中(这是线程:D)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-10
        • 2014-12-24
        相关资源
        最近更新 更多