im a new guy on this programming world so i guess this question is simple. So I have one imagebutton on my fragment and I whatI want is that when I click on it, it does a fragment transaction to another fragment; but the thing is that when I run the app and click on the imagebutton, it only "superimposes" the content of the other fragment into the one where the imagebutton is, of course what i want to do is just to go to the other fragment, ive been dealing with this for a while so I hope someone helps me, thanks.
Here is my java code of the fragment
public class inicio extends Fragment {
public inicio() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_inicio,container,false);
ImageButton luces = (ImageButton)view.findViewById(R.id.imageButton);
luces.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
interior interior= new interior();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.inicioo, interior).commit();
}
});
}
}
New code added...
public class transaction extends MainActivity
implements com.example.administradora.prueba.inicio.OnSelectedListener{
public void onButtonSelected() {
interior interior= new interior();
getSupportFragmentManager().beginTransaction().replace(R.id.inicioo, interior).commit();
}
}
but i get this error in the logcat:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.administradora.prueba/com.example.administradora.prueba.MainActivity}: java.lang.ClassCastException: com.example.administradora.prueba.MainActivity#20f8fe9b must implement OnSelectedListener
You shouldn't replace a Fragment from another Fragment. Try to do that through the Activity.
Define some interface for the Fragment to hold
public class MyFragment extends Fragment {
OnSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnSelectedListener {
public void onButtonSelected();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (OnSelectedListener ) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnSelectedListener");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_inicio,container,false);
ImageButton luces = (ImageButton)view.findViewById(R.id.imageButton);
luces.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Send the event to the host activity
if (mCallback != null) mCallback.onButtonSelected();
}
});
return view;
}
}
And swap the Fragment container in the interface implementation from the Activity.
public class MainActivity extends Activity
implements MyFragment.OnSelectedListener{
...
public void onButtonSelected() {
interior interior= new interior();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.inicioo, interior)
.commit();
}
}
The first two sections of Communicating with Other Fragments is what you are looking for.
Related
So basically, i have an activity called (Profile Activity) and two fragments connected to it (Profile view and profile edit fragment). Since im completely new with android studio, java language and fragments, im trying to place both fragments into activity but in a way that only profile view fragment is shown. Edit profile fragment needs to be hidden. Im using next part of the code:
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileViewFragment).commit();
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileEditFragment).commit();
I already tried something with "hide" and "show", but with no success. I have imported "android.support.v4.app.FragmentManager;" Thank you.
EDIT:
Profile activity after implementing new code:
public class ProfileActivity extends AppCompatActivity implements ProfileViewFragment.ProfileViewListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
//ovo ispod je za proslijedivanje iz activita u fragment
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
ProfileViewFragment profileViewFragment = new ProfileViewFragment();
ProfileEditFragment profileEditFragment=new ProfileEditFragment();
profileViewFragment.setArguments(getIntent().getExtras());
profileEditFragment.setArguments(getIntent().getExtras());
//getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileEditFragment).commit();
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileViewFragment).commit();
//getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, profileViewFragment).commit();
//FragmentManager fm=getSupportFragmentManager();
//fm.beginTransaction().setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out).show(new ProfileViewFragment()).commit();
//fm.beginTransaction().setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out).show(new ProfileEditFragment()).commit();
//-----------------------------------
}
#Override
public void onOpenProfileEditor() {
ProfileEditFragment profileEditFragment=new ProfileEditFragment();
profileEditFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, profileEditFragment).commit();
}
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof ProfileViewFragment) {
ProfileViewFragment profileFragment = (ProfileViewFragment) fragment;
profileFragment.setListener(this::onOpenProfileEditor);
}
}
}
Profile view fragment with new code:
public class ProfileViewFragment extends Fragment {
private Unbinder unbinder;
//novi kod sa stacka
private ProfileViewListener listener;
//-------------
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
FragmentProfileViewBinding viewBinding=DataBindingUtil.inflate(inflater, R.layout.fragment_profile_view, container, false);
View view=viewBinding.getRoot();
unbinder = ButterKnife.bind(this, view);
UserModel user = (UserModel) getArguments().get(ModelEnum.UserModel.name());
//viewBinding povezuje fragment i xml (proslijeduje user)
viewBinding.setUser(user);
//viewBinding.setUserGender(user);
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
// #OnClick(R.id.btn_change_settings)
// public void changeSettings(){
//getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, new ProfileEditFragment()).commit();
// }
#Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
//ISPOD JE NOVI KOD SA STACK OVERFLOWA
public interface ProfileViewListener{
void onProfileEditor();
}
public void setListener(ProfileViewListener listener) {
this.listener = listener;
}
#OnClick(R.id.btn_change_settings)
public void onEdit(View view){
if(listener!=null){
onOpenProfileEditor();
}
}
}
Instead of
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileEditFragment).commit();
It must be
getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, profileEditFragment).commit();
This will replace your fragment, instead of adding it.
Please, also note that you must call "add" for the first time and use "replace" afterwards.
You may find more about fragments here: https://developer.android.com/training/basics/fragments/fragment-ui
EDIT
For the new issue you have outlined, the solution is to "report" you activity that an event had happened, so it can take action. Here is how to do that.
First, we need an interface (you can add it inside you Profile fragment) and to link the activity to our fragment, if it implements that interface.
public class ProfileViewFragment extends Fragment {
...
...
private ProfileViewListener listener;
...
...
#OnClick(R.id.btn_change_settings)
public onEdit(View view) {
// If there is anyone listening, report that we need to open editor
if (listener != null) {
listener .onOpenProfileEditor();
}
}
public void setListener(ProfileViewListener listener) {
this.listener = listener;
}
// The interface
public interface ProfileViewListener {
void onOpenProfileEditor();
}
}
And in the class, we need to implement the interface and subscribe as a listener.
public class ProfileActivity extends AppCompatActivity implements ProfileViewFragment.ProfileViewListener {
...
...
#Override
public void onOpenProfileEditor() {
ProfileEditFragment profileEditFragment=new ProfileEditFragment();
profileEditFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager()
.beginTransaction
.replace(R.id.profile_fragment, profileEditFragment)
.commit();
}
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof ProfileViewFragment) {
ProfileViewFragment profileFragment = (ProfileViewFragment) fragment;
profileFragment.setListener(this);
}
}
}
You may find more detail on Activity-Fragment communication here - https://developer.android.com/training/basics/fragments/communicating
I have two fragment Parent and child, And Now I am trying to get some value from childFragment to parentFragment using callback.
Here is what i have tried so far:
Adding childfragment
activity.getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frame_layout, fragment).addToBackStack(null)
.commit();
Now on buttonClick of childFragment i want to get response to parentFragment.
Example:
nearestCenter.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getFragmentManager() != null) {
getFragmentManager().popBackStack();
}
}
});
P.S
I know how to do with Activity to Fragment but is there any way to get callback from fragment to frag.
You can use below code. Of course you should be careful about class cast exception and null pointer exception.
private void callParentFragmentMethod(){
ParentFragment f = (ParentFragment) getParentFragment();
f.someMethod();
}
You can use interface to interact like this :
public interface MyInterface{
void sendMessageToParent(Parameters parameter);
}
Now implement this on your parent fragment like this -
public class ParentFragment implements MyInterface{
public static Myinterface myinterface;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
// Register your interface like this.
myinterface = this;
return view;
}
#Override
public void sendMessage(Parameters Parameters){
}
}
Now from child activity call it like this:-
if(ParentFragment.myinterface!=null){
ParentFragment.myinterface.sendMessageToParent(parameters);
}
This will do. And make sure in onDestroy of parent you assign it null like this:-
myinterface = null;
Hope this helps.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I want to pass data from an activity to a fragment, using an interface.
Please have a look at the code snippets below:
Interface:
public interface FragmentCommunicator {
public void passData(String name);
}
MainActivity:
public class MainActivity extends AppCompatActivity{
FragmentCommunicator fragmentCommunicator;
private Fragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b = (Button) findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragment= new Fragment();
fragmentCommunicator = (FragmentCommunicator) getApplication();
fragmentCommunicator.passData("hello");
getSupportFragmentManager().beginTransaction().replace(R.id.container ,fragment).commit();
}
});
}
}
Fragment:
public class Fragment extends android.support.v4.app.Fragment implements FragmentCommunicator {
FragmentCommunicator communicator;
Context c;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, null);
return view;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.c = context;
}
#Override
public void passData(String name) {
Toast.makeText(c, name, Toast.LENGTH_SHORT).show();
}
}
I just want to pass some string when I click on button, (or some other event) to launch a fragment, and when the fragment is launched, it should show a toast containing that string...
Please help
any help would be appreciated.
Write this line of code after onCreate method.
public void passVal(FragmentCommunicator fragmentCommunicator) {
this.fragmentCommunicator = fragmentCommunicator;
}
Something like this
public class MainActivity extends AppCompatActivity{
FragmentCommunicator fragmentCommunicator;
private Fragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b = (Button) findViewById(R.id.button);
fragment= new Fragment();
//App is crasing for this line. Working fine by removing it
//fragmentCommunicator = (FragmentCommunicator) getApplication();
//fragmentCommunicator.passData("hello");
getSupportFragmentManager().beginTransaction().replace(R.id.container ,fragment).commit();
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragmentCommunicator.passData("Hello");
}
});
}
//Here is new method
public void passVal(FragmentCommunicator fragmentCommunicator) {
this.fragmentCommunicator = fragmentCommunicator;
}
}
Then write this line of code into onCreateView() of your fragment. Something like this
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, null);
((MainActivity) getActivity()).passVal(new FragmentCommunicator() {
#Override
public void passData(String name) {
Toast.makeText(c, name, Toast.LENGTH_SHORT).show();
}
});
return view;
}
Note: no need to implement FragmentCommunicator interface in your fragment. Hope it works. It works for me. I have tested
Activities contain fragments, you shouldn't need to pass anything. One technique would be to store your data in the activity scope and get a reference to it with getActivity().
Best practice to reference the parent activity of a fragment?
As far as the code you posted, I don't see where you call your pass data method within the fragment. I would suggest calling it in onviewcreated().
I will attempt to provide some sample code later as doing this on my mobile device is proving difficult.
Try passdata (getActivity ().someStringVariable);
In your Fragment class, have a TAG field. Naming a fragment Fragment can be a bit confusing as it is the same name as an Android Fragment, so I will use ExampleFragment:
public class ExampleFragment extends android.support.v4.app.Fragment implements FragmentCommunicator {
public static final String TAG = "ExampleFragment";
// ...
}
Now, when you replace the fragment in the activity, make sure to pass the TAG:
getSupportFragmentManager().beginTransaction().replace(R.id.container ,fragment, ExampleFragment.TAG).commit();
Note that in your case it would be Fragment.TAG, but I used ExampleFragment to clarify that Fragment.TAG is not part of the Android SDK.
To get a reference of your fragment in your activity, use the FragmentManager to find your fragment:
Fragment myFragment = getSupportFragmentManager().findFragmentByTag(ExampleFragment.TAG);
You can then make sure that myFragment is not null and cast it to FragmentCommunicator:
if (myFragment != null) {
fragmentCommunicator = (FragmentCommunicator) myFragment;
}
Note that in your example fragmentCommunicator = (FragmentCommunicator) getApplication(); is invalid because it is your fragment that is implementing the interface, not your application.
I have a main activity class, and a private inner class within the main activity. The private inner class has methods that when called will display fragments. This inner class implements an interface defined in the Fragment's class, to be used as a sort of callback. It is probably easiest to show through code.
public class MainActivity extends FragmentActivity {
//on a button clicked
EditItemManger em = new EditItemManager();
em.begin();
private class EditItemManager implements on EditItemFragment.EditedItemClickedListener{
//consructor, other stuff. no onCreate method because this inner class does not (explicity??) extend activty
public void begin(){
EditItemFragment editItemFrag = new EditItemFragment();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(editItemFrag, EDIT_FRAG_TAG)
fragmentTransaction.commit();
}
#Override
public void onEditItemClicked() {
editFinish();
}
public void editFinish()
{
// other stuff
}
}
}
My EditItemFragment class, where the onAttach method always has a null activity parameter
public class EditItemFragment extends DialogFragment {
protected EditedItemClickedListener editedItemClickedListener;
protected ImageButton button;
public EditItemFragment(){}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
final Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.edit_name_fragment, container, false);
button = (ImageButton) view.findViewById(R.id.submit_new_item_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
editedItemClickedListener.onEditedItemButtonClicked();
}
});
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
editedItemClickedListener= (EditedItemClickedListener) activity;
} catch (ClassCastException e) {
e.printStackTrace();
}
}
public interface OnEditNameButtonClickedListener {
public void onEditNameButtonClicked();
}
So because the parameter in onAttach() in my Fragment class is always null, it eventually causes a null pointer exception. I am wondering if it is because the fragment is called from a class that is not extending activity. The problem is that if this class extends activity, there will be an issue with trying to commit the Fragment Transaction
I guest your onAttach returns nullpointer exception. Its because your parent Activity the main activity doesnt implement your custom interface so it return null. See the code below let me know if it help you:
public class MainActivity extends FragmentActivity implements EditItemFragment.EditedItemClickedListener{
private DialogFragment editItemDialog;
//Do your code here
#Override
public void onEditItemClicked() {
editFinish();
}
public void showDialog(){
//this is for showing your custom dialog fragment
editItemDialog = EditItemFragment.newInstance();
editItemDialog.show(getSupportFragmentManager(),"editItemDialog");
}
}
this is for your EditItemFragment:
public class EditItemFragment extends DialogFragment{
//Do your code here
public static EditItemFragment newInstance(){
EditItemFragment editItemDialog = new EditItemFragment();
return editItemDialog;
}
}
I have this interface in my activity.
public interface LogoutUser {
void logout();
}
My fragment implements this interface, so in my fragment, I have this:
#Override
public void logout() {
// logout
}
In my activity I call
mLogoutUser.logout();
Where mLogoutUser is of the type LogoutUser interface.
My issue is the mLogoutUser object that is null. How can initialize it?
Thank you!
As I said in my comment, I resolved this issue using onAttach method in my fragment, but in this way you have to have the callback field (mLogoutUser in this case) declared in the fragment, and initialize it this way:
public class MyFragment extends ListFragment {
LogoutUser mLogoutUser;
// Container Activity must implement this interface
public interface LogoutUser {
public void logout();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mLogoutUser = (LogoutUser) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement LogoutUser");
}
}
...
}
More info in Communicating with Other Fragments.
But if your case is the field declared in the activity, you can use the onAttachFragment method from your activity to initialize your listener field this way:
#Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
mLogoutUser = (LogoutUser) fragment;
}
Also, you can use an event bus to make this communication between fragments and activities. An option is the Otto library, from Square.
Sample for creating callback from Fragment to Activity
public interface CallBackListener {
void onCallBack();// pass any parameter in your onCallBack which you want to return
}
CallBackFragment.class
public class CallBackFragment extends Fragment {
private CallBackListener callBackListener;
public CallBackFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_call_back, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//getActivity() is fully created in onActivityCreated and instanceOf differentiate it between different Activities
if (getActivity() instanceof CallBackListener)
callBackListener = (CallBackListener) getActivity();
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button btn = (Button) view.findViewById(R.id.btn_click);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(callBackListener != null)
callBackListener.onCallBack();
}
});
}
}
CallbackHandlingActivity.class
public class CallbackHandlingActivity extends AppCompatActivity implements CallBackListener
{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_all_user);
}
#Override
public void onCallBack() {
Toast.makeText(mContext,"onCallback Called",Toast.LENGTH_LONG).show();
}
}
Android Fragments - Communicating with Activity
You need to get a reference to your fragment with getFragmentById() or getFragmentByTag()
getFragmentManager().findFragmentById(R.id.example_fragment);
You can use kotlinx Channel to send data or callback between fragments and activity or vice versa
In your Mainactivity:
val loginPromptChannel = Channel<LoginPromptState>()
val loginStateFlow = loginPromptChannel.receiveAsFlow()
//onCreate
lifecycleScope.launchWhenStarted {
loginStateFlow.collect() { state ->
when (state) {
is LoginPromptState.Login -> {
//smooth scroll to login fragment
binding.viewpager.setCurrentItem(2, true)
}
}
}
}
//create sealed a class
sealed class LoginPromptState {
object Login : LoginPromptState()
}
In your fragment send callback like:
lifecycleScope.launch {
val channelLogin = (activity as MainActivity).loginPromptChannel
channelLogin.send(MainActivity.LoginPromptState.Login)
}