So question. Which of the two is the proper way to do a callback?(Unless both of these are incorrect) Or does it depend on the case.
For example. Let's say i wanted to return something from a Fragment to its Activity.
1)I implement an interface in the Fragment and then on its onAttach I set the listener, and then implement the interface in the activity.
public class UrgentCareFragment{
public interface TestListener {
void finishedTest();
}
TestListener mEventListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_urgent_care_viewpager_fragment, container, false);
mEventListener.finishedTest();
return v;
}
#TargetApi(23)
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mEventListener = (TestListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement urgentCareListener");
}
}
/*
* Deprecated on API 23
* Use onAttachToContext instead
*/
#SuppressWarnings("deprecation")
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (Build.VERSION.SDK_INT < 23) {
try {
mEventListener = (TestListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement urgentCareListener");
}
}
}
}
Activity Class.
public class testActivity extends AppCompatActivity implements TestListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_urgent_care);
}
#Override
public void finishedTest(){
//do what you need to do
}
}
2) I create an interface class. In the Fragment I set the listener to the activities context by using getActivity. And then implement the interface in the activity.
Interface Class
public interface TestListener {
void finishedTest();
}
Fragment
public class UrgentCareFragment{
TestListener mEventListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mEventListener = (TestListener) getActivity();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_urgent_care_viewpager_fragment, container, false);
mEventListener.finishedTest();
return v;
}
}
Activity Class.
public class testActivity extends AppCompatActivity implements TestListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_urgent_care);
}
#Override
public void finishedTest(){
//do what you need to do
}
}
Which is the correct way? My main concern is the way the listener is set. Could either of these two cause issues. Or is there one i should throw out. Both seem to work properly, I am just trying to make sure what the correct way is, or if both are fine.
Thanks
Related
I am writing an android app using android studio. So far I have created a tabbed activity to be my main activity, and another activity that would be opened on a click of a button in one of the tabs in my main tabbed activity. The problem is that I have tried to accomplish this in a few ways but it seems like the code in my public View onCreateView just doesn't get executed at all. This is the code I'm trying to run:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
Button mainSignInButton = (Button) view.findViewById(R.id.mainSignInButton);
mainSignInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getActivity() ,LoginActivity.class);
startActivity(i);
}
});
return view;
}
I have also tried to add a simple toast message to this block of code to see if it gets executed but I didnt see the toast pop up as well...
First of all, delegate to Activity the startActivity(). Try something like follow on your fragment:
public class FragmentMain extends Fragment {
private OnInteractionListener mListener;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
Button mainSignInButton = (Button) view.findViewById(R.id.mainSignInButton);
mainSignInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListener.onClickSignInButton()
}
});
return view;
}
public interface OnInteractionListener {
void onClickSignInButton();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null
}
}
On your Activity try like follow:
public class MyActivity extends AppCompatActivity implements FragmentMain.OnInteractionListener {
...
#Override
public void onClickSignInButton() {
Intent i = new Intent(this, LoginActivity.class);
startActivity(i);
}
}
I am trying to send data from activity to fragment and vice versa using interfaces but getting an error of cycling inheritance involving MyFragment.
Implementing interface created in MyFragment:
public class MyActivity implements OnSendFromMyFragListener {
OnSendFromMyActivityListener mCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCallback.sendFromMyActivity(2);
}
#Override
public void sendFromMyFrag (int a) {
//do something
}
public interface OnSendFromMyActivityListener {
public void sendFromMyActivity(int b);
}
}
Implementing interface created in MyActivity:
public class MyFragment extends Fragment implements OnSendFromMyActivityListener {
OnSendFromMyFragListener mCallback;
public interface OnSendFromMyFragListener {
void sendFromMyFrag(int a);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallback = (OnSendFromMyFragListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString());
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_my, container, false);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCallback.sendFromMyFrag(1);
}
}
});
return view;
}
#Override
public void sendFromMyActivity(int b) {
//do something
}
}
Well the reason you are getting this error is because your Activity depends on your Fragment and Fragment depends on your Activity. Don't Agree?
Let me show you. Imagine you are a compiler in your work you stumbled across:
class A implements B.A {
interface B {
void foo1();
}
#Override
public void foo2()
{
// do something;
}
}
Now you know that class A depends on (implements) B.A, so before you go further into class A you move on to class B:
class B implements A.B {
interface A {
void foo2();
}
#Override
public void foo1()
{
// Do Something;
}
}
Now you see that class B depends on (implements) class A specifically class A.B! What do you (compiler) do? Go back to class A? But that depends on class B. So you see this becomes an unending cycle thus causing a cyclic dependency where both your class' definitions depend on each other.
As an alternative you could either create a member event listener or an anonymous one. Or if you don't like either of those options, you could also create a separate java interface class file for any one of the two interfaces.
Maybe you have to do this for Activity
public class MyActivity extends AppCompatActivity implements MyFragment.OnSendFromMyFragListener {
public interface OnSendFromMyActivityListener {
void sendFromMyActivity(int b);
}
OnSendFromMyActivityListener mCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyFragment myFragment = MyFragment.newInstance();
//Do the transaction.....
//And after this
mCallback.sendFromMyActivity(0);
}
public void setOnSendFromMyActivityListener(OnSendFromMyActivityListener mCallback){
this.mCallback = mCallback;
}
#Override
public void sendFromMyFrag(int a) {
//do something
}}
And this for Fragment
public class MyFragment extends Fragment implements OnSendFromMyActivityListener {
OnSendFromMyFragListener mCallback;
public interface OnSendFromMyFragListener {
void sendFromMyFrag(int a);
}
public static MyFragment newInstance() {
Bundle args = new Bundle();
MyFragment fragment = new MyFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallback = (OnSendFromMyFragListener) getActivity();
((MyActivity) getActivity()).setOnSendFromMyActivityListener(this);
} catch (ClassCastException e) {
throw new ClassCastException(context.toString());
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_place_suggest, container, false);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCallback.sendFromMyFrag(1);
}
});
return view;
}
#Override
public void sendFromMyActivity(int b) {
//do something
}
if you want you can put setters of the interface also to the Fragment for better abstraction.
Something you have to watch out is to look for nulls interfaces
Thanks
I want to pass some data from a fragment to an activity.
This question has been asked already many times, and this answer is the best i have found so far.
I have followed the official documentation, but I still haven't got any results. What I have so far in the fragment is:
public class DropPackageFourthFragment1 extends Fragment {
public DropPackageFourthFragment1() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v=inflater.inflate(R.layout.fragment_drop_package_fourth_fragment1, container, false );
passData("hellooooo");
return v;
}
//Pass data to activity
OnDataPass dataPasser;
#Override
public void onAttach(Context context) {
super.onAttach(context);
Activity a;
if (context instanceof Activity){
a=(Activity) context;
dataPasser = (OnDataPass) a;
}
}
public interface OnDataPass {
public void onDataPass(String data);
}
public void passData(String data) {
dataPasser.onDataPass(data);
}
}
And in the main activity i have:
public class DropPackageFourth extends AppCompatActivity implements DropPackageFourthFragment1.OnDataPass{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drop_package_fourth);
}
#Override
public void onDataPass(String data) {
Log.d("LOG","hello " + data);
}
}
The LogCat doesn't show anything, I feel like i'm missing something, but I cannot find what it is!
Any help would be appreciated!
Use EventBus.
https://github.com/greenrobot/EventBus
or RxAndroid's PublishSubject
https://github.com/ReactiveX/RxAndroid
The code is in fact working, I was just filtering the LogCat and i wasn't seeing anything!
I'm going insane!!
I don't manage to pass data from a fragment(A) to an another fragment(B).
I read about using a public interface... and it seems to work, but i don't understand how to use this method.
Fragment(A)
package it.anddev.pagertabs;
public class Page1Fragment extends Fragment {
String Str;
OnDataPass dataPasser;
Class Senddata extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
// do something [...]
}
#Override
protected String doInBackground(String... args) {
// do something [...]
dataPasser.onDataPass(result_array.toString());
}
return null;
}
protected void onPostExecute(String file_url) {
// do something [...]
}};
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
dataPasser = (OnDataPass) activity;
}
public interface OnDataPass {
public void onDataPass(String data);
}
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
// do something [...]
Button Avanti = (Button) view.findViewById(R.id.sendbutton);
Avanti.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
//mViewPager.setCurrentItem(1, true);
new Senddata().execute();
}
});
FragmentB
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
if (container == null) {
return null;
}
View view = (LinearLayout)inflater.inflate(R.layout.page2,container,false);
Button mostra = (Button) view.findViewById(R.id.mostrabutton);
// String str = i need to get string from "public void onDataPass"
mostra.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
//mViewPager.setCurrentItem(1, true);
Log.d("IT WORKS", str);
}
});
return view;
}
#Override
public void onDataPass(final String data) {
// TODO Auto-generated method stub
Log.d("okkkkkk", "" + data);
}
So finally, how i can get the string from the public void in the fragmentB?
Thanks
Consider my 2 fragments A and B, and Suppose I need to pass data from B to A.
Then create an interface in B, and pass the data to the Main Activity. There create another interface and pass data to fragment A.
Sharing a small example:
Fragment A looks like
public class FragmentA extends Fragment implements InterfaceDataCommunicatorFromActivity {
public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity;
String data;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void updateData(String data) {
this.data = data;
//data is updated here which is from fragment B
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
interfaceDataCommunicatorFromActivity = (InterfaceDataCommunicatorFromActivity) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement InterfaceDataCommunicatorFromActivity");
}
}
}
FragmentB looks like
class FragmentB extends Fragment {
public InterfaceDataCommunicator interfaceDataCommunicator;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// call this inorder to send Data to interface
interfaceDataCommunicator.updateData("data");
}
public interface InterfaceDataCommunicator {
public void updateData(String data);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
interfaceDataCommunicator = (InterfaceDataCommunicator) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement InterfaceDataCommunicator");
}
}
}
Main Activity is
public class MainActivity extends Activity implements InterfaceDataCommunicator {
public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void updateData(String data) {
interfaceDataCommunicatorFromActivity.updateData(data);
}
public interface InterfaceDataCommunicatorFromActivity {
public void updateData(String data);
}
}
The Most easiest way is create a static variable in first fragment and use this variable in second fragment.
Use a public interface to pass the String through the Activity that is containing the fragments. Here is simular question and solution with more detail.
Consider 2 fragments A and B and suppose I need to pass data from B to A.
Then create an interface in B, and pass the data to the Activity. From there you can call in A getActivity() to get the information.
Example:
Activity is:
public class MainActivity extends Activity implements InterfaceDataCommunicator {
public static String data;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void updateData(String data) {
this.data = data;
}
}
Fragment A:
public class FragmentA extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().data;//receive data
return super.onCreateView(inflater, container, savedInstanceState);
}
}
Fragment B:
class FragmentB extends Fragment {
public InterfaceDataCommunicator interfaceDataCommunicator;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
interfaceDataCommunicator.updateData(/*the String to send*/); //send data
}
public interface InterfaceDataCommunicator {
public void updateData(String data);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
interfaceDataCommunicator = (InterfaceDataCommunicator) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement InterfaceDataCommunicator");
}
}
}
This is my main activity:
public class MainActivity extends BaseGameActivity implements GameFragment.Listener {
GameFragment mGameFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGameFragment = new GameFragment();
mGameFragment.setListener(this);
}
#Override
public void onGameEnded(int score) {
...
}
}
And this is just a fragment to host my game.
public class GameFragment extends Fragment implements View.OnClickListener {
public interface Listener {
public void onGameEnded(int score);
}
Listener mListener = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.game_layout, container, false);
checkSequence();
return view;
}
public void setListener(Listener l) {
mListener = l;
}
private void checkSequence() {
if (mListener != null)
mListener.onGameEnded(score);
}
}
For some reason mListener is always null. I've tried other questions on SO but none of them have worked. What am I doing wrong?
I think you have to Override this two Methods in GameFragment
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof Listener ) {
mListener = (Listener) activity;
} else {
throw new ClassCastException(activity.toString()
+ " must implemenet GameFragment.Listener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener= null;
}
for more detail Read this Tutorial
EDIT
And Don't Forget to Initialize Fragment in Activity
// Create an instance of GameFragment
GameFragment mGameFragment= new GameFragment();
// Add the fragment to the 'fragment_container' Layout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, mGameFragment).commit();