Greetings,
I'm currently developing an Android application, but I'd like to be able to handle button click events etc in a separate file for each Activity. Is this possible? At the moment, I have one very large file that handles all events for several Activity windows.
Any advice greatly appreciated.
Thanks in advance,
For event handling there is OnClickListener interface, you can create your own implementation and use it only in place you get the button, for example in onCreate():
#Override
public void onCreate(Bundle savedInstance) {
...
Button btn = (Button) findViewById(R.id.ok_button);
btn.setOnClickListener(new onClickListener() {
#Override
public void onClick() {
// the code
}
}
So, you don't have to create a separate file at all.
What you are trying to do is not possible (at least in a clean way).
To handle a click, you must implement one interface (View.OnCLickListener). I'm assuming clicking in a different view will produce a different type of response (i.e. one button might open a popup and another might start an activity).
Yes, you could check the id of the view that was clicked and decide what to do based on that.. but this looks like ugly!
In order to accomplish code reuse, usually I implement everything in a inner class. This way I can choose what to do in each case just once.
If you've done something very general, you might do it in a separate file so you can reuse it in other classes.
I think you should spend a little time familiarizing yourself with the basics of object orientation before you go further - you are doing yourself a disservice because without the basic understanding, you are probably going to write a ton of code that in the end, wouldn't be needed if you had the basic understanding. Pick up a beginning Java book or do a tutorial or two online - you will be glad you did.
And I hope you don't take my advice to be picking on you - I am simply telling you that your question indicates you don't know the basics.
Now to answer your question... You want to create a single class that implements all the shared event handling logic (shared code means only the code that all activities will use). You will then use this shared event handler from each of your Activity classes by making your activity classes either an IS A EventHandlingClass or HAS A EventHandlingClass. Now its up to you to find out what IS A or HAS A actually means, and when you do, you will then have the basic understanding of object oriented languages.
Good Luck!
Rodney
Related
In Android you can write in button for example the onClick() function and linking the function to it. But most of the time I see people not doing it but activating onClickListener in the Java file to the button.
Why? What are the differences between the two? Are there cases when you are not allowed to use one of them?
Short Explanation:
onClick via xml is good for fixed implementation in your code, but using OnClickListener is better for complex app structure with multiple UI elements or complex UI flow, but they both do the exact same thing.
Detailed:
when you set onClick via layout, LayoutInflator initiated by setContentView
pass this attribute to respected view constructor & managed by the views code.
But by using OnClickListener you can alter the behaviour of the control of click event management when it comes to complex app structure.
Below is snap of the internal implementation of onClick attribute
case R.styleable.View_onClick:
if (context.isRestricted()) {
throw new IllegalStateException("The android:onClick attribute cannot "
+ "be used within a restricted context");
}
final String handlerName = a.getString(attr);
if (handlerName != null) {
setOnClickListener(new DeclaredOnClickListener(this, handlerName));
}
internal implementation itself uses setOnClickListener, so both are same,
as i mentioned above, using xml onClick option is good only when app is simple, otherwise use Listener.
Functionally you are able to use either and they will both do the same thing. There is no restriction on which one you use, however many developers will favor using the Java code because it's a bit more flexible and allows you to add more functionality if you need to. Sometimes you might see people adding a very basic method call in the XML file which then links to a Java method doing everything they need.
All in all it's just a matter of preference and coding style.
I'm trying to learn more about proper architecture so I'm going to try to refactor some of my working code. I have an android app that swaps in a few different Fragments for the main view. Right now, the different fragments exist as properties in MainActivity. When the user picks a menu item I have to check what kind of Fragment is currently being shown (via instanceof) and perform some different tasks depending on what kind of fragment it is. It's pretty ugly and I feel like it should be better abstracted. In the future, the case statement will grow even more and need to be maintained. Also, most of the code is duplicated since I only really need to do something special for one fragment in particular. How can I abstract away these details out of MainActivity? I tried to make a base class for all my fragments but it didn't quite work out because some of the fragments extend MapFragment and some just extend Fragment. So I'm guessing an interface is the way to go but I'm not quite sure how to do it. Do I need to create an abstract factory to get these objects in MainActivity? What is the proper way to do this? After reading up a little bit on architecture, it seems to me that my MainActivity should only know about some abstractions for my Fragments and not the concrete classes themselves, is that correct? Thanks for any help you can provide.
This is a bit of a general question, but I will give a specific example for you.
I have a bunch of activities in an App. In all of the activities, there is a Facebook button. When you click the button it takes you to a specific Facebook page. I wish for the button to behave exactly the same way on every page.
Right now, in every single Activity, I create an onClickListener() for the Facebook button and make the intent and start the activity. It's the same code in every single Activity.
What is the best way to write this code once and include it in multiple activities? Is there anyway to include other .java files?
One solution that I know would work, is to make a base CustomActivity class that extends Activity and then have all activities extend CustomActivity. Then put my onClickListener() code in CustomActivity. I'm new to Java though and I wasn't sure if that was the best approach or not. Some of my Activities already extend other custom activity classes as is, so extending things that extend more things might get kinda messy, I dunno.
UPDATE
Playing the devil's advocate here: Lets say I went with the inheritance route and I create some CustomActivity that I want my Activities to extend. CustomActivity would contain a bunch of general code that I need to use for all Activities, including but not limited to the Facebook button functionality. What happens when there is an Activity that I need to use generic code from the CustomActivity but there is no Facebook button in that specific Activity?
A common base class is perhaps the best approach. (It doesn't work quite so well if some of your activities extend Activity and some extend Activity subclasses (such as ListActivity).
An alternate approach is to create a separate class that implements the logic of your click listener. This doesn't eliminate all duplicate code — each activity still needs to instantiate and register a listener — but the logic for what to do will only need to be written once in the listener class.
In either alternative, you might consider assigning the android:onClick attribute to the button. That way you don't need to register a click listener; you just need to implement the target method in each activity. This is particularly useful with the base class approach.
UPDATE
Suppose you go the inheritance route and you want an activity with no Facebook button. If you are using the android:onClick technique, then you don't have to do anything different in your code — since no button will invoke your onClick method, the method will just sit there doing nothing. If you are installing an OnClickListener in code, then you just need to test that the button exists (i.e., that findViewById() did not return null) before registering the listener.
Generally a common base class is NOT the best approach (although it's certainly valid).
This took me (and every OO programmer who "gets" OO that I know of) a while to really grok, but you should use inheritance as sparingly as you possibly can. Every time you do it you should ask yourself if there is REALLY no other way to do this.
One way to find out is to be very strict with the "is-a" test--if you call your base activity a "Facebook Activity", could you really say that each child "is" a Facebook activity? Probably not. Also if you decided to add in Twitter to some of the pages (but not others), how do you do this?
Not that inheritance is completely out! A great solution might be to extend a control to launch your facebook activity and call it a facebook button--have it encapsulate all the stuff you need to do to connect to facebook. Now you can add this to any page you want by simply dragging it on (I'm pretty sure android tools let you add new components to the pallet). It's not "Free" like extending your activity class, but in the long run it will cost you a lot less stress.
You probably won't believe me now, we all need to learn from our own experience, just keep this in mind and use it to evaluate your code as you evolve it over time.
--edit, comment response--
You can encapsulate any facebook activity you think you will use a lot in it's own class--get it to a bare minimum so you can just add it to any class in a one-liner.
At some point, however, you may decide that it's STILL too much boilerplate, I totally understand. At that point you COULD use an abstract base activity like you suggest, but I wouldn't hard-code it to handle facebook explicitly, instead I'd have it support behaviors such as facebook (and maybe others), and turn-on these behaviors as desired. You could then tell it NOT to add the facebook behavior to a given screen if you like, or add in Twitter to some of them.
You can make this boilerplate minimum, for instance if you want "Standard" functionality, you shouldn't have to do anything special, if you wish to disable facebook you might start your constructor with:
super(DISABLE_FACEBOOK_BEHAVIOR);
and if you want one that also enables Twitter you could use:
super(DISABLE_FACEBOOK_BEHAVIOR, ENABLE_TWITTER_BEHAVIOR);
with a constructor like AbstractAction(BehaviorEnum... behaviors).
This is more flexible and you actually can say that each if your activities IS-A "behavior supporting activity" with a clear conscience.
It is, of course, a perfectly good approach to be less flexible at first and refactor into a pattern like this later when you need to, just be on the look-out for your inheritance model causing problems so you don't let it mess you up for too long before you fix it.
Well, extending things is the principle of OOP, so I don't think this is a problem to have more than one level of subclasses. The solution you thought about is in my opinion the best.
Absolutely. Use inheritance to gain some reusability as you should with OOP. You'll find, as you progress, that there are gonna be more and more things you'd like to reuse in your activities -- things more complex than an onClickListener for a FB button -- so it's a great idea to start building a nice, reusable "super" activity that you can inherit from.
I have recently written my first Android app which was roughly 8,000-10,000 lines of code. One thing that continuously hindered my use of normal design patterns was android's heavy use of asynchronous calls (opening dialogs, activities, etc). Due to this, my code very quickly began looking "spaghetti" like, and I eventually started to dislike looking at certain classes.
Are there specific design patterns or programming methodologies which are for systems such as these that anyone would recommend? Are there any suggestions for writing manageable asynchronous code?
Use global variables
If you do not want to mess up your code with simple Intent.putExtra() calls and manage this things for each unique Activity you'll have to use global variables within the application. Extend Application and store data that you need as long your application is alive. To actually implement it, use this excellent answer. This will make dependencies between activities disappear. For example, say that you need a "username" for your application during the application's life cycle - this is an excellent tool for just that. No need for dirty Intent.putExtra() calls.
Use styles
One common mistake when making the first Android application is that one usually just start writing the XML views. The XML files will (without problem and very fast) go up to very many lines of code. Here you can have a solution where you just use the style attribute to implement a specific behaviour. For example, consider this piece of code:
values/styles.xml:
<style name="TitleText">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">#000</item>
<item name="android:textStyle">bold</item>
</style>
layout/main.xml:
Now, if you have, let's say, two TextViews and both of them should have the same behaviour, make them use the TitleText style. Sample code:
<!--- ... -->
<TextView
android:id="#+id/textview_one"
style="#style/TitleText"
/>
<TextView
android:id="#+id/textview_two"
style="#style/TitleText"
/>
<!--- ... -->
Simple and you don't need to duplicate code. If you really want to look further on this particular subject, please look at Layout Tricks: Creating Reusable UI Components.
Use strings
This point is short but I think it is important to mention it. Another mistake that developers might do is to skip the strings.xml and just write UI messages (and attribute names) inside the code (where he will need it). To make your application easier to maintain; just define messages and attributes in the strings.xml file.
Create and use a global tool class
When I wrote my first application I just wrote (and duplicated) methods where I needed it. The result? A lot of methods that had the same behaviour between various activities. What I have learned is to make a tool class. For example, let's say you have to make web requests in all of your activities. In that case, skip defining them inside the actual Activity and make a static method for it. Sample code:
public final class Tools {
private Tools() {
}
public static final void sendData(String url,
String user, String pass) {
// URLConnections, HttpClients, etc...
}
}
Now, you can just use this code below in your Activity that needs to send data towards a server:
Tools.sendData("www.www.www", "user", "pass");
However, you get the point. Use this "pattern" where you need it, it will keep you from messing up your code.
Let custom classes define the behaviour where the user needs to interact with your application
This is probably the most useful point. To just define "where the user needs to interact with your application" let's say you have a Menu, which behaviour is very long in terms of lines, why do we keep the Menu's calculations in the same class? Every little item will make your Activity class a painful piece of code longer - your code look like "spaghetti". For example, instead of having something like this:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item;
item = menu.findItem(R.id.menu_id_one);
if (aBooleanVariable) {
item.setEnabled(true);
} else {
item.setEnabled(false);
}
// More code...
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem i) {
// Code, calculations...
// ...
// ...
return super.onOptionsItemSelected(i);
}
redesign it to something like this:
private MyCustomMenuInstance mMenuInstance;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mMenuInstance = new MyCustomMenuInstance();
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
mMenuInstance.onPrepareOptionsMenu(menu);
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem i) {
mMenuInstance.onOptionsItemSelected(i);
return super.onOptionsItemSelected(i);
}
For example, MyCustomMenuInstance:
public class MyCustomMenuInstance {
// Member fields..
public MyCustomMenuInstance() {
// Init stuff.
}
public void onPrepareOptionsMenu(Menu menu) {
// Do things..
// Maybe you want to modify a variable in the Activity
// class? Well, pass an instance as an argument and create
// a method for it in your Activity class.
}
public void onOptionsItemSelected(MenuItem i) {
// Do things..
// Maybe you want to modify a variable in the Activity
// class? Well, pass an instance as an argument and create
// a method for it in your Activity class.
}
}
You see where this is going. You can apply this to many things, e.g. onClick, onClickListener, onCreateOptionsMenu, the list is long. To learn more "best practices" you can see some sample applications from Google here. Look for how they've implemented things in a nice and correct way.
Last word; keep your code clean, name your variables and methods in a logical manner and especially in a correct way. Always, always understand where you are in your code - that is very important.
From an amateur perspective, I don't expect my first attempt to be a clean, production-ready app. I end up with spaghetti, fettucini and even ravioli code sometimes. At that point, I try to rethink what is what I dislike the most from the code, and search for a better alternative:
Rethink your classes to better describe your objects,
keep the code in each method to a minimum,
avoid dependencies to static variables anywhere you can,
use threads for expensive tasks, don't use them for quick procedures,
separate the UI from the app logic (keep it in your classes instead),
keep private fields anywhere you can: it will be helpful when you want to change your class,
iterate through these until you like the code
One of the most common errors I've seen in asynchronous methods is to use a static variable inside a loop that creates one or more threads, without considering that the value may change in another thread. Avoid statics!
As OceanBlue points out, it may not be clear from this that final static variables do not create any danger, but public static variables that can change. It is not a problem with the statics themselves, but with the notion that they will have a value and then find out that the value changed. It may be difficult to spot where the problem was. Typical examples would be a clicks counter or a timer value, when there could be more than one view clicked or more than one timer.
Hopefully you will receive suggestions from people with much more experience than me. Good luck!
If handling the the UI is your biggest concern, then you'll want to master event-driven coding. The ideas behind event-driven coding are behind all modern UI systems, and are useful in all kinds of things (not just UI).
The easiest way for me to think of it when learning was simply to treat each component and event as if it's self-contained. All you need to worry about is the event object passed into your event method. If you're used to writing applications that run basically from beginning to end, it's a bit of a mind shift, but practice will get you there pretty quickly.
What about using the Model View Controller pattern?
At least you have to isolate in the "model" (object or set of objects)
all the state and its logical management, and have in
a separate class (maybe the Activity class)
all the stuff related to the views, listeners,callbacks, ...)
Im pretty new to gui programming so i've been reading through every post on this site about swing and design. Whats been answered over and over again is that one should have a multiton class for the actions. Like this: (GUI being some JFrame)
alt text http://img341.imageshack.us/img341/255/skjermdump.png
Now, this works great for one-way actions, like OpenDialog. But the actions for buttons in DialogA and B will have to have access to all the components (there will be many) in its dialog, and the controller. This is where im stuck.
The only sane way i can see is to put it in DialogA/B but i would then need to pass the controller all the way down, through classes that dont even need it, and it'll get all spaghetti. Really dont want that.
Someone must have encountered this problem before. So where should i put this Action? Or should i just drop the whole design?
Edit: got a good answer from elsewhere. Resolved.
In MVC the controller and the view access each other, the controller shields the view from the model. The best thing to do is to put your ActionHandler as anonymous class and have it simply call back to your view that in turn calls the controller.
If you really want you could have a Controller superclass that has generic messages to send a message and pass in a HashMap, that gives you good separation of code but, adds complexity and removes type checking.