I'm trying to create a UI library that basically holds a lot of methods and actions I typically use when building a layout. One example of such a function is managing the fab clicks. I have one fab in the main activity, and I change its function, icon, and visibility based on which fragment is loaded. I'm currently doing everything with interfaces as you can see here. It all works fine, but the only issue is that I have to make sure other users use activities and fragments that extend my interface.
Example
protected void hideFab() {
capsuleActivity().getFab().hide();
}
protected CActivityCore capsuleActivity() {
if (!(getActivity() instanceof CActivityCore)) {
throw new RuntimeException(s(R.string.capsule_activity_context_error));
}
return ((CActivityCore) getActivity());
}
If they don't need the functions for one fragment, they have to override a lot of my methods to make it not do anything. My other option could be to use an EventBus, and to just send various events whenever something is called and resolve it accordingly. That way, it no longer matters if users use my classes or not; if they only want the functions in a few fragments, they can just extend my fragment for those fragments and not worry about the rest.
My question is, would this be a nice and viable way of doing things, or is this moreso overkill as to how EventBuses should be used?
Another function I'm considering is to have the activity send a callback to the current fragment and have it run only if the fragment extends a certain class.
Current implementation:
#SuppressWarnings("unchecked")
protected <T extends Fragment & CFragmentCore> void onCurrentFragment(Class<T> clazz, #NonNull Current<T> callback) {
Fragment current = getSupportFragmentManager().findFragmentById(getFragmentId());
if (clazz.isInstance(current.getClass())) {
callback.onMatch((T) current);
}
}
But I could also instead use an EventBus with an event containing the class and a callback function.
Using an EventBus is a design choice. It has advantages and disadvantages, which you can easily find on Google.
There is no such thing as an "overkill" if you are able to simplify your code.
Apart from that, an EventBus is probably a good idea in your scenario, as it provides an easy way to manage View-Controller communication.
Related
Since Fragments need to survive configuration change, it is strongly suggested by Android that we should implement our own newInstance() method when creating a fragment, passing necessary data to its Bundle instead of using new MyFragment().
Now, the problem is, I want to pass a callback (interface) to this Fragment.
At first I tried to make my interface extends Serializable, and simply use args.putSerializable("myInterface", myInterface).
But when Android try to save its state (parcel it), an Exception is thrown (Parcelable encountered IOException writing serializable object).
I know the official way to do this is to make the caller Activity implements the callback, and reference the callback to the activity during onAttach() of the fragment.
Yes, it works, but it feels weird, because I am actually creating a library and now instead of asking user to pass a callback to the builder, I have to tell them your caller activity must implements a certain interface.
More importantly, what if I want to show this Fragment from another Fragment? onAttach() always attach to an Activity.
So, is there a way that I can let user pass the callback to the fragment, and being able to survive configuration change (e.g. device rotation)?
UPDATE
As requested, here is the interface that I want to pass:
public interface OnImageSelectedListener extends Serializable {
void onImageSelected (String uri);
}
And how I construct this interface:
new OnImageSelectedListener() {
#Override
public void onSingleImageSelected(String uri) {
Glide.with(MainActivity.this).load(uri).into(ivImage);
}
}
At last, I come to the conclusion:
We should not retain the callback.
Imagine the callback does the below code:
Glide.with(context).load(image).into(imageView);
When device rotates, the above imageView, which belongs to an activity or another fragment, is also destroyed and re-created. The old ImageView that is referenced in the retained callback no longer exists.
This will either make Glide throw an exception; or leaks the old ImageView and thus the whole Activity.
That's why we should always reference the callback to an attaching Activity.
And if the caller is a Fragment, instead of referencing the callback in onAttach(), simply reference the parent fragment in onCreateView():
if (getParentFragment() != null && getParentFragment() instanceof YourInterface) {
yourCallback = (YourInterface) getParentFragment();
}
So if to answer the original question,
Can I pass an interface to bundle of a Fragment?
The answer is, probably no, but you just shouldn't.
The reason you are facing this issue is because,
Glide is non Serializable data and you cannot serialize it. Since serialization is a process defined by Java and done on JVM, it doesn't understand Parcelable, hence fails with an error. This is also applicable even if you are just using them in the callback method.
But since you are developing a Library, you won't be able to control the usage of your Callback interface. So the solution would be avoid sending this object by Serializing it.
Instead, when usecase of your library starts (there must be some entry point to tigger the usecase), you need to request your to pass the reference directly to your method. You can then maintain the reference and execute callback when necessary. You need to implement some wrappers to achieve it. And communicate internally through LocalBroadcastReceiver
If the above approach is not possible, then only solution would be to ask user of your Library to register for LocalBroadcastReceive and deliver result through Broadcast.
I'm fairly new to Android Programming and have a question about best practice regarding how many Activities I should create.
I'm working on a Puzzle App. Currently, I have a Single Activity and around 15 Fragments(SherlockFragment).
One problem I'm experiencing is that the Activity code is becoming large and complex. Another challenge is communication between fragments.
I understand that the best practice for communication between Fragments is to create an Interface in the fragments and implement the interface in the Activity.
ref: http://developer.android.com/training/basics/fragments/communicating.html
Example:
I have a Contact fragment which contains a ListView where the user can select one or more contacts(Phone Contacts). By following the guidelines given by the link above, I could implement something like this in the Contact Fragment:
public interface OnContactSelected{
public void onContactSelected(Contact contact);
}
...
...
mCallback.onContactSelected(contact);
Then, I can listen to the selection of contacts in the Activity using code like this:
public Class PuzzleActivity extends SherlockFragmentActivity
implements ContactFragment.OnContactSelected{
...
...
public void onActivityCreated(Contact contact){
// Do something
}
The problem I'm facing is this:
The Contact fragment is an independent module used for different tasks, example:
1) Selecting a contact to add as a Friend
2) Selecting an opponent for an online game.
So the onContactSelected implementation in the Activity depends what I'm doing right now
public void onActivityCreated(Contact contact){
// if{inInAddFriendMode())doThis(); else doThat();
}
What I'm considering is to refactor the code and implement one activity for each of the main tasks in the APP, example:
FriendActivity.java ( To show and add friends)
MultiplayerGameSetupActivity.java (To configure a new game with how many players, choice of opponents, level of difficulty etc)
GameActivity.java (The game it's self)
SettingActivity.java
I'm also thinking about creating a base Activity which all of the Activities above extends.
To me this seems to solve all the problems by making the Activity code less complex, and also by allowing me to implement the Fragment interfaces cleanly in the Activities.
From your experience, is this a good approach, or should I stick to one Activity?
Thanks in advance.
I personally think it sounds like a good idea. I have found myself in the same situation as you a few times and maintaining it that way just gets more and more difficult with every addition.
The first thing I do now when I start a new project is create a Base Activity and a Base Fragment that all my others extend. I find doing it this way really helps with keeping it DRY and since everything is separated MUCH easier to maintain.
I am working with Android Fragments pretty extensively and one of the problems I am having is the lack of proper mechanism to pass complex objects to it.
In the android developers documentation for Fragments, they have a static method called newInstance called with some simple arguments which will be packaged into a Bundle and used inside the Fragment. However this method cannot be employed for passing complex objects.
Because I have been using the Fragments api a lot, it is becoming more and more important to have complex objects passed to it. One way to do this is by implementing the Parcelable interface, which I don't want to do for all the classes.
So, I thought I could do this :
Define an interface like this in the Fragment:
// Container Activity must implement this interface
public interface ReceiveDataInterface {
public MyClass getData(uniqueFragmentID);
}
Force the Activities using this fragment to implement the interface and call ReceiveDataInterface.getData(getArgument.getString(UNIQUEID))
In the Activity instantiate fragment using the newInstance method by passing a uniqueFragmentID and implement the ReceiveDataInterface which gives data based on uniqueFragmentID.
Is it a good idea to do this? if not, why? and how should I go about doing this?
Note:This is done in the same lines as OnArticleSelectedListener described in the documentation.
Any help is much appreciated.
We use this approach for any app we build for android. It works well. I havent tested every method of doing this, but i think this is among the best way.
Another approach would be to make the Fragment themselves independent. Why not write the code that fetches data from network/database in the Fragment itself?
In the examples provided by Google Web toolkit that they are adding the event handlers in one class only for the whole application.
As in - for Module1, 2 and 3 all events are registered in the main AppController class. I find this a bit monolithic and would not it better when we are using the MVP pattern that we declare a method called bind() in each of the Presenters that is as follows:
public class MyTestPresenter implements Presenter{
private void bind()
{
TestEvent.eventBus.addHandler(TestEvent.Type, new TestEventHandlerImpl() )
}
}
public class TestEvent
{
public static SimpleEventBus eventBus = new SimpleEventBus()
}
Query is:
If our application is huge - we would be using one eventbus to populate more than a thousand events in it - or would we design in such a way that we have separate instances of event bus for each module?.
Any cost of keeping the static event bus field. Any better design to give it's instance to all classes - passing it around to all classes through a constructor with each presenter class having it's reference seems a bit of clutter ...
What are activity and places in GWT when it comes to event handling? - Can someone give a pointer to how to understand the concept of activity/place in general?
Actually I dislike event bus implementation in GWT too. I've asked smt about before.
Now I develop some desktop application and I design eventBus in next way.
public interface EventBus {
void fireEvent(Event event);
<T extends Event> void addHandler(Class<T> eventType, Handler<T> handler);
interface Event {
}
interface Handler<E extends Event> {
void handle(E event);
}
}
So in usual Java application I would design it in other way, but here we should deal with issues connected with javascript and so on.
If our application is huge - we would
be using one eventbus to populate more
than a thousand events in it - or
would we design in such a way that we
have separate instances of event bus
for each module?.
I was thinking about this question too. I found that there are no any real advantages. For modularity you can separate visibility of your events. And there is some disadvantage. Suppose you should deal with several eventBusses in same class - code will be messy. Beside you should map this instances to classes somehow.
Any cost of keeping the static event
bus field. Any better design to give
it's instance to all classes - passing
it around to all classes through a
constructor with each presenter class
having it's reference seems a bit of
clutter ...
You can do both. In new Activity-Place framework it passed as parameter.
What are activity and places in GWT
when it comes to event handling? - Can
someone give a pointer to how to
understand the concept of
activity/place in general?
Activity it's like your old presenter but without low level view binding. Place just like history entry that used for specify windows.
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