Passing data into multiple fragments that uses one container - android

First time posting here and also a new developer for Android Apps.
Desire Function of Example App:
1) Activity starts in fullscreen A
2) Fragment B then populates/inflates container of A fullscreen
3) Fragment B has a button, button is press
4) Fragment B is now replaced with Fragment C
5) Fragment C is now full screen and has data that is inputted by users, user then hits button to send to next Fragment
6) Fragment C is replaced with Fragment D and presents data to view which was inputted from Fragment C
Summary Functionality:
I am trying to keep everything on one screen going from
A (Activity) -> B (Fragment replace) -> C (Fragment replace to type data) -> D (Fragment replace and see last fragment data)
Problem/Issue
My code crashes when I try to populate the last screen with data obviously. It seems to throw an error in MainActivity at this specific line when I debug it
CartFragmentCode addCartInfoTextFragment = (CartFragmentCode) getSupportFragmentManager().findFragmentById(R.id.maincontainer);
I am definitely passing the values correctly through the interface I created, but during the debug process, I found out that my current program is trying to populate information into the same container since it seems like it didn't commit yet to replace the fragment to assign the variables to the right UI.
I was checking if I was able to replace the Fragment C with D, and I was able to only if I remove that above line of code.
Code Below
Main
public class MainActivity extends FragmentActivity implements OrderFragmentCode.FragUIListeners{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Fragment AllMenu = new AllMenuFragmentCode();
FragmentManager fragManager = getSupportFragmentManager(); //getSupportFragmentManager setup
FragmentTransaction ft = fragManager.beginTransaction(); //setup fragmentTranscation = ft
ft.add(R.id.maincontainer, AllMenu);
ft.commit();
}
#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;
}
public void onCartButtonClicked(String editFood, String editType, String editName){
CartFragmentCode addCartInfoTextFragment = (CartFragmentCode) getSupportFragmentManager().findFragmentById(R.id.maincontainer);
addCartInfoTextFragment.UpdateCartTexts(editFood, editType, editName);
}}
Fragment A
public class AllMenuFragmentCode extends Fragment implements OnClickListener {
private Button Order;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.all_menu_fragment, container, false);
Order = (Button) view.findViewById(R.id.orderButton);
Order.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
Fragment OrderFragmentCode = new OrderFragmentCode();
FragmentManager fragManager = getFragmentManager(); //getSupportFragmentManager setup
FragmentTransaction ft = fragManager.beginTransaction(); //setup fragmentTranscation = ft
ft.replace(R.id.maincontainer, OrderFragmentCode);
ft.addToBackStack(null);
ft.commit();
}}
Fragment C
public class OrderFragmentCode extends Fragment implements OnClickListener {
FragUIListeners activityCallback;
public interface FragUIListeners {
public void onCartButtonClicked(String foodText, String typeText, String nameText);
}
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
activityCallback = (FragUIListeners) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement FragUIListeners");
}
}
private EditText editTextFood;
private EditText editTextType;
private EditText editTextName;
private Button AddToCartButton;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.order_fragment, container, false);
editTextFood = (EditText) view.findViewById(R.id.editText);
editTextType = (EditText) view.findViewById(R.id.editText2);
editTextName = (EditText) view.findViewById(R.id.editText3);
AddToCartButton = (Button) view.findViewById(R.id.addToCart);
AddToCartButton.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
Fragment Cart = new CartFragmentCode();
FragmentManager fragManager = getFragmentManager();
FragmentTransaction ft = fragManager.beginTransaction();
ft.replace(R.id.maincontainer, Cart);
ft.addToBackStack(null);
ft.commit();
activityCallback.onCartButtonClicked(editTextFood.getText().toString(), editTextType.getText().toString(), editTextName.getText().toString());
}}
Fragment D
public class CartFragmentCode extends Fragment{
private TextView foodView;
private TextView typeView;
private TextView nameView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.cart_fragment, container, false);
foodView = (TextView) view.findViewById(R.id.foodView);
typeView = (TextView) view.findViewById(R.id.typeView);
nameView = (TextView) view.findViewById(R.id.nameView);
return view;
}
public void UpdateCartTexts(String editfood, String edittype, String editname)
{
foodView.setText(editfood);
typeView.setText(edittype);
nameView.setText(editname);
}}
--Final Say--
Sorry for the long post, this has been bugging me for HOURS and I even tried to use bundles and setting the arguements but I wasnt able to get that working either (I thought if i were able to obtain values correctly I could work around and use this to assign values to my textviews through getArguments on my last Fragment).
Please help!!!! Thanks!!!

In the line CartFragmentCode addCartInfoTextFragment = (CartFragmentCode) getSupportFragmentManager().findFragmentById(R.id.maincontainer);
findFragmentById sholule be passed that you use as 2nd argument in add while adding fragment to container for e.g. ft.add(R.id.maincontainer, AllMenu); if you want to get this fragment then you use findFragmentById(AllMenu) which is the tag that is associated with the fragment. R.id.maincontainer is the container in which that fragment is being displayed.

I guess the problem is you call onCartButtonClicked inside fragment C (where fragment C still exist) so the fragment D isn't created and take C place yet.
Try to call onCartButtonClicked by a Handler in your MainActivity

This is was one of my resource at the time to mimic a solution (he was using two fragments in one activity, while my app is trying to use one activity and replacing the main framelayout): http://www.techotopia.com/index.php/Using_Fragments_in_Android_-_A_Worked_Example
After playing around with example codes and using the available documentations. I cannot use these two lines to transfer the information as suggested in my MainActivity:
CartFragmentCode addCartInfoTextFragment = (CartFragmentCode) getSupportFragmentManager().findFragmentById(R.id.maincontainer);
addCartInfoTextFragment.UpdateCartTexts(editFood, editType, editName);
I think I finally found a workaround or a solution? I am not sure if this is the correct way of passing information to fragments or other classes, but here it is...
I basically Took away those two lines and rework my MainActivity's Click method and changed it to this...
public void onCartButtonClicked(String editFood, String editType, String editName){
CartFragmentCode.passFood = editFood;
CartFragmentCode.passType = editType;
CartFragmentCode.passName = editName;
}
I then went to my last fragment Code which was OrderFragmentCode.java and declared my Strings to retrieve them at the top of the Class and they were...
public static String passFood;
public static String passType;
public static String passName;
I then took the those values and setText them to my textViews. Wallah! It works as intented, however I am not sure if this is the right way to do things... If you guys are able to find a more professional way to handle data across multiple fragments, please let me know!

Related

Executing lifecycle method of backstack fragment problem in android

I have an activity with two fragment and want to be executed first fragment when its back from second fragment using back button. And i am using the add() when navigating first fragment to second fragment. Here is my scenario and code snippet:
First fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.one_fragment, container, false);
final Button button = (Button) view.findViewById(R.id.buttonChange);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
buttonClicked(v);
}
});
return view;
}
public void buttonClicked(View view) {
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_Container, new TwoFragment());
fragmentTransaction.addToBackStack("sdfsf");
fragmentTransaction.commit();
}
Moving to Second fragment and here is the code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.two_fragment, container, false);
return view;
}
The problem is that, When I am navigating from first to second fragment and then back again in the first fragment using back button first fragment lifecycle method is not executing. Instead of using add() if I use replace() then lifecycle method are executing properly. I know its the difference between add() and replace() but I want to use add() and also want to have navigation callback to handle some logic when I back in the first fragment using back button.
Also tried below code:
fragmentManager.addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
Log.e(TAG, "onBackStackChanged: ");
// Update your UI here.
}
});
But its also calling multiple times and creating anomalies.
How can I handle this? Specially handle some logic in first fragment when I back from second fragment.
The easiest way I can think of is to set result when you're done with the second fragment that essentially tells the first fragment to "resume" via its onActivityResult method.
When you create an instance of Fragment B, call #setTargetFragment() and pass in Fragment A as your target fragment. Then when Fragment B is done and going to return to Fragment A, before it exits, you will set the result of it for Fragment A by calling:
getTargetFragment().onActivityResult(getTargetRequestCode(), RESULT_FRAGMENT_B_FINISHED,null)
///// horizontal scroll padding
Note that RESULT_FRAGMENT_B_FINISHED would be some static integer you define somewhere, like
public static final int RESULT_FRAGMENT_B_FINISHED = 123123;
Now in Fragment A all you need to do is override onActivityResult and check that the request code matches the request code integer from setTargetFragment and the result code also matches RESULT_FRAGMENT_B_FINISHED, if so you can run the code that would have been fired from onResume().
#getTargetFragment()
#onActivityResult()
#getTargetRequestCode()
Instead of passing data between the two fragments I recommend you to use a SharedViewModel.
The idea is that the first fragment observe some data for changes and the second one edit this data.
Example:
Shared ViewModel
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new
MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
First fragment
public class FirstFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model =
ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// Update the UI.
});
}
}
Second fragment
public class SecondFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model =
ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.select(new Item("value 1","value 2");
}
}
You can read about ViewModels, LiveData and Architecture components starting from here: https://developer.android.com/topic/libraries/architecture/viewmodel#java
This answer is assuming that you want to execute some logic based on some data change. If it's not the case, you can explain what kind of logic do you want to execute and I will edit my answer.

Android: Fragment inside Activity. NullPointerException when getting View from Fragment

Users have a crash. I know why but I do not know how to fix it. I am newbie in android dev.
Situation:
Android: Fragment inside Activity. Fragment has an EditText. Activity has a button. User tap the button. Inside Button.OnClick() I want to get text Fragment.EditText.getText();
Some users have a crash here EditText.getText(). i.e. EditText is null.
How I do:
In Activity:
public class MyAcrivity extends AppCompatActivity implements OnFragmentInteractionListener {
final MyFrag myFrag= MyFrag.newInstance();
public void run(final View view) {
//some users have crash here because getEt() return null
final String str = myFrag.getEt().getText().toString();
}
}
In Fragment:
public class MyFrag extends Fragment {
private EditText et;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_myfrag, container, false);
et = (EditText) view.findViewById(R.id.et);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
et = (EditText) view.findViewById(R.id.et);
}
public EditText getEt() {
// return (EditText) getView().findViewById(R.id.et); here getView() could be nul too
return et;
}
}
I know getView() could be null (already googled it).
Init "View" inside onCreateView useless. Crash still happend.
Init "View" inside onViewCreated useless. Crash still happend.
I can NOT reproduce this crash in emulator or my smartphone. I have stable work of my app. BUT some users have the crash and Fabric(crashlytics) is sending messages about it.
People! Help! How to obtain some View from Fragment correctly? I can not to find answers from lifecycle of Fragment. Please explain to me what is wrong.
From your code it seems you have only created instance of fragment and trying to access the view .But to get the view of the fragment you have to add fragment to your activity.
Do this in your activity
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
MyFrag myFrag= MyFrag();
ft.replace("YOUR_FRAGMENT_CONTAINER's id", myFrag);
ft.commit();
Just a hunge, try to do the newInstance() call in the activity lifecycle. Otherwise, there might not be a trustable context to attach fragments. Try to do so in the onCreate().
And something that might be unrelated, but did you properly attach that fragment to the activity? Chances are you are already doing, since some users are correctly accessing it. Anyway, here's the fragment documentation, and a code block to attach it.
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment myFrag = MyFrag.newInstance();
fragmentTransaction.add(R.id.fragment_container, myFrag);
fragmentTransaction.commit();
Use butterknife like this:
class ExampleActivity extends Activity {
#Bind(R.id.user) EditText username;
#Bind(R.id.pass) EditText password;
#BindString(R.string.login_error)
String loginErrorMessage;
#OnClick(R.id.submit) void submit() {
// TODO call server...
}
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}
Add the fragment to the Activity in Activity.onCreate() method.
Get the reference to the Activity during Fragment.onAttach (Context) in the Fragment.
Create a method in Activity like enableButton(), which will enable the button like button.setEnabled (true).
Call this method from Fragment onCreateView after initializing the EditText.
This way you can ensure that EditText is initialized before the button is clicked.
Also remember to make the Activity reference null in Fragment.onDetach() to prevent any leak.
If you use getActivity.findViewById in Fragment.
public class MyFrag extends Fragment {
private EditText et;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_myfrag, container, false);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
et = (EditText) getActivity.findViewById(R.id.et);
}
public EditText getEt() {
// return (EditText) getView().findViewById(R.id.et); here getView() could be nul too
return et;
}
}

Can I navigate from one fragment (fragment1) to another (fragment2) through a button which is on fragment1?

I am having trouble to navigate from one fragment to another through a button in my android application. I have considered several questions about this issue but the solutions provided are not solving my problem. Here is my code and I don't know what I am doing wrong.
public class fragment_profile extends Fragment {
TextView txtFname, txtLname, txtGender, txtAge, txtPhone, txtEmail;
Button btImages, btVideos;
ImageButton btProfilePic;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_profile, container, false);
btProfilePic = (ImageButton)rootView.findViewById(R.id.ProfilePic);
txtFname = (TextView)rootView.findViewById(R.id.tvFName);
txtLname = (TextView)rootView.findViewById(R.id.tvLName);
txtGender = (TextView)rootView.findViewById(R.id.tvGender);
txtAge = (TextView)rootView.findViewById(R.id.tvAge);
txtPhone = (TextView)rootView.findViewById(R.id.tvPhone);
txtEmail = (TextView)rootView.findViewById(R.id.tvEmail);
btImages = (Button)rootView.findViewById(R.id.btnImages);
btVideos = (Button)rootView.findViewById(R.id.btnVideos);
//The code to replace fragment is not good, the clicklistener is working fine as I have tested it with a toast message
btImages.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//An object of the fragment tree is created
fragmentImages ImageGallery = new fragmentImages();
//The fragment is finally added
fragmentTransaction.replace(R.id.fragment_profile, ImageGallery, "Image Gallery").commit();
//Set title of action bar = title of fragment
getActivity().setTitle(getTag());
}
});
btVideos.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//An object of the fragment tree is created
fragmentVideos VideoGallery = new fragmentVideos();
//The fragment is finally added
fragmentTransaction.replace(R.id.fragment_profile, VideoGallery, "Video Gallery").commit();
//Set title of action bar = title of fragment
getActivity().setTitle(getTag());
}
});
return rootView;
}
}
The issue is with the code inside the onClickListener. Can anyone tell me what I am doing wrong? Thank you.
You want to use the supportFragmentManager. Within your onClickListener(s), make your transaction this:
//An object of the fragment tree is created
fragmentImages ImageGallery = new fragmentImages();
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_profile, ImageGallery).commit();
//rest of your setting the activity title below
It is also best practise to make write your classes like FragmentImages and then your variables as imageGallery for example or even fragmentImages so you know what the object is.
I think you have to add your fragment_profile fragment to the backstack so you can recall it afterwards after you have triggered the other fragments. Try the following:
fragmentTransaction.replace(R.id.fragment_profile, ImageGallery, "Image Gallery").addToBackStack(null).commit();
Same with the latter:
fragmentTransaction.replace(R.id.fragment_profile, VideoGallery, "Video Gallery").addToBackStack(null).commit();
I got the information from here: Fragment Replacing Existing Fragment

Adding a fragment in android on button click and adding data to it simultaneously

I am creating a android app in which I have a main activity which has 2 fragments, fragUp and fragDown. fragUp has two edit text fields and a button and fragDown has two text view fields. Initially main activity shows only fragUp and asks user for the input fields, when the user clicks the button then onClick method is triggered and fragDown is created below fragUp and shows the two fields entered by the user.
Summary-
FRAGMENTS- fragUp , fragDown
MAIN ACTIVITY- main activity
Main activity has two linear layouts 1.ly1 for fragUp2.ly2 for fragDown
Note- All fragments are added dynamically in main java file and not declared in main.xml file.
This is main activity code
public class MainActivity extends AppCompatActivity implements fragUp.fragInterface {
FragmentTransaction ft,ft1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ft=getFragmentManager().beginTransaction();
fragUp fu=new fragUp();
ft.add(R.id.ly1,fu); //Fragment fragUp is added dynamically.
ft.commit();
}
public void set(String a,String b){
ft1=getFragmentManager().beginTransaction();
fragDown ob=new fragDown();
ft1.add(R.id.ly2,ob);
ft1.commit();
fragDown fd=(fragDown)getFragmentManager().findFragmentById(R.id.ly2);
fd.seta(a, b);
}
This is my fragUp java code-
public class fragUp extends Fragment {
View v;
public interface fragInterface{
public void set(String a,String b);
}
fragInterface ob;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v=inflater.inflate(R.layout.fragup,container,false);
Button b=(Button)v.findViewById(R.id.button1);
b.setOnClickListener( new OnClickListener(){
public void onClick(View v){
store();
}});
return v;
}
public void onAttach(Activity activity){
super.onAttach(activity);
try{
ob=(fragInterface)activity;
}
catch(ClassCastException e){
throw new ClassCastException();
}
}
public void store(){ with main activity
EditText et1=(EditText)v.findViewById(R.id.editText1);
EditText et2=(EditText)v.findViewById(R.id.editText2);
ob.set(et1.getText().toString(),et2.getText().toString()); //Interface implemented to share data
}
}
This is fragDown java code-
public class fragDown extends Fragment {
View v;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v=inflater.inflate(R.layout.fragdown,container,false);
return v;
}
public void seta(String a,String b){
TextView t1=(TextView)v.findViewById(R.id.textView1);
TextView t2=(TextView)v.findViewById(R.id.textView2);
t1.setText(a);
t2.setText(b);
}
}
When I run the app and press the button my app crashes and logcat says-
08-05 09:37:02.198: E/AndroidRuntime(2866): java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.fragment.fragDown.seta(java.lang.String, java.lang.String)' on a null object reference
08-05 09:37:02.198: E/AndroidRuntime(2866): at com.example.fragment.Second.set(Second.java:30)
08-05 09:37:02.198: E/AndroidRuntime(2866): at com.example.fragment.fragUp.store(fragUp.java:52)
08-05 09:37:02.198: E/AndroidRuntime(2866): at com.example.fragment.fragUp$1.onClick(fragUp.java:25)
If anyone can help me then it would be great. I spent hours debugging it can't find where I went wrong. Please help.
Why don't you pass the values to the fragment as arguments? Check the "Layout" section on this guide: http://developer.android.com/reference/android/app/Fragment.html
Here's an excerpt from that guide that could help you:
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
Then when setting up the fragment:
// Prepare args
Bundle arguments = new Bundle();
arguments.putString(key, value);
// Init fragment and pass args
fragment = new DetailsFragment();
fragment.setArguments(arguments);
// Commit to the fragment manager, thus
// inflating the view
getSupportFragmentManager().beginTransaction()
.add(R.id.your_id, fragment).commit();
You can access the bundled arguments on your fragment's onCreate method.
Addressing your code specifically, you should:
MainActivity.set, pass the args to your fragment:
public void set(String a,String b) {
ft1 = getFragmentManager().beginTransaction();
fragDown ob = new fragDown();
// Add args. It is a good practice
// to declare keys as public static final
// variables, accessing them accordingly. Here
// I'm just putting the string, but you should
// avoid that.
Bundle args = new Bundle();
args.putString("key_a", a);
args.putString("key_b", b);
ob.setArguments(args);
ft1.add(R.id.ly2, ob);
ft1.commit();
}
Add FragDown.onCreate method:
private String a = "";
private String b = "";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.a = getArguments().getString("key_a");
this.b = getArguments().getString("key_b");
}
Call seta on your onCreateView:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragdown, container, false);
seta(this.a, this.b)
return v;
}
this is due to the Fragment's lifecycle: http://developer.android.com/reference/android/app/Fragment.html#Lifecycle
Now, a bit of advice:
If you're serious about Android development, go read the links I posted (from top to bottom) until you understand them. Sorry, there's no way around them.
The "show me the code" kind of questions are usually considered rude and are prone to get downvoted or get hateful comments. StackOverflow is working towards a "be nice" campaign, and that's one of the main reasons I coped with it and followed up.
Asking a question in StackOverflow should really be your last resource, after you've exhausted every other option and have gone through docs, tutorials, source code, GitHub issues and Pull Requests, and so on.
Take this advice with a grain of salt :)

Interface communication from fragment to activity issue

I've recently tried to use an interface for fragment-activity communication. The idea is that when a button is pressed in a fragment, it retrieves data from an EditText in the same fragment, it then sends the string to the MainActivty - this controls all my fragments - which then starts another fragment and delivers the string to this fragment for use later, however, I'm having trouble initially setting up the first interface which sends the data. Unfortunately nothing happens, and I cannot therefore get to the next fragment which should be displayed. Additionally I have tried using getActivity() but it cannot find the associated method within the fragment, leading me to believe that the fragments somehow aren't directly connected to MainActivity (I've only just grasped basics of Java and a little of Android, just learning.)
I've listed the relevant information below, thanks for the assistance!
Fragment
public class CreateWorkoutFragment extends Fragment implements OnClickListener {
View rootViewCreateWorkoutFragment;
EditText editTextWorkoutName;
// Using an ImageView for custom button
ImageView buttonNext;
String valueCreateWorkoutEditText;
OnDataPass dataPasser;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootViewCreateWorkoutFragment = inflater.inflate(R.layout.fragment_create_workout, container, false);
buttonNext = (ImageView) rootViewCreateWorkoutFragment.findViewById(R.id.button_workout_name_next);
editTextWorkoutName = (EditText) rootViewCreateWorkoutFragment.findViewById(R.id.edit_text_workout_name);
buttonNext.setOnClickListener(this);
return rootViewCreateWorkoutFragment;
}
public interface OnDataPass {
public void onDataPass(String data);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
dataPasser = (OnDataPass) activity;
}
public void passData(String data) {
dataPasser.onDataPass(data);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_workout_name_next:
valueCreateWorkoutEditText = editTextWorkoutName.getText().toString();
passData(valueCreateWorkoutEditText);
break;
}
}
}
Main Activity
public class MainActivity extends FragmentActivity implements OnClickListener, CreateWorkoutFragment.OnDataPass {
ImageView buttonCreate;
Fragment newFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.AppThemeBlue);
setContentView(R.layout.activity_main);
buttonCreate = (ImageView) findViewById(R.id.create_foreground);
buttonCreate.setOnClickListener(this);
FragmentManager fragManager = getSupportFragmentManager();
FragmentTransaction tranManager = fragManager.beginTransaction();
CreateWorkoutFragment createWorkoutFrag = new CreateWorkoutFragment();
// fragment_change is just the area in XML where fragments switch
tranManager.add(R.id.fragment_change, createWorkoutFrag);
tranManager.commit();
newFragment = null;
}
#Override
public void onDataPass(String data) {
// CreateFragment is not to be confused with CreateWorkoutFragment
// CreateFragment is the fragment I'm trying to start when any strings
// are obtained from CreateWorkoutFragment
newFragment = new CreateFragment();
}
#Override
public void onClick(View v) {
switch (v.getId()) {
// create_foreground is just an ImageView used as a button
// Additionaly, other buttons are used to create other fragments,
// I've cut them out currently as they are not nessesary which is
// why CreateWorkoutFragment is only button and default currently
case R.id.create_foreground:
newFragment = new CreateWorkoutFragment();
break;
default:
newFragment = new CreateWorkoutFragment();
}
FragmentTransaction tranManager = getSupportFragmentManager().beginTransaction();
tranManager.replace(R.id.fragment_change, newFragment);
tranManager.addToBackStack(null);
tranManager.commit();
}
}
Sorry the code isn't exactly tidy, however, it was the most relevant code cut out from a large class. As I said, I have tried other methods yet cannot get any response from MainActivity either way. Thanks in advance!
Just before I posted: Got the app to write logcat messages to me, it manages to pass the data when the button is clicked - at least I think, and is something to do with the fragment not starting! At MainActivity>onDataPass()>new Fragment = new CreateFragment() Any ideas? As mentioned before, other buttons do exist and manage to change the fragment. However, were cutout to reduce amount of code posted.
getActivity() but it cannot find the associated method within the fragment
This is because getActivity() returns an Activity, not a MainActivity which is your custom subclass. You can easily fix this with a cast. For example, in your fragment, you can do this:
OnDataPass main = (OnDataPass) getActivity();
main.onDataPass(message);
Since such a cast is required, the interface seems to get in the way in my opinion. You can just as easily cast directly to MainActivity:
MainActivity main = (MainActivity) getActivity();
main.onDataPass(message);

Categories

Resources