Android Idioms -- Part I

7 views
Skip to first unread message

Jeffrey Peacock

unread,
Oct 13, 2015, 12:19:26 AM10/13/15
to socal-...@googlegroups.com
There are 2 basic ways to assign an onClick() listener to a button, or other View's that accept clicks.  The 1st is the old programmatic way:
final Button button = (Button) findViewById(R.id.button_id);
button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        // onClick implementation
    }
});
The other mechanism is to declare the listener method using the attribute:

    android:onClick=”methodName”

in the layout XML that contains the Button.  Then define the method in the Activity that uses the layout like this:
/**
 **  onClick listener for ??? button
 **
 **  @param view the view the that received the click
 */
public void methodName(final View view) {
    // onClick implementation
}
So, which do you prefer?  Recommend?  What is the compelling argument for either or both?

Thanks.

/J

Wolf Paulus

unread,
Oct 13, 2015, 12:32:03 AM10/13/15
to socal-...@googlegroups.com
Usually I’m very much in favor of a declarative approach, especially if it serves the separation of concerns. E.g. we are building the static UI declaratively in XML and the behavior in (Java) code. Binding the two however, is the tricky part, where should that happen?

I guess, if you screw up what you call,  "the old way” (R.id.button_id doesn’t exist) that can be caught at compile time, while using the declarative approach (missing method implementation) problems will only get caught at runtime.

Moreover, and here comes the more important argument, the declarative approach doesn’t work with Fragments, which is very how you should build your Android apps these days. So long story short, the "old programmatic way” is the new way and should be the preferred way to bind event handlers. 
   

Cheers
Wolf
— 



--
You received this message because you are subscribed to the Google Groups "SoCal Android Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to socal-androi...@googlegroups.com.
To post to this group, send email to socal-...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/socal-android/561C8647.2070202%40JeffreyPeacock.com.
For more options, visit https://groups.google.com/d/optout.

Jeffrey Peacock

unread,
Oct 13, 2015, 12:54:27 AM10/13/15
to socal-...@googlegroups.com

Have you verified with Fragments?  I think I did this th other day and it was fine.

/J

Ray Tayek

unread,
Oct 13, 2015, 12:59:01 AM10/13/15
to socal-...@googlegroups.com
pardon the top post, i go for the programmatic way.

i need to start some treads that run on the edt (see attached).

thanks
--
You received this message because you are subscribed to the Google Groups "SoCal Android Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to socal-androi...@googlegroups.com.
To post to this group, send email to socal-...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/socal-android/561C8647.2070202%40JeffreyPeacock.com.
For more options, visit https://groups.google.com/d/optout.


-- 
Honesty is a very expensive gift. So, don't expect it from cheap people - Warren Buffett
http://tayek.com/
AndroidGui.java
Build.java

Wolf Paulus

unread,
Oct 13, 2015, 1:02:43 AM10/13/15
to socal-...@googlegroups.com

Jeffrey Peacock

unread,
Oct 13, 2015, 1:54:07 PM10/13/15
to socal-...@googlegroups.com

Unfortunately, as a comment to the article states, there is a fly in the ointment.

A button in a fragment layout, using the android:onClick=”methodName” attribute, will look for the listener in the Activity to which the fragment is attached. To my way of thinking this only gets us to programmatic definitions in Fragments – let’s not throw out the baby with the bath water.  However, considering that the convention is to name layouts for Activity’s with an ‘activity_’ prefix, and layouts for fragments with a ‘fragment_’ prefix; and the intimate knowledge that Activity’s have about their attached Fragment’s, and the initimate knowledge Fragment’s have about the Activity’s to which they are attached, seems to already allow for liberal cooperation.  This makes me wonder if there isn’t already enough convention and structure in place to allow for an idiom, a set of rules,  which continues to allow onClick methods to be declared in the XML.

I don’t have an immediate answer right now.  I need to think on this a bit.

Ideas?

/J

Jeffrey Peacock

unread,
Oct 13, 2015, 4:06:03 PM10/13/15
to socal-...@googlegroups.com
Ray,

We need to talk about some of your code:
    final GuiAdapterABC adapterFor1=new GuiAdapterABC(tablet.model) {
        @Override
        public void setText(final int id,final String string) {
            new Timer().schedule(new TimerTask() {
                @Override
                public void run() {
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            ((CheckBox)gui.idToButton.get(id)).setText(string);
                        }
                    });
                }
            },0);
        }


You're creating a Timer to schedule a Task to be run without delya to run something on the UI thread.  Get rid of the overhead and just do:

                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            ((CheckBox)gui.idToButton.get(id)).setText(string);
                        }
                    });
/J

Ray Tayek

unread,
Oct 13, 2015, 4:29:58 PM10/13/15
to socal-...@googlegroups.com
On 10/13/2015 1:06 PM, Jeffrey Peacock wrote:
Ray,

We need to talk about some of your code:
    final GuiAdapterABC adapterFor1=new GuiAdapterABC(tablet.model) {
        @Override
        public void setText(final int id,final String string) {
            new Timer().schedule(new TimerTask() {...
            },0);
        }


You're creating a Timer to schedule a Task to be run without delya to run something on the UI thread.  Get rid of the overhead and just do:

                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            ((CheckBox)gui.idToButton.get(id)).setText(string);
                        }
                    });
/J

iirc, that gets some error saying that i can not invoke gui stuff on the thread that is calling set text.

thanks

For more options, visit https://groups.google.com/d/optout.

Jeffrey Peacock

unread,
Oct 13, 2015, 5:15:06 PM10/13/15
to socal-...@googlegroups.com

I don't know how that can hapen unless the time/sapce continuum is completely out of wack.

The contract of activity.runOnUiThread() is to run the Runnable on the UI thread so the UI can be updated.

/J

Ray Tayek

unread,
Oct 13, 2015, 6:46:54 PM10/13/15
to socal-...@googlegroups.com
On 10/13/2015 2:15 PM, Jeffrey Peacock wrote:

I don't know how that can hapen unless the time/sapce continuum is completely out of wack.

The contract of activity.runOnUiThread() is to run the Runnable on the UI thread so the UI can be updated.

/J
if i don't do that, i crash (please see below).

thanks

    --------- beginning of crash
10-13 15:44:01.346    2376-2399/? E/AndroidRuntime﹕ FATAL EXCEPTION: client
    Process: com.tayek.tablet.android, PID: 2376
    java.lang.RuntimeException: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
            at com.tayek.tablet.io.UdpClient.run(UdpClient.java:44)
            at java.lang.Thread.run(Thread.java:818)
     Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
            at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6357)
            at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:909)
            at android.view.ViewGroup.invalidateChild(ViewGroup.java:4690)
            at android.view.View.invalidateInternal(View.java:11801)
            at android.view.View.invalidate(View.java:11765)
            at android.view.View.invalidate(View.java:11749)
            at android.widget.TextView.checkForRelayout(TextView.java:6858)
            at android.widget.TextView.setText(TextView.java:4057)
            at android.widget.TextView.setText(TextView.java:3915)
            at android.widget.TextView.setText(TextView.java:3890)
            at com.tayek.tablet.android.Build$2.setText(Build.java:33)
            at com.tayek.tablet.io.GuiAdapterABC.update(GuiAdapterABC.java:17)
            at com.tayek.tablet.android.Build.update(Build.java:173)
            at java.util.Observable.notifyObservers(Observable.java:138)
            at com.tayek.tablet.model.ModelBase.setChangedAndNotify(ModelBase.java:20)
            at com.tayek.tablet.model.ModelBase.setState(ModelBase.java:25)
            at com.tayek.tablet.model.Model.setState(Model.java:15)
            at com.tayek.tablet.model.ModelBase.receivedBroadcast(ModelBase.java:30)
            at com.tayek.tablet.model.Tablet.receivedBroadcast(Tablet.java:45)
            at com.tayek.tablet.Mediator.receivedBroadcast(Mediator.java:83)
            at com.tayek.tablet.io.UdpClient.run(UdpClient.java:38)
            at java.lang.Thread.run(Thread.java:818)
1

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages