Message from discussion
Button#onClickListener thread unsafe?
Received: by 10.204.6.19 with SMTP id 19mr613009bkx.8.1350233500735;
Sun, 14 Oct 2012 09:51:40 -0700 (PDT)
X-BeenThere: android-developers@googlegroups.com
Received: by 10.204.131.72 with SMTP id w8ls4315496bks.3.gmail; Sun, 14 Oct
2012 09:48:47 -0700 (PDT)
Received: by 10.204.5.194 with SMTP id 2mr611391bkw.7.1350233327332;
Sun, 14 Oct 2012 09:48:47 -0700 (PDT)
Received: by 10.204.5.194 with SMTP id 2mr611390bkw.7.1350233327314;
Sun, 14 Oct 2012 09:48:47 -0700 (PDT)
Return-Path: <jg.sv...@gmail.com>
Received: from mail-lb0-f196.google.com (mail-lb0-f196.google.com [209.85.217.196])
by gmr-mx.google.com with ESMTPS id y23si100050bkv.2.2012.10.14.09.48.47
(version=TLSv1/SSLv3 cipher=OTHER);
Sun, 14 Oct 2012 09:48:47 -0700 (PDT)
Received-SPF: pass (google.com: domain of jg.sv...@gmail.com designates 209.85.217.196 as permitted sender) client-ip=209.85.217.196;
Authentication-Results: gmr-mx.google.com; spf=pass (google.com: domain of jg.sv...@gmail.com designates 209.85.217.196 as permitted sender) smtp.mail=jg.sv...@gmail.com; dkim=pass header...@gmail.com
Received: by mail-lb0-f196.google.com with SMTP id n8so1053056lbj.3
for <android-developers@googlegroups.com>; Sun, 14 Oct 2012 09:48:47 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20120113;
h=mime-version:in-reply-to:references:from:date:message-id:subject:to
:content-type;
bh=7cbuz0vxy2xqcO4Bb51XVHzGYrTCskuvNccDGLrzrp8=;
b=0LaJ2Xoq9ZsnHai5GPnTv/0+RxUO2EnXaBfbD9tV2tsdi6FHsy7I7xPwHrlTkBbVe2
3PNPXHSLEuo+hhx91FwKvIpfeU1+q5OU4I6EUQewDRlwulUZLUpbl4yl/HLjCNoGXn2P
ApoNXi7ZSQ2+ogvPlmAteL1MLu//+rdcrlSfy5K+qibeSMUYTzULtC+dZDKQn4TjXED4
4Yxy0HIXKfS/2A3NxNinRdy9keQHyLHXjI7DbG/aZwbCmZaT9ImOvv4/54ulI1UYbMJq
TYsUH34UCF3qN5Ta94+NmTst4Kz+yMFiCxiz29Ry9TXuOGZyw8S6V1kmMlbg2yb+Jdsu
FZqg==
Received: by 10.152.105.103 with SMTP id gl7mr8008231lab.10.1350233326915;
Sun, 14 Oct 2012 09:48:46 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.112.4.38 with HTTP; Sun, 14 Oct 2012 09:48:26 -0700 (PDT)
In-Reply-To: <a90637c9-d86c-4309-8aa1-2b72a7453...@r8g2000pbs.googlegroups.com>
References: <a90637c9-d86c-4309-8aa1-2b72a7453...@r8g2000pbs.googlegroups.com>
From: =?UTF-8?Q?Gergely_Juh=C3=A1sz?= <jg.sv...@gmail.com>
Date: Sun, 14 Oct 2012 18:48:26 +0200
Message-ID: <CAKC-o=XfamyB=rcTtMDencD3kJS=p_zhUfxSvCpYAU81gV8...@mail.gmail.com>
Subject: Re: [android-developers] Button#onClickListener thread unsafe?
To: android-developers@googlegroups.com
Content-Type: text/plain; charset=UTF-8
The input events are queued. So your case is valid. When you disable a
button there can be already multiple events in the event queue. Sad
but true :(
On 14 October 2012 10:09, Greenhand <cooperateonl...@gmail.com> wrote:
> In my project, I has a layout as follows:
> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/
> android"
> android:layout_width="fill_parent"
> android:layout_height="fill_parent"
> android:orientation="vertical">
>
> <Button
> android:id="@+id/startButton"
> android:layout_width="fill_parent"
> android:layout_height="0dp"
> android:layout_weight="1"
> android:text="start"
> />
> <Button
> android:id="@+id/stopButton"
> android:layout_width="fill_parent"
> android:layout_height="0dp"
> android:layout_weight="1"
> android:text="stop"
> />
> </LinearLayout>
> It is quite simple. There are two buttons. One is start and the other
> is stop.
>
> And an Activity as follows:
> package button.test;
>
> import android.app.Activity;
> import android.os.Bundle;
> import android.util.Log;
> import android.view.View;
> import android.widget.Button;
>
> public class MainActivity extends Activity {
> private static final String TAG = "MainActivity";
> private Button startButton;
> private Button stopButton;
> @Override
> public void onCreate(Bundle savedInstanceState) {
> super.onCreate(savedInstanceState);
> setContentView(R.layout.activity_main);
> startButton = (Button)findViewById(R.id.startButton);
> startButton.setOnClickListener(new View.OnClickListener() {
>
> @Override
> public void onClick(View arg0) {
> Log.d(TAG,"startButton isEnabled(): "+arg0.isEnabled()+" executing
> on thread "+ Thread.currentThread().getName());
> if(arg0.isEnabled()==false){
> throw new RuntimeException("startButton");
> }
> arg0.setEnabled(false);
> stopButton.setEnabled(true);
> }
> });
> stopButton = (Button)findViewById(R.id.stopButton);
> stopButton.setOnClickListener(new View.OnClickListener() {
>
> @Override
> public void onClick(View arg0) {
> Log.d(TAG,"stopButton isEnabled(): "+arg0.isEnabled()+" executing
> on thread "+ Thread.currentThread().getName());
> if(arg0.isEnabled()==false){
> throw new RuntimeException("stopButton");
> }
> arg0.setEnabled(false);
> startButton.setEnabled(true);
> }
> });
> }
> }
> The logic is: (1)When the start button is clicked, disable it and
> enable the stop button. (2)When the stop button is clicked, disable it
> and enable the start button.
>
> What I expect is that when the onClickListener of a button is
> executing, the button state should be enabled. It is impossible to
> fire the onClickListener when the button is disabled. Therefore, I add
> the if block and the RuntimeException to detect it.
>
> It works when I interact with it but it crashes when I run the monkey
> test (adb shell monkey -p button.test -v 50000).
>
> The logcat messages are as follows:
> D/MainActivity(1836): startButton isEnabled(): true main
> D/MainActivity(1836): stopButton isEnabled(): true main
> D/MainActivity(1836): startButton isEnabled(): true main
> D/MainActivity(1836): startButton isEnabled(): false main
> D/AndroidRuntime(1836): Shutting down VM
> W/dalvikvm(1836): threadid=1: thread exiting with uncaught exception
> (group=0x41745300)
> E/AndroidRuntime(1836): FATAL EXCEPTION: main
> E/AndroidRuntime(1836): java.lang.RuntimeException: startButton
> E/AndroidRuntime(1836): at button.test.MainActivity
> $1.onClick(MainActivity.java:24)
> E/AndroidRuntime(1836): at android.view.View.performClick(View.java:
> 4084)
> E/AndroidRuntime(1836): at android.view.View
> $PerformClick.run(View.java:16966)
> E/AndroidRuntime(1836): at
> android.os.Handler.handleCallback(Handler.java:615)
> E/AndroidRuntime(1836): at
> android.os.Handler.dispatchMessage(Handler.java:92)
> E/AndroidRuntime(1836): at android.os.Looper.loop(Looper.java:137)
> E/AndroidRuntime(1836): at
> android.app.ActivityThread.main(ActivityThread.java:4745)
> E/AndroidRuntime(1836): at
> java.lang.reflect.Method.invokeNative(Native Method)
> E/AndroidRuntime(1836): at
> java.lang.reflect.Method.invoke(Method.java:511)
> E/AndroidRuntime(1836): at com.android.internal.os.ZygoteInit
> $MethodAndArgsCaller.run(ZygoteInit.java:786)
> E/AndroidRuntime(1836): at
> com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
> E/AndroidRuntime(1836): at dalvik.system.NativeStart.main(Native
> Method)
>
> Note that at line 4, the button state is disabled when the
> onClickListener is executing!!! It is quite strange. In addition, both
> the onClickListeners are run on the main thread.
> What I expect is that there is no race condition between the
> onClickListeners because they run on the same thread.
>
> Can anyone explain why the program crashes when I run the monkey
> test?
>
> --
> You received this message because you are subscribed to the Google
> Groups "Android Developers" group.
> To post to this group, send email to android-developers@googlegroups.com
> To unsubscribe from this group, send email to
> android-developers+unsubscribe@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/android-developers?hl=en