"Already executed" error (Retrofit2 and Android) - android

First of all, I have 2 fragments and they show different json values(2 links). If I change fragment(.replace()), that fragment get values with retrofit and show it. It works well but other fragment is deleted with values. After change fragment, it downloads again so I change structure. I want to take 2 json objects once so I get json objects in mainactivity and fragments get these with methods. They work well in first opening but if i open a fragment second time, it gives this error. How can I solve it?
java.lang.IllegalStateException: Already executed.
at retrofit2.OkHttpCall.enqueue(OkHttpCall.java:84)
Code is very long, i will show main structure.
MainActivity.java
public class MainActivity extends AppCompatActivity
{
private Call<Restaurant[]> restaurantCall;
private Call<Dining[]> diningCall;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Restaurant Json value
RestaurantInterface restaurantInterface = RetroClient.getClient().create(RestaurantInterface.class);
restaurantCall = restaurantInterface.getJsonValues();
//Dininghall Json value
DiningInterface diningInterface = RetroClient.getClient().create(DiningInterface.class);
diningCall = diningInterface.getJsonValues();
}
public Call<Restaurant[]> RestaurantJson()
{
return this.restaurantCall;
}
public Call<Dining[]> DiningJson()
{
return this.diningCall;
}
}
RestaurantFragment.java (Other fragment has same structure)
public class RestFragment extends Fragment
{
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_rest, container, false);
Call<Restaurant[]> call = ((MainActivity) getActivity()).RestaurantJson();
call.enqueue(new Callback<Restaurant[]>()
{
.
.

Summing up, in order to avoid the "Already executed" exception, clone the call:
public Call<Restaurant[]> RestaurantJson()
{
return this.restaurantCall.clone();
}
public Call<Dining[]> DiningJson()
{
return this.diningCall.clone();
}
If you want to execute the call in the activity and not in the fragment as you are actually doing, then you need to call enqueue(new Callbak(... in your activity.
So you need something like this:
public class RestFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_rest, container, false);
((MainActivity) getActivity()).RestaurantJson(this);
}
public void onResponse(Response<T> response) {
//your fragment code on response
}
...
}
public class MainActivity extends AppCompatActivity {
public void RestaurantJson(final RestFragment fragment)
{
RestaurantInterface restaurantInterface = RetroClient.getClient().create(RestaurantInterface.class);
restaurantCall = restaurantInterface.getJsonValues();
restaurantCall.enqueue(new Callback<Restaurant[]>() {
#Override
public void onResponse(Call<T> call, Response<T> response) {
...
fragment.onResponse(response);
}
}
...
}
The same for your DiningFragment and your dining call...

Related

Remove Fragment 2 from BackStack and pass data to Fragment 1

Inside my MainActivity (Demo) I add FragmentDemo 1 to backstack. Inside this fragmentDemo 1, pressing a button opens a new FragmentDemo 2, where I have an edit text. On pressing the button on this second fragment, I want to remove it from backstack and send the data from editText back to FragmentDemo 1.
I am using a listener on Fragment 2, and implementing the methods, but when I run the code I have the following message. java.lang.ClassCastException: com.example.teacherapp.activities.Demo#5630fb7must implement Listener
Demo (Main Activity)
public class Demo extends AppCompatActivity implements FragmentInterface {
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
if (savedInstanceState == null) {
addFragment(new FragmentDemo1());
}
}
#Override
public void onMyFragment(Fragment fragment) {
addFragment(fragment);
}
private void addFragment(Fragment fragment){
getSupportFragmentManager()
.beginTransaction()
.add(R.id.demo_container,fragment)
.addToBackStack(null)
.commit();
}
}
FragmentInterface
public interface FragmentInterface {
void onMyFragment(Fragment fragment);
}
FragmentDemo 1
public class FragmentDemo1 extends Fragment implements FragmentInterface, FragmentDemo2.Fragment2CallBack {
Button btnFrag1;
TextView tvFrag1;
public FragmentDemo1() {
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_fragment_demo1, container, false);
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
btnFrag1 = view.findViewById(R.id.fragment1_button);
tvFrag1 = view.findViewById(R.id.fragment1_tv);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getFragmentManager();
btnFrag1.setText("Frag 1: " + String.valueOf(fm.getBackStackEntryCount()));
btnFrag1.setOnClickListener(v -> {
replaceFragment(new FragmentDemo2());
});
}
#Override
public void onMyFragment(Fragment fragment) {
replaceFragment(fragment);
}
private void replaceFragment(Fragment fragment) {
getFragmentManager().
beginTransaction().
replace(R.id.demo_container, fragment).
addToBackStack(null).
commit();
}
#Override
public void onDataSent(String myData) {
Toast.makeText(getContext(), "RECEIVED. "+myData, Toast.LENGTH_LONG).show();
}
}
FragmentDemo 2
public class FragmentDemo2 extends Fragment {
private Button btnFrag2;
private EditText etFrag2;
private Fragment2CallBack listener;
public FragmentDemo2(){}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_fragment_demo2,container,false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
btnFrag2=view.findViewById(R.id.fragment2_button);
etFrag2=view.findViewById(R.id.fragment2_et);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm=getFragmentManager();
btnFrag2.setOnClickListener(v->{
String info=etFrag2.getText().toString();
listener.onDataSent(info);
fm.popBackStack();
});
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try{
listener=(Fragment2CallBack) context;
}catch (ClassCastException e){
throw new ClassCastException(context.toString()+"must implement Listener");
}
}
public interface Fragment2CallBack{
void onDataSent(String s);
}
}
The result expected is to have fragment 2 removed from backstack and open fragment 1, with received data from fragment 2.
Fragment Back Stack Example.
Refer this url https://www.dev2qa.com/android-fragment-back-stack-example/
The Problem in your existing code
The Context you try to use in FragmentDemo2 is of Demo activity (not of FragmentDemo1) so you can not type cast it to listener when you are trying to attach
If you want to achieve the same goal with existing code, follow below step
1) Expose API from FragmentDemo2 that will allow to set Listener of type Fragment2Callback
public void setListener(Fragment2Callback li) {listener = li;}
2) From FragmentDemo1, when you create FragmentDemo2 instance, you also need to set itself as listener to FragmentDemo2
FragmentDemo2 frg = new FragemtDemo2()
frg.setListener(this);
replaceFragment(frg);
3) Then replaceFragment() from FragmentDemo1
4) remove casting of listener from onAttach() inside FragmentDemo2
So now you have FragmentDemo1 as listener inside FragmentDemo2, which you can use to communicate to fragmentDemo1
I hope this information help you

How to attach a fragment onto a context (programmatically)?

Currently I'm coding an android project using Android Studio 3.1.2 and SDK 19.
When I refactored almost my whole code and replaced a lot of getContext() calls with requireContext() and getActivity() with requireActivity() i came across the problem, that the app crashes already at the launcher activity. I know that there are several posts related to the same problem of getting IllegalStateException: Fragment myFragment not attached to a contextbut they're all very project-specific so it doesn't actually show me the step i missed to do. So i hereby show you my example of code and pray for a merciful programmer that enlightens me, what I have to do, to solve this problem just in the suiting way.
This is my SplashActivity (the launcher activity):
public class SplashActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
Fragment fragmentToDisplay = null;
if (!(getIntent().getBooleanExtra("isLaunch", true))) {
fragmentToDisplay = new LoginFragment();
} else {
if (savedInstanceState == null) {
fragmentToDisplay = new SplashFragment();
}
}
if (fragmentToDisplay.isAdded()) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragmentToDisplay).commit();
}
}
}
This is the SplashFragment which gets loaded initially:
public class SplashFragment extends RequestingFragment {
private Handler delayHandler = new Handler();
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_splash, container, false);
requestQueue = Volley.newRequestQueue(this.requireContext());
requestParams.add(SessionHandler.getAppInstanceID(this.getContext()));
startRequest(RequestOperation.SESSION_CHECK);
onSuccess(new JSONObject(), "");
return fragmentView;
}
#Override
public void onDestroy() {
super.onDestroy();
delayHandler.removeCallbacksAndMessages(null);
}
#Override
public void onSuccess(final JSONObject json, String parsingKey) {
delayHandler.postDelayed(new Runnable() {
#Override
public void run() {
//parsing stuff
}
}, 2000);
}
#Override
public void onError() {
showErrorDialog();
}
private void showErrorDialog() {
//show a horrifying dialog
}
}
I would be very thankful, if someone could explain to me, what in particular is causing the exception and how do I do it correctly. Thanks in advance.

Why does pressing back from detail activity after landscape-to-portrait-switch show an empty screen?

Below is the MainActivity class that I'm using. The code checks to see if the phone is in landscape or portrait. If it's in portrait, it will show the main fragment in the main activity only (the main fragment is a static fragment in the main_activity.xml file). Then if a "Recipe" is clicked it will open a detail activity with its own fragment. If the phone is in landscape mode, it will show the main fragment and the detail fragment side by side. Everything works perfectly fine however when I follow the procedure below I get a white screen instead of the main activity:
Procedure:
Switch to landscape
Switch back to portrait
Choose an item and wait for the detail activity to open
Press back
Here instead of the main activity window I get a white screen
If I don't switch to landscape and just start with the portrait mode everything is fine. It seems like switching to landscape does something that causes the problem and I can't figure out what. Any tip on what's going on or where to look would be much appreciated.
public class MainActivity extends AppCompatActivity implements RecipesFragment.OnRecipeClickListener {
private String RECIPE_PARCEL_KEY;
private boolean mTwoPane;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RECIPE_PARCEL_KEY = getString(R.string.ParcelKey_RecipeParcel);
if (findViewById(R.id.linearLayoutTwoPane) != null) {
mTwoPane = true;
if (savedInstanceState == null) {
RecipeFragment recipeFragment = new RecipeFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.recipeFrameForTwoPane, recipeFragment)
.commit();
}
} else {
mTwoPane = false;
}
}
#Override
public void OnRecipeClick(Recipe recipe) {
if (mTwoPane) {
RecipeFragment recipeFragment = new RecipeFragment();
recipeFragment.setRecipe(recipe);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.recipeFrameForTwoPane, recipeFragment)
.commit();
} else {
Class destinationClass = DetailActivity.class;
Intent intentToStartDetailActivity = new Intent(this, destinationClass);
intentToStartDetailActivity.putExtra(RECIPE_PARCEL_KEY, recipe);
startActivity(intentToStartDetailActivity);
}
}
}
EDIT:
Adding RecipeFragment's code below:
public class RecipeFragment extends Fragment {
private Recipe mRecipe;
#BindView(R.id.tv_recipeName) TextView recipeNameTextView;
public RecipeFragment(){
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.recipe_fragment,container,false);
ButterKnife.bind(this,view);
if(mRecipe!=null) {
recipeNameTextView.setText(mRecipe.getName());
}else{
recipeNameTextView.setText(getString(R.string.messageSelectARecipe));
}
return view;
}
public void setRecipe(Recipe recipe){
mRecipe = recipe;
}
}
EDIT:
I followed #mt0s's advice and created different background colors for the fragments and activities and finally narrowed down the problem to a line in my recyclerview adapter code. My adapter code is below. Inside loadInBackground() on line URL url = new URL(getString(R.string.URL_RecipeJSON)); I get a Fragment RecipesFragment{96e9b6a} not attached to Activity exception. I don't understand why I'm getting this exception and what the best way to resolve this is. Have I placed the right code in the right fragment methods (ie OnCreate vs OnActivityCreated vs OnCreateView vs etc)?
public class RecipesFragment extends Fragment
implements RecipeAdapter.RecipeAdapterOnClickHandler,
LoaderManager.LoaderCallbacks<ArrayList<Recipe>> {
#BindView(R.id.rv_recipes) RecyclerView mRecyclerView;
private RecipeAdapter mRecipeAdapter;
private static final int LOADER_ID = 1000;
private static final String TAG = "RecipesFragment";
private OnRecipeClickListener mOnRecipeClickListener;
public RecipesFragment(){
}
public interface OnRecipeClickListener {
void OnRecipeClick(Recipe recipe);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.recipes_fragment, container, false);
ButterKnife.bind(this, view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mRecipeAdapter = new RecipeAdapter(this);
mRecyclerView.setAdapter(mRecipeAdapter);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void OnClick(Recipe recipe) {
mOnRecipeClickListener.OnRecipeClick(recipe);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
mOnRecipeClickListener = (OnRecipeClickListener) context;
} catch (ClassCastException e){
Log.e(TAG, "onAttach: Host activity class must implement OnRecipeClickListener.");
}
}
#Override
public Loader<ArrayList<Recipe>> onCreateLoader(int i, Bundle bundle) {
return new AsyncTaskLoader<ArrayList<Recipe>>(getActivity()) {
#Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad();
}
#Override
public ArrayList<Recipe> loadInBackground() {
String response;
ArrayList<Recipe> recipes = null;
try {
URL url = new URL(getString(R.string.URL_RecipeJSON)); //***I get an exception here***
response = NetworkUtils.getResponseFromHttpUrl(url, getActivity());
recipes = RecipeJsonUtils.getRecipeFromJson(getActivity(), response);
} catch (Exception e) {
Log.e(TAG, "loadInBackground: " + e.getMessage());
}
return recipes;
}
};
}
#Override
public void onLoadFinished(Loader<ArrayList<Recipe>> loader, ArrayList<Recipe> recipes) {
mRecipeAdapter.setRecipeData(recipes);
}
#Override
public void onLoaderReset(Loader<ArrayList<Recipe>> loader) {
}
}
I finally figured out the problem and the solution. The problem is that onStartLoading() in the AsyncTaskLoader anonymous class in RecipesFragment class gets called every time the fragment is resumed whether the enclosing Loader is called or not. This causes the problem. I need to have control over when onStartLoading() is being called and I only want it to be called if and only if the enclosing Loader is being initialized or restarted. As such, I destroyed the loader in onPause() of the fragment and restarted it in onResume(). Hence, I added the following code to the RecipesFragment class:
#Override
public void onPause() {
super.onPause();
getLoaderManager().destroyLoader(LOADER_ID);
}
#Override
public void onResume() {
super.onResume();
getLoaderManager().restartLoader(LOADER_ID, null, this);
}
I also removed initLoader() from onCreate(). This way, every time the fragment is resumed (or created) onStartLoading() will be called. I tried this and it solves my problem.
When you switch from the landscape to portrait or the opposite the Android OS destroy your activity and recreate it again. this what probably trigger your problem

send intent from main activity to two fragment

I have 2 Fragment and I have to send some id to the Fragment. I use this:
public void onItemLongClick(View view, int position) {
FragmentManager fm = getSupportFragmentManager();
actionOption actionOption = new actionOption();
actionOption.show(fm,"fragment_edit_name");
ToDoModule movie = dbList.get(position);
int y= movie.getId();
Bundle args = new Bundle();
args.putInt("exampleInt", y);
actionOption.setArguments(args);
EditOption editOption = new EditOption();
ToDoModule bl = dbList.get(position);
int z= movie.getId();
Bundle zs = new Bundle();
zs.putInt("int", y);
editOption.setArguments(zs);
}
First Fragment is working, but the second is not sent. Cannot send value to EditOption?
How to solve it?
Its very unusual that, you're trying to pass some data to two Fragment at the same time. It would be great if you could write the situation you have there in brief in your question.
Anyway, #PrerakSola came up with a solution for saving the data you want to pass in a SharedPreference and I do think it should work in your case.
You're trying to pass a movie id to actionOption as well as to editOption. You might try to store the id first in a SharedPreference like this.
From your Activity
public void onItemLongClick(View view, int position) {
// ... Your code
// Save the movie id
SharedPreferences pref = getSharedPreferences("MY_APPLICATION", MODE_PRIVATE);
pref.edit().putInt("MOVIE_ID", movie.getId()).commit();
// Do not pass any bundle to the Fragment. Just transact the Fragment here
}
Now from your Fragment's onCreateView fetch the value from preference.
SharedPreferences pref = getActivity().getSharedPreferences("MY_APPLICATION", MODE_PRIVATE);
String movieID = pref.getInt("MOVIE_ID", 0);
Another way you might try to have a public static int variable which might contain the movie id and you can access it from anywhere from your code.
Hope that helps!
Something like this , you can do it
public interface SetData {
public void data(String id);
}
From your activity class or on item click listner
SetData setData;
setData.setDrawerEnabled("anydata");
Infragment , YourFragment extends Fragment implements SetData
hi yesterday i have done same thing and how it work, i'll give you idea.
It already answered but just i want to share my experiance.This way is perfect.
First of all create two interfaces in your activity,
public interface TaskListener1 {
public void onResultAvailable(String result);
}
public interface TaskListener2 {
public void onResultAvailable(String result);
}
Now come to your activity then call like this where you want to send data to fragment.I'm just giving you example.You can make it as you want.
class TestAsyncTask extends AsyncTask<Void, String, Void> {
String response_result;
public TaskListener1 taskListener1 = null;
public TaskListener2 taskListener2 = null;
public TestAsyncTask(TaskListener1 taskListener1, TaskListener2 taskListener2) {
this.taskListener1 = taskListener1;
this.taskListener2 = taskListener2;
}
#Override
protected Void doInBackground(Void... unused) {
response_result = "Test data what you want to send";
return null;
}
#Override
protected void onPostExecute(Void unused) {
taskListener1.onResultAvailable(response_result);
taskListener2.onResultAvailable(response_result);
}
}
Call like this,
new TestAsyncTask(new Fragment1), new Fragment2)).execute();
And how to get data in fragment,
First fragment,
public class Fragment1 extends Fragment implements YourActivity.TaskListener1 {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment1, container, false);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onResultAvailable(String result) {
Logs.d("TAG", "Fragment result1:" + result);
}
}
Second fragment,
public class Fragment2 extends Fragment implements YourActivity.TaskListener2 {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment2, container, false);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onResultAvailable(String result) {
Logs.d("TAG", "Fragment result2:" + result);
}
}
Thanks hope this will help somebody.

Passing data From Activity to Fragment using interface [closed]

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.

Categories

Resources