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");
}
}
}
Related
My problem is that i have a recyclerview implemented on a fragment that uses Room. RecyclerView, Adapter and Database need to be together in one class (i guess).
My problem is that if I put them into StudentActivity,
recyclerView = findViewById(R.id.SubjectRecyclerView);
will be null, because the Fragment won't be available by the time this function called.
If i put them into StudentSubjectsFragment,
everything would be good, but NewSubjectDialogFragment tells me that StudentActivity needs to implement NewSubjectDialogFragment because of this:
private NewSubjectDialogListener listener;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentActivity activity = getActivity();
if (activity instanceof NewSubjectDialogListener) {
listener = (NewSubjectDialogListener) activity;
} else {
throw new RuntimeException("Activity must implement the NewSubjectDialogListener interface!");
}
}
If at the
FragmentActivity activity = getActivity();
line somehow I would be able to call the getActivity() function of StudentSubjectsFragment class, I think it would solve my problem, and then the class that would implement the NewSubjectDialogFragment would be the StudentSubjectsFragment instead of StudentActivity.
I tried this:
FragmentActivity activity = getActivity().getSupportFragmentManager().findFragmentByTag("StudentSubjectsFragment").getActivity();
But activity is null.
StudentSubjectsFragment class:
public class StudentSubjectsFragment extends Fragment
implements NewSubjectDialogFragment.NewSubjectDialogListener,
SubjectAdapter.SubjectClickListener {
public static final String TAG = "StudentSubjectsFragment";
private RecyclerView recyclerView;
private SubjectAdapter adapter;
private SubjectDatabase database;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.student_subjects, container, false);
FloatingActionButton fab = rootView.findViewById(R.id.fabbb);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new NewSubjectDialogFragment().show(getActivity().getSupportFragmentManager(), NewSubjectDialogFragment.TAG);
}
});
database = Room.databaseBuilder(
getActivity(),
SubjectDatabase.class,
"subject-list"
).build();
recyclerView = rootView.findViewById(R.id.SubjectRecyclerView);
adapter = new SubjectAdapter(this);
loadItemsInBackground();
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(adapter);
return rootView;
}
private void loadItemsInBackground() {
new AsyncTask<Void, Void, List<Subject>>() {
#Override
protected List<Subject> doInBackground(Void... voids) {
return database.subjectDao().getAll();
}
#Override
protected void onPostExecute(List<Subject> subjects) {
adapter.update(subjects);
}
}.execute();
}
#Override
public void onItemChanged(final Subject item) {
new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... voids) {
database.subjectDao().update(item);
return true;
}
#Override
protected void onPostExecute(Boolean isSuccessful) {
Log.d("StudentActivity", "Subject update was successful");
}
}.execute();
}
#Override
public void onItemDeleted(final Subject item) {
new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... voids) {
database.subjectDao().deleteItem(item);
return true;
}
}.execute();
}
#Override
public void onSubjectCreated(final Subject newItem) {
new AsyncTask<Void, Void, Subject>() {
#Override
protected Subject doInBackground(Void... voids) {
newItem.id = database.subjectDao().insert(newItem);
return newItem;
}
#Override
protected void onPostExecute(Subject subject) {
adapter.addItem(subject);
}
}.execute();
}
}
StudentActivity class:
public class StudentActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_student);
ViewPager vpProfile = findViewById(R.id.vpStudent);
vpProfile.setAdapter(new StudentPagerAdapter(getSupportFragmentManager()));
}
}
NewSubjectDialogFragment class:
public class NewSubjectDialogFragment extends DialogFragment {
private EditText nameEditText;
public static final String TAG = "NewSubjectDialogFragment";
public interface NewSubjectDialogListener {
void onSubjectCreated(Subject newItem);
}
private NewSubjectDialogListener listener;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentActivity activity = getActivity().getSupportFragmentManager().findFragmentByTag("StudentSubjectsFragment").getActivity();
if (activity instanceof NewSubjectDialogListener) {
listener = (NewSubjectDialogListener) activity;
} else {
throw new RuntimeException("Activity must implement the NewSubjectDialogListener interface!");
}
}
private boolean isValid() {
return nameEditText.getText().length() > 0;
}
private Subject getSubject() {
Subject subject = new Subject();
subject.name = nameEditText.getText().toString();
return subject;
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(requireContext())
.setTitle(R.string.new_subject_item)
.setView(getContentView())
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if (isValid()) {
listener.onSubjectCreated(getSubject());
}
}
})
.setNegativeButton(R.string.cancel, null)
.create();
}
private View getContentView() {
final View contentView = LayoutInflater.from(getContext()).inflate(R.layout.dialog_new_subject_item, null);
nameEditText = contentView.findViewById(R.id.SubjectNameEditText);
return contentView;
}
}
I think there is a way to change NewSubjectDialogFragment to work with StudentSubjectsFragment but I am a beginner in android developing and don't know how to do it.
Solution of Mike M. worked perfectly.
The working code parts are the following:
NewSubjectDialogFragment:
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Fragment fragment = getParentFragment();
if (fragment instanceof NewSubjectDialogListener) {
listener = (NewSubjectDialogListener) fragment;
} else {
throw new RuntimeException("Fragment must implement the NewSubjectDialogListener interface!");
}
}
StudentSubjectFragment:
FloatingActionButton fab = rootView.findViewById(R.id.fabbb);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new NewSubjectDialogFragment().show(getChildFragmentManager(), NewSubjectDialogFragment.TAG);
}
});
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
This is a very strange behavior and I don't know how to fix it.
I have an Activity as a Presenter (In a MVP Architecture).
When the activity starts, I attach a Fragment as a View. The fragment itself is very simple.
public class CurrentSaleFragment extends BaseFragment {
private MainMVP.SalesPresenterOps salesPresenterOps;
private SaleAdapter adapter;
private ListView lv;
#BindView(R.id.btn_sell)
FloatingActionButton btnAdd;
public static CurrentSaleFragment newInstance(){
CurrentSaleFragment fragment = new CurrentSaleFragment();
Bundle arguments = new Bundle();
arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_quick_sale );
fragment.setArguments(arguments);
return fragment;
}
#Override
protected void init() {
super.init();
lv = (ListView)view.findViewById(R.id.lv_sale);
}
#OnClick(R.id.btn_sell)
public void addToSale(View view){
mPresenter.moveToFragment(SellProductFragment.newInstance());
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
salesPresenterOps = (MainMVP.SalesPresenterOps)context;
}
#Override
public void onDetach() {
salesPresenterOps = null;
super.onDetach();
}
}
The BaseFragment from which this fragmend extends :
public class BaseFragment extends Fragment implements MainMVP.RequiredViewOps, View.OnClickListener,
LoaderRequiredOps{
protected View view;
protected MainMVP.PresenterOps mPresenter;
protected final static String LAYOUT_RES_ID = "layout_res_id";
#Override
public void showOperationResult(String message, final long rowId) {
Snackbar.make(view, message, Snackbar.LENGTH_LONG).setAction(
R.string.see, new View.OnClickListener() {
#Override
public void onClick(View v) {
onOperationResultClick(rowId);
}
}
).show();
}
#Override
public void showSnackBar(String msg) {
Snackbar.make(view, msg, Snackbar.LENGTH_SHORT).show();
}
#Override
public void showAlert(String msg) {}
protected void onOperationResultClick(long rowId){}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mPresenter = (MainMVP.PresenterOps)context;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
this.view = inflater.inflate(getArguments().getInt(LAYOUT_RES_ID), null);
init();
return view;
}
protected void addToClickListener(View ... params){
for (View v : params){
v.setOnClickListener(this);
}
}
protected void init() {
if (view != null){
ButterKnife.bind(this, view);
}
}
#Override
public void onDetach() {
mPresenter = null;
Log.d(getClass().getSimpleName(), "Fragment was detached");
super.onDetach();
}
#Override
public void onClick(View v) {}
#Override
public void onPreLoad() {
Dialogs.buildLoadingDialog(getContext(), "Loading...").show();
}
#Override
public void onLoad() {}
#Override
public void onDoneLoading() {
Dialogs.dismiss();
}
}
When I enter the method 'moveToFragment()' I just replace CurrentSaleFragment for a new Fragment:
protected void addFragment(BaseFragment fragment){
mView = fragment;
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_holder,
fragment, null).addToBackStack(null).commit();
}
Then the new fragment is attached:
public class SellProductFragment extends BaseFragment{
private ListView listView;
private ProductListAdapter adapter;
private MainMVP.SalesPresenterOps mSalesPresenter;
public static SellProductFragment newInstance(){
SellProductFragment fragment = new SellProductFragment();
Bundle arguments = new Bundle();
arguments.putInt(LAYOUT_RES_ID, R.layout.fragment_inventory);
fragment.setArguments(arguments);
return fragment;
}
private void reload(){
final Loader loader = new Loader(this);
loader.execute();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mSalesPresenter = (MainMVP.SalesPresenterOps)context;
}
#Override
protected void init() {
super.init();
listView = (ListView)view.findViewById(R.id.lv_inventory);
reload();
FloatingActionButton button = (FloatingActionButton)view.findViewById(R.id.btn_add);
addToClickListener(button);
}
#Override
public void onLoad() {
adapter = new ProductListAdapter(getActivity().getApplicationContext(), R.layout.row_product_item,
mSalesPresenter.getProducts());
try{
updateListView();
}catch (Exception e){
Log.w(getClass().getSimpleName(), e.getMessage());
}
}
private void updateListView(){
if (adapter != null && listView != null){
listView.setAdapter(adapter);
}else{
throw new RuntimeException();
}
}
}
See that This fragment also extends from BaseFragment and implements LoaderRequiredOps. The interface is used to 'load' any data. It adds a dialog and updated the adapter when the loading is done:
public class Loader extends AsyncTask<Void, Void, Void> {
private LoaderRequiredOps presenter;
public Loader(LoaderRequiredOps presenter){
this.presenter = presenter;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
presenter.onPreLoad();
}
#Override
protected Void doInBackground(Void... params) {
presenter.onLoad();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
presenter.onDoneLoading();
presenter = null;
}
}
Now, when I try to execute the method reload() from the SellProductFragment i get the 'Only the original thread that created a view hierarchy can touch its views.'
This does not happen if the SellProductFragment is attached first instead of CurrentSaleFragment.
What is happening here?
Your Async Loader class calls the presenters method onLoad() from a background thread during doInBackground().
My guess is that in the onLoad() method of the presenter, a view is referenced.
In order to change the view at this point, post the view logic as a Runnable to the UI thread (you said your presenter is the activity, so this should be possible from the onLoad method).
#Override
public void onLoad() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your ui code here...
}
});
// Rest of your code here...
}
For an unknown reason, an unidentified configuration allows to execute the setting of an adapter for a ListView on the doInBackground() method.
Moved it to onPostExecute() and now it's working
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
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();