I am having this issue where I have nested fragments. I need one to be able to send information to the other.
For example, if I press a button in the inner fragment I want the outer fragment to perform an action.
Any help would be great!
Edit: I forgot to mention that both of these are live fragments. As far as I know using bundles only allows me to set arguments when creating a fragment but not after it has been created.
Well there are plenty of ways to manage this. It really depends on the architecture you want to go with.
You could go lazy and use a Bus library that uses sub/pub modeling and reflection for notifying generic objects that registered and have matching signature methods of changes, However, this is frowned upon to use reflection for regular coding practices that could be implemented without it.
I would say you can either create an interface that represents the calls that would go back and forth like IMainActivityCallbacks with methods like dataChange(myObject obj)
.
Then in your onAttach of fragment you cast the context as IMainActivityCallbacks. Make sure the MainActivity implements the interface.
Then simply call the mIMainActivityCallbacks.dataChange(someObject);
This will call the method in the parent activity and allow him to pass it to the child fragment that needs it with mMyOtherFragment.publicMethod(newDataJustReceived).
You could also get crazier if you want and pass an interface into the child fragment that references the outer fragment so when MainActivity news up the children fragment, the outer one could implement an interface of doStuff and then be passed as an interface to the inner child fragment. So the child fragment can easily say if "mParentInterface" is not null then mParentInterface.doStuff.
There are millions of ways to skin a cat, but prefer to use interfaces rather then Reflection based libraries typically. Hope that helps.
Use interface in this case. 1) Define interface in you first fragment(in which you click something and waiting something to happen in a second fragment) and use callback method you define in your interface. For example:
OnButtonClickListener mCallback;
......your code
public interface OnButtonClickListener {
void onButtonSelected(int position);
}
......your code
then you call your callback method
.....
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
mCallback.onButtonSelected(position);
}
});
2) Then implement this interface in host activity you have for nested fragments.
For example:
public class MainActivity extends AppCompatActivity implements YourFragment.OnButtonClickListener{....
3) Define callback method of your interface in this activity. For example:
public void onButtonSelected(int position) {
...Here just change something in your second fragment.....
Hope this will be helpful.
I use greenrobot EventBus in that cases.
You need to add this library to your build gradle:
compile 'org.greenrobot:eventbus:3.0.0'
That you can send message like this:
EventBus.getDefault().post(new ActionEvent("test action"));
And another fragment can catch it this way:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onActionEvent(ActionEvent event) {
//do something
}
You can sending different actions, if you want, same way.
Don`t forget to according to fragment lifecycle:
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
Related
I have two activities Activity A and Activity B inside of the same application and they need to be able to call methods on each other. A needs to communicate to B at the start (possibly see "code" below).
B will call a lot of methods on A (this means that I cannot use the startActivityForResult method for communication because this would close B (Activity B is a Bluetooth Client and Server because it is a Peer to Peer app)). I do use startActivityForResult to start B for more of a kill signal than anything as the result.
Activity A uses a SupportMapFragment and Activity B cannot be a fragment because I want to be able to switch from B to A and then never use B again.
Originally, I started with one activity and tried switching between views using a ViewFlipper and just a call to setContentView(R.layout.my_layout_A) or setContentView(R.layout.my_layout_B). The fragment of course caused a lot of problems for both.
Using Fragments were confusing. The SupportMapFragment is the code for a Google Map which is a Fragment.
When I click a menu option inside of the MapsActivity (Activity A), I would like to be able to start myBluetoothActivity (Activity B) with a reference to the MapsActivity (Activity A) OR start myBluetoothActivity and then be able to set a reference to the caller inside of myBluetoothActivity (but this option would require having a reference to the BluetoothActivity inside of the MapsActivity or having some way to obtain the started activity from the intent).
//the following code is in Kotlin, but this can easily be converted over to java:
//option A: (pass it inside of the constructor)
var mbta:myBluetoothActivity = myBluetoothActivity(this)
//line for intent that I am unsure of
//intent so that I can start the activity with the pointer to the caller already passed into the new activity
startActivity(mbta)
//option B: (set this reference after obtaining a reference from intent):
var mintent:Intent = Intent(this.applicationContext, myBluetoothActivity::class.java)
startActivity(mintent)
//obtain the reference to the BluetoothActivity from the intent (NOT SURE HOW TO DO THIS???)
mbta.setCallerReference(this)
How can I accomplish this communication between the two activities via reference between the two activities? Should I use an interface for communication? If I should use it, (which I did try) how should I?
In other words, I am trying to access the caller activity (Activity A) from (Activity B) directly via a reference to Activity A inside of B OR trying to get the reference to B from the intent that started it inside of Activity A. I am trying to get a reference to that, so I can use it for communication/method calling/member variable and UI modification purposes.
NOTES: 1. The BluetoothActivity and the MapsActivity are NOT SERIALIZABLE. I tried serializing it and then adding it to the extras Bundle in the Intent and it just crashed saying that that was impossible to serialize due to BroadCastReciever. As this also deals with WIFI. Which I am highly considering separating out to be put with the BluetoothActivity in a future release.
I am also ASSUMING that Activity B will never just be started up by anything other than my MapsActivity class.
I am also new to Kotlin, but I know Java.
When I tried using an interface, I caused a StackOverflow error and I have no idea why.
I have read the documentation for Intents on the website.
I have done some research on here which gave me those ideas above. I am not sure how to implement them.
You are using the wrong approach. The solution requires a bit more work than you would think. The correct approach is to:
First, realize that these activities Activity A and Activity B (and any other activities) are activities that are specific to your application and you want to establish direct communication between them.
Second, realize that you are trying to get the current (or a previous) activity's context. The context will help serve the reference.
Third, you can create your own Activity and Application classes by extending the desired classes. The Application class is a low-level class used for the activities.
From here, you will be able to make use of the getApplicationContext() which will return your custom Application class.
Design: It is inside of your CustomApplication class that you must track the references to the activities that you want. From there all that you have to do is cast the getApplicationContext() to your CustomApplication class and then call your methods that access the Activity(ies). You must of course cast your Activities if you want to access certain instances of a specific activity that you created to its "type." For example:
MapsActivity mact = (MapsActivity)(((MyApplication)(this.getApplicationContext())).getCurrentActivity())
You must of course note that this activity must be already created (the onCreate method was already called) for this to return the current activity. The same of course goes for the other life-cycle methods for the activity as you will make a baseActivity which will deal with these as well as you will also have an Application life-cycle that will help deal with this too.
To answer the question: "How to get the current foreground activity context in android?" I turned to StackOverflow and found user: gezdy 's answer to be exactly what I needed at: How to get current foreground activity context in android?.
(BEGIN QUOTATION FROM: GEZDY)
You should manage activities references. Add the name of the
application in the manifest file :
<application
android:name=".MyApp"
....
</application>
Your application class :
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
Create a new Activity :
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (this.equals(currActivity))
mMyApp.setCurrentActivity(null);
}
}
So, now instead of extending Activity class for your activities, just
extend MyBaseActivity. Now, you can get your current activity from
application or Activity context like that :
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
(END OF QUOTATION FROM: GEZDY)
Note: All code is written in java for this answer.
This question already has answers here:
Calling activity class method from Service class
(7 answers)
Closed 5 years ago.
Here i am trying to call method of main activity class from Audio Service class.
but when i call the method like :-
new HomeActivity().previousChannel();
at that time activity class method get called but it also called oncreate() method automatically.
Please help me.
I will prefer you to use EventBus for communication between Classes,Fragments,Services whatever it may be.It is very simple, most reliable and efficient.
It can be achieved in just 3 Steps:
1.Define Events.
public static class MessageEvent { /* Additional fields if needed */ }
2.Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle:
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
3.Post Events.
EventBus.getDefault().post(new MessageEvent());
For more Details You can check here.
Hope it may help you.
you can use an interface with name MyCallBack that will be implemented by your activity with any method like do Something();
your activity will implement method of interface.
From your service class you need to call method of interface from variable of that interface type.
For that In your service class take a variable of type Interface like serviceCallBack and pass context of activity class in that variable.
from that variable you can call method of interface that will automatically take you to activity class and you can call your activity methods like update any UI component
I've been working on Xamarin for the past couple of years along with Android studio and I decided to create an application for a friend (full source code here https://github.com/nekrull/waiter don't be too harsh please :) )
The idea is that there is a base activity which exchanges fragments when a new screen should appear.
Fragments have everything that has to do with user interaction and the activity they are attached to handles the business logic.
To do this I have a base class CoreActivity/DataActivity which has some methods most Fragments use (like blocking the back button) and some helper methods (like calling a method on an attached fragment of a specific class) , a CoreInteraction that responds to this activity and
CoreFragment/AttachedFragment which is used as the base of all view fragments
so for example the view fragment would look like this:
public class GroupsFragment extends AttachedFragment<GroupsFragment.GroupsInteraction> {
//this is what we expect to be able to call in the parent
public interface GroupsInteraction extends CoreInteraction {
Group get_shown_group();
void new_group();
void select_parent();
}
}
which is basically a fragment that expects its attached activity to be able to respond to the interaction methods.
the activity fragment would look like this:
public class MainActivity extends DataActivity<MainData> implements
GroupsFragment.GroupsInteraction, (other interactions here) {
}
The problem is that since the application I'm working on has only one Activity with many small screens, the code inside the base activity will get big, that does not cause a problem with the application or compiling or anything else. But it makes it really hard to find what I'm looking for easily.
What I used to do in Xamarin is something like this:
public partial class MainActivity : DataActivity<MainData> {
}
for the initialization activity and then each interaction would get its own file like this:
public partial class MainActivity : GroupsInteraction {
}
It had the same effect (since the class is compiled as a single class) but the code would be tidy and easy to read.
Obviously there are no partial classes in Java, but is there a way to delegate the implementation of an interface to another class?
Something along the lines of saying "when you're invoking a method from interface a, invoke it from that class" without actually writing stuff like :
public Group get_shown_group() {
return new GroupHandler(this).get_shown_group();
}
public void new_group() {
new GroupHandler(this).new_group();
}
public void select_parent() {
new GroupHandler(this).select_parent();
}
Thanks in advance for any help you can provide
Something along the lines of saying "when you're invoking a method from interface a, invoke it from that class"
Taking you literally what you describe is plain delegation, a class does not implement some or any functionality itself, instead it wraps a class implementing the desired functionality, calling the methods of said wrapped class. You could even switch implementation at runtime, just changing the wrapped class as you go (assuming the classes share a common interface, of course). Of course that does not "spare" you from writing the delegations yourself.
class Wrapper implements GroupsInteraction {
private final GroupInteraction gi;
public Wrapper(GroupsInteraction gi) {
this.gi = gi;
}
Group get_shown_group() {
return this.gi.get_shown_group();
}
// ... other interface impls
}
Additionally, you should keep the GroupHandler as a member instead of creating a new Object each time, so
public Group get_shown_group() {
return new GroupHandler(this).get_shown_group();
}
becomes
public Group get_shown_group() {
return this.groupHandler.get_shown_group();
}
You can try Delegation Pattern
BaseActivity {
MyDelegateClass delegate;
void example() {
delegate.example();
}
}
P.S. both activity and delegate implements same interface
Details here
I'm planning to create a floating contextual menu for my app in a fragment after onLongClick and I also have a custom Adapter extending from RecyclerView.Adapter and a custom holder extending from RecyclerView.ViewHolder.
I found out there are 2 options to register :
Option 1 : Registering the listener inside onCreateViewHolder method by holder.itemView.setOnLongClickListener and retrieving any ViewHolder instance variable I want by calling holder.getSomeVariable() inside the event handler and set it to current instance variable so I can retrieve it from Activity/Fragment (because I can get reference of adapter from my fragment).
The advantage I notice is that it allows me to declare the implementation onCreateContextMenu() and onContextItemSelected() method and override them in my Fragment/Activity, which allows the reusing of the existing provided method and get the ViewHolder variables inside the onContextItemSelected().
I notice the downside is that we need to create extra setter and getter method in the adapter (because we cannot reference ViewHolder instance from Activity/Fragment).
Option 2 : Registering the click listener inside ViewHolder. According to this website ,the advantage is it allows more explicit click listener (I also have other listeners registered in the ViewHolder class, so they're group together which makes the code structure looks better).
However, I notice the downside from using this way is we cannot declare onCreateContextMenu() and onContextItemSelected() inside Activity/Fragment anymore because we cannot get the viewholder reference from Activity/Fragment, we can only get adapter reference. As a result, the readability is a bit worse. (I have a contextual_menu.xml, so will need to do the inflation in the viewholder as well instead of in fragment/activity. Is inflation of XML in viewholder even a correct practice?)
From what I understand, in general scenario , it's better to register listener in ViewHolder (Option 2).
But in my context, which method (Option 1 or Option 2) should I apply? Does the general scenario still apply (should I apply Option 2)?
Also are there any more advantages and disadvantages from those 2 listed options?
I use it in Activity or Fragment that way
1- Create interface like that:
public interface OnItemLongClickListener {
void onItemLongClick(int position);
}
EDIT:
2- In your Adapter ViewHolder class create a reference like that:
private OnItemLongClickListener listener;
3- In adapter create setter method to initialize listener which will call another setter method in ViewHolder class like that:
class Adapter extends RecyclerView.Adapter<YourViewHolder>{
.
.
.
.
public void setOnItemLongClickListener(OnItemLongClickListener listener){
viewHolderObject.setonItemLongClickListener(listener);
}
}
public class YourViewHolder extends RecyclerView.ViewHolder{
.
.
.
.
public void setOnItemLongClickListener(OnItemLongClickListener listener){
this.listener = listener;
}
}
4- In your ViewHolder in method onLongClick() do this:
#override
public boolean onLongClick(View v){
listener.onItemLongClick(getAdapterPosition());
}
5- In your Activity Do the contextual menu staff
I hope this help you.!
I am still fairly new to Android and I am trying to implement Achievements inside my app. I basically want to replicate the achievements implemented in the "Type-a-Number Challenge" sample app given on the Google play developer site here.
I have a first activity that contains the methods and classes to handle the achievements, and a second activity where I have the variables that would be forwarded to the first activity for "processing". I copied the code that I believed was necessary for doing this, but I am always getting a null pointer exception when calling the listener inside the second class.
Here is my listener in the second activity:
public interface Listener {
public void onEnteredScore(int score);
}
Listener mListener = null;
public void setListener(Listener l) {
mListener = l;
}
The null pointer exception is flagged here when I call the listener as such (where mRequestedScore is different to 0):
mListener.onEnteredScore(mRequestedScore);
The first activity's class implements the second activity listener like this:
public class FirstActivity extends BaseGameActivity
implements SecondActivity.Listener
And includes the onEnteredScore method as such
#Override
public void onEnteredScore(int requestedScore) {
checkForAchievements(requestedScore);
pushAccomplishments();
}
I am not entirely sure if the error appears because the listener is expecting a click or some action by the user, or the "linkage" is not being established properly between both activities.
I looked around for similar issues but haven't found anything yet.
Apologies if the mistake is obvious.
Thanks in advance for any help provided.
Your "linkage" isn't established, hence the null.
If you want to pass data between Activities (not fragments), you'll need to use the Intent framework - see How do I pass data between Activities in Android application?
The Interface method that you are following in the Type a Number Challenge is useful for passing data between Fragments and the parent Activity. That is what it is being used for in that example. You don't appear to be using Fragments.
For achievements, you are probably better served using a class attached to your FirstActivity. That class can then implement your Listener interface (if the interface is even useful at that point). Using a separate activity is far more heavyweight than is required.