the code below named Presenteter is my main class, and I am replacing the Fragment according to questions.
public class Presenteter extends AppCompatActivity {
private final Questions question1Fragment = new Questions();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.present);
FragmentTransaction ft=getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out);
ft.replace(R.id.flPersonalization, question1Fragment);
ft.commit();
}
This is my Questions class. It is getting the questions from REST server. All questions are listed in in one Spinner. I didn't write them here, in order not to confuse you.
public class Questions extends Fragment implements AdapterView.OnItemSelectedListener {
SearchableSpinner spinner;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.question, container, false);
LinearLayout ln=(LinearLayout)view.findViewById(R.id.listLayout);
spinner=(SearchableSpinner)view.findViewById(R.id.spinner1);
}
Finally I want to use Spinner's onItemSelected() event in my Presenter class.
How can I do this?
Thanks in advance.
You could do something like this in your Fragment:
Presenteter p = (Presenteter) getActivity();
// ...
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
p.yourMethod(); // call a method of your Presenteter class
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
I'm glad your question is answered but there is a better way for doing this.
If you are familiar with Rx stuff, that's one way to do it.
If Rx is not your cup of tea, you can use EventBus which simplifies exactly this kind of communication.
Link:
EventBus
I would suggest going for the latter if you are not sure.
Related
I am using a "Drawer Navigation" project using fragments and so far this method works:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Navigation.findNavController(view).navigate(R.id.nav_gallery);
}
});
But I want to use the navigation method inside a fragment class calling a function like this:
boolean b;
public void fragmentNavigation() {
if (b) {
Navigation.findNavController(getView()).navigate(R.id.nav_gallery);
}
}
I am a newbie using the navigation architecture and I still don't know if I need to declare some type of action listener for that function or how to make it work.
You can do that, but be careful of :
using getView() is Nullable; so you must make sure that your fragment has already created the view.
You can solve this by a couple of ways
First: Overriding onViewCreated() which has a nonNull view argument
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
fragmentNavigation(view);
}
boolean b;
public void fragmentNavigation(View view) {
if (b) {
Navigation.findNavController(view).navigate(R.id.nav_gallery);
}
}
Second: Create a View field in the fragment class, and set it within onCreateView()
View view;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.main_fragment, container, false);
return view;
}
then always call fragmentNavigation(view); on that view field.
Your fragment is hosted by the NavHostFragment of the Navigation Graph; so that you can avoid potential IllegalStateException
I got code from stack overflow to call a callback in a fragment from the Activity class.
I got the following code from stack overflow
fraKey fragment=(fraKey)getFragmentManager().findFragmentById(R.id.idFraKey);
I get the following error
inconvertable types cannot cast "android.app.fragment to com.example.mylib.keyfrag
the fragment code
public class fraKey extends Fragment implements View.OnClickListener {
int ted=0;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_fra_key, container, false);
}
public void onViewCreated(View view, Bundle savedInstanceState) {
View temp;
temp = view.findViewById(R.id.idUpdate);
temp.setOnClickListener(this);
temp = view.findViewById(R.id.idTest);
temp.setOnClickListener(this);
}
public void onClick(View v) {
ted++;
cKeys mKeys = new cKeys();
((actMyLib)getActivity()).updateKeya(mKeys);
}
} // end class
you just need this article. It's very helpful. Have a great day.
Is this a proper way of communication between fragments ?
public class MainActivity extends AppCompatActivity implements IFragmentsHandler {
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
}
#Override
protected void startFragment1() {
Fragment1 f1 = new Fragment1();
f1.setFragmentsHandler(this);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, f1)
.commit();
}
#Override
protected void startFramgment2() {
Fragment1 f2 = new Fragment1();
f2.setFragmentsHandler(this);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, f2)
.commit();
}
}
public class Fragment1 {
private IFragmentsHadnler fragmentsHandler;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment1, container, false);
//...Code...
fragmentsHandler.startFragment1();
}
public void setFragmentsHandler(IFragmentsHandler fragmentsHandler) {
this.fragmentsHandler = fragmentsHandler;
}
}
public class Fragment2 {
private IFragmentsHadnler fragmentsHandler;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment2, container, false);
//...Code...
fragmentsHandler.startFragment2();
}
public void setFragmentsHandler(IFragmentsHandler fragmentsHandler) {
this.fragmentsHandler = fragmentsHandler;
}
}
[EDIT1] : Posted the Interface (though it was obvious)
public interface IFragmentsHandler {
public void startFragment1();
public void startFragment2();
}
From my Java perspective this will throw OutOfMemoryError but I'm not if it is the same for the Android. Anyway what is the preferred way of communication between fragments?
According to android developer guide, communication between fragments is done through the associated Activity.
A fragment use his interface to communicate with the Activity. And the Activity deliver a message by capturing the Fragment instance with findFragmentById() or creating one if needed, then directly call the other fragment's public methods.
Fragment1 wants to pass some data: uses his interface method implemented by Activity.
Activity executes that method receiving the data, create&replace or find (depending on your layout) the Fragment2 and pass this data or execute some public method on fragment2 class (depending on your layout).
Fragment2 extract data from bundle or execute (depending on your layout) his public method to receive the data.
I think the problem in your code is you are misunderstanding interface purpose. You are using for start the same fragment who is calling the method. Fragment1 is calling startFragment1() in his onCreateView(), but it is already started.
If you needed, in here there is a good tutorial.
To communicate between components consider app architecture MVP, VIPER, etc. On code side it may use event bus for communication or just plain callbacks.
Do navigation in one place
Do business logic in another place
Do present-view logic in presenter
Do view logic in views, fragments, adapters
As you started, you can use interfaces to communicate between Fragments as suggested by Google.
But an easy way to communicate between fragments is by using event bus (which implements the publish/subscribe pattern) like EventBus library.
You can also use RxJava to create your own event bus and thus make communications between components of your app (have a look to this Stackoverflow question: RxJava as event bus?)
I have a main Activity in which I created a ViewPager that instantiate 3 other Fragments. One of these is a GridView which makes a popup appear when the user click on one item. Then, in this popup, I have a simple button.
What I want to do is: when the user click on this button, I would like to access a method in my main Activity (that should change the current item of my ViewPager) and then dismiss the popup.
I tried everything I could, but I cannot achieve this... I can set up the click event on my popup and dismiss it easily, but I didn't find out how I can access a method (or even a variable) from my popup to my main Activity.
I will put my most relevant code in here so you can understand the structure of my classes (hopefully...).
My main Activity:
public class MainActivity extends FirstActivity{
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.viewpager);
// Set an Adapter on the ViewPager
mViewPager.setAdapter(new MainActivity_Adapter(getSupportFragmentManager()));
public void onSaveInstanceState(Bundle savedInstanceState)
{
menuBar.onSaveInstanceState(savedInstanceState);
}}
My ViewPager activity:
public class MainActivity_Adapter extends FragmentPagerAdapter{
public MainActivity_Adapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
// Set the color background for each page
switch (position)
{
case 0:
return MainActivity_Inventory.newInstance();
case 1:
return MainActivity_Map.newInstance();
default:
return MainActivity_AR.newInstance();
}
}
// The number of Splash Screens to display
#Override
public int getCount()
{
return 3;
}}
My "Inventory" Fragment
public class MainActivity_Inventory extends Fragment implements View.OnClickListener{
public static MainActivity_Inventory newInstance()
{
MainActivity_Inventory frag = new MainActivity_Inventory();
Bundle b = new Bundle();
frag.setArguments(b);
return frag;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Select the layout
int layout;
layout = R.layout.activity_inventory_01;
// Inflate the layout resource file
View view = getActivity().getLayoutInflater().inflate(layout, container, false);
// Set the grid view
GridView gridview = (GridView) view.findViewById(R.id.inventory_gridView);
gridview.setAdapter(new InventoryImageAdapter(super.getActivity()));
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView parent, View v, int position, long id)
{
// Create a popup to show item details
createPopup();
}
});
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
}
public void createPopup()
{
DialogFragment newFragment = new PopupActivity_Inventory();
newFragment.show(getFragmentManager(), "itemDetails");
}
#Override
public void onClick(View v)
{
}}
And my popup dialog fragment:
public class PopupActivity_Inventory extends DialogFragment{
#Override
public Dialog onCreateDialog(final Bundle savedInstanceState)
{
// Build the alert dialog
final Dialog dialog = new Dialog(this.getActivity());
// Get the layout inflater
final LayoutInflater inflater = getActivity().getLayoutInflater();
// Set up the dialog box
dialog.setContentView(inflater.inflate(R.layout.activity_inventory_popup_01, null));
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.getWindow().setGravity(Gravity.TOP);
//dialog.getWindow().getAttributes().y = 100;
(dialog.findViewById(R.id.brick_button_01)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
// When button is clicked, ACCESS MAIN ACTIVITY!
dialog.dismiss();
}
});
return dialog;
}}
I really hope you can help me with this... I really need to get it working. Thank you very much!
If you need further details or explanation, please just tell me.
The best thing to do is use EventBus library. I have a demo app in which you can add items to RecyclerView from anywhere within the app using EventBus. You can use it as a reference to simply do something else instead of current task. Here is the link to the repo:
https://github.com/code-crusher/android-demos/tree/master/EventBusDemo
And if you want to understand how it works you can refer to my article, it explains how to make communications like this easy:
https://medium.com/#code_crusher/eventbus-for-android
Hope it helps. Happy coding :)
Read this https://developer.android.com/training/basics/fragments/communicating.html
Look for "To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity...."
Another way to achieve it is using an EventBus and post events by Fragments to be caught by Activities.
I am working on Android. I'm just trying to optimizing my code. Generally I have noticed so many issue which is optimize but due to some limited time we are not optimizing that. Here I have share my problem. basically in all application I have facing this same Issue.
Problem
What is the best way to handle signup Fragment and EditSignUp Fragment?
Description
Generally in my case I am making one single registration.xml and making two different Fragment RegistrationFragment.java and EditRegistrationFragment.java. Just like below.
RegistrationFragment.java
public class RagistrationFragment extends BaseFragment {
private TextView tvEmail;
private TextView tvLeaveIn;
private TextView tvUserName;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.registration, container, false);
return view;
}
public void inilialization()
{
tvUserName=(TextView)getView().findViewById(R.id.tvUserName);
tvLeaveIn=(TextView)getView().findViewById(R.id.tvLeaveIn);
tvEmail=(TextView)getView().findViewById(R.id.tvEmail);
}
EditRegistration.java
public class EditRagistrationFragment extends BaseFragment {
private TextView tvEmail;
private TextView tvLeaveIn;
private TextView tvUserName;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.registration, container, false);
return view;
}
public void inilialization()
{
tvUserName=(TextView)getView().findViewById(R.id.tvUserName);
tvLeaveIn=(TextView)getView().findViewById(R.id.tvLeaveIn);
tvEmail=(TextView)getView().findViewById(R.id.tvEmail);
tvEmail.setEnabled(false);
}
So here code is not reused. It's just a Example.Here I have define one method for initializing UI but this method is not reused. I know you can reuse this kind of method putting in BaseFragment but it's not proper way because baseFragment will extend by all Fragment in Application.initialization() is just one example.
I hope you are clear with my problem
Please give me proper suggestion.
Thanks,