I have a FloatingActionButton and RecyclerView in one of my fragments. Fab opens a new activity where user can save a task into sqlite and all the saved tasks from sqlite are shown in the recycler view. Now what I want is that when the user saves a new task and click on the back button of the activity from toolbar, the recycler view should be updated automatically. Right now, I have to switch to another fragment and then come back to the previous one to see the newly created task. I researched about it and found that interfaces are the best option for this but I am having problems passing the context of the fragment to the activity.
Here is the activity for new task creation:
public class AddTaskActivity extends AppCompatActivity {
DataUpdateListener dataUpdateListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_task);
dataUpdateListener = (CalendarFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_calendar);
ActionBar supportActionBar = getSupportActionBar();
if (supportActionBar != null) {
supportActionBar.setTitle(R.string.add_task);
supportActionBar.setDisplayHomeAsUpEnabled(true);
}
}
private void saveTask(String task_type, String task) {
// this method is used to save the task in sqlite
byte[] imageByteArray;
if (addPictureBtn.getVisibility() == View.GONE) {
imageByteArray = Utils.getImageByteArray(selectedImage);
if (Utils.saveTask(task_type, imageByteArray, task, 0) != -1) {
AlertDialog alertDialog = Utils.showProgressDialog(this, R.layout.success_popup);
Button okBtn = (Button) alertDialog.findViewById(R.id.okBtn);
okBtn.setOnClickListener(v -> {
alertDialog.dismiss();
finish();
});
}
dataUpdateListener.onDataUpdate();
}
}
public interface DataUpdateListener {
void onDataUpdate();
}
}
This is my fragment which is implementing the interface:
public class CalendarFragment extends Fragment implements AddTaskActivity.DataUpdateListener {
CalendarView calendarView;
TextView noTaskFoundTV;
RecyclerView recyclerView;
FloatingActionButton addTaskBtn;
private FragmentCalendarBinding binding;
CalendarTasksAdapter calendarTasksAdapter;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentCalendarBinding.inflate(inflater, container, false);
return binding.getRoot();
}
#Override
public void onViewCreated(#NonNull #NotNull View view, #Nullable #org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
calendarView = view.findViewById(R.id.calendar);
Calendar calendar = Calendar.getInstance();
long milliTime = calendar.getTimeInMillis();
calendarView.setDate(milliTime, true, true);
recyclerView = view.findViewById(R.id.rv);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(false);
noTaskFoundTV = view.findViewById(R.id.noTaskFound);
addTaskBtn = view.findViewById(R.id.fab);
addTaskBtn.setOnClickListener(v -> {
Intent intent = new Intent(getContext(), AddTaskActivity.class);
startActivity(intent);
});
fetchTodayPendingTasks();
}
public void fetchTodayPendingTasks() {
JSONObject todayTasksFromDB = Utils.getTodayPendingTasksFromDB();
if (todayTasksFromDB != null) {
noTaskFoundTV.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
try {
JSONArray tasks = todayTasksFromDB.getJSONArray("tasks");
calendarTasksAdapter = new CalendarTasksAdapter(getActivity(), tasks);
recyclerView.setAdapter(calendarTasksAdapter);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
#Override
public void onDataUpdate() {
//this toast never triggers/shown when the task is created from the activity
Toast.makeText(getContext(), "Triggered", Toast.LENGTH_SHORT).show();
}
}
For this kind of usage, the best practice is to use Room database which is basically wrapping sqlite with abstraction layer. And then you could use LiveData.
Perfect example with source code can be found here.
Please try to open activity through startActivityResult like
In fragment
Intent intent = new Intent(getContext(), AddTaskActivity.class); startActivityForResult(intent,requestcode);
In addtaskactivity
Intent inten =new Intent()
setResult with OK
and then again check onActivityResult in fragment with request code, you can refresh you view here
Or another way to check and refresh in onStart() method of fragment with one static Boolean variable updated from task activity and again false this Boolean from onstart when you finish refreshing. But first of all I would prefer first way.
You should use onResumed method of fragment lifecycle.
you should override onResumed Method on CalendarFragment
This method is called after returning to the main page.
call fetchTodayPendingTasks(); in onResumed method.
It is better to make changes in the fetchTodayPendingTasks. like this:
public class CalendarFragment extends Fragment implements AddTaskActivity.DataUpdateListener {
CalendarView calendarView;
TextView noTaskFoundTV;
RecyclerView recyclerView;
FloatingActionButton addTaskBtn;
private FragmentCalendarBinding binding;
CalendarTasksAdapter calendarTasksAdapter;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentCalendarBinding.inflate(inflater, container, false);
return binding.getRoot();
}
#Override
public void onViewCreated(#NonNull #NotNull View view, #Nullable #org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
calendarView = view.findViewById(R.id.calendar);
Calendar calendar = Calendar.getInstance();
long milliTime = calendar.getTimeInMillis();
calendarView.setDate(milliTime, true, true);
recyclerView = view.findViewById(R.id.rv);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(false);
noTaskFoundTV = view.findViewById(R.id.noTaskFound);
addTaskBtn = view.findViewById(R.id.fab);
addTaskBtn.setOnClickListener(v -> {
Intent intent = new Intent(getContext(), AddTaskActivity.class);
startActivity(intent);
});
calendarTasksAdapter = new CalendarTasksAdapter(getActivity());
recyclerView.setAdapter(calendarTasksAdapter);
fetchTodayPendingTasks();
}
public void fetchTodayPendingTasks() {
JSONObject todayTasksFromDB = Utils.getTodayPendingTasksFromDB();
if (todayTasksFromDB != null) {
noTaskFoundTV.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
try {
JSONArray tasks = todayTasksFromDB.getJSONArray("tasks");
adapter.setData(tasks)
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
#Override
public void onDataUpdate() {
//this toast never triggers/shown when the task is created from the activity
Toast.makeText(getContext(), "Triggered", Toast.LENGTH_SHORT).show();
}
}
and you should define a setData method in your adapter. Do not forget to call notifyDataSetChanged().
public void setData(JSONArray array){
// set to your data list
notifyDataSetChanged();
}
Related
In fragment'A' when a certain condition is established, it should go to 'ChatActivity'.
Intent intent = new Intent(getContext(), ChatActivity.class);
intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("uid", matchedUid);
startActivity(intent);
The problem is when other fragment or Activity is showing on the top, the condition is established so startActivity is not executed.. occur an error
'java.lang.String android.content.Context.getPackageName()' on a null object reference
below is entire code
public class MatchFragment extends Fragment implements MatchMVP.View {
private static final String TAG = "MatchFragment";
private MatchPresenter matchPresenter;
private ToggleButton randomMatchBtn;
private ProgressBar progressBar, progressCircle;
private TextView searchingText;
private AdView adView;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v;
setupMVP();
if(matchPresenter.checkOnlineStatus(getContext())) {
v = inflater.inflate(R.layout.fragment_match, container, false);
setupView(v);
matchPresenter.isSearching();
initAd(v);
} else {
v = inflater.inflate(R.layout.fragment_offline, container, false);
}
return v;
}
private void setupMVP() {
matchPresenter = new MatchPresenter(this);
}
private void setupView(View v) {
progressBar = v.findViewById(R.id.progressbar);
progressCircle = v.findViewById(R.id.progressbar_circle);
searchingText = v.findViewById(R.id.searching_text);
progressBar.setVisibility(View.INVISIBLE);
progressCircle.setVisibility(View.INVISIBLE);
searchingText.setVisibility(View.INVISIBLE);
randomMatchBtn = v.findViewById(R.id.random_match_btn);
randomMatchBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(matchPresenter.checkOnlineStatus(getContext())) {
if(randomMatchBtn.isChecked()) {
matchPresenter.searchRandomUser();
progressBar.setVisibility(View.VISIBLE);
} else {
matchPresenter.stopMatch();
progressBar.setVisibility(View.VISIBLE);
}
} else {
showSnackBar("error");
}
}
});
}
private void initAd(View v) {
MobileAds.initialize(getActivity(), "ca-app-pub-6263138384822549~5566878684");
adView = v.findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder().build();
adView.loadAd(adRequest);
}
#Override
public void createChatRoom(String matchedUid) {
Intent intent = new Intent(getContext(), ChatActivity.class);
intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("uid", matchedUid);
startActivity(intent);
Vibrator vibrator;
if(getContext() != null) {
vibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(700);
}
}
#Override
public void showSnackBar(String msg) {
Snackbar snackbar = Snackbar.make(getActivity().findViewById(android.R.id.content), msg, 2500);
View snackBarLayout = snackbar.getView();
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
// Layout must match parent layout type
lp.setMargins(0, 300, 0, 0);
// Margins relative to the parent view.
snackBarLayout.setLayoutParams(lp);
snackbar.show();
}
#Override
public void randomMatchBtnOff() {
randomMatchBtn.setChecked(false);
}
#Override
public void randomMatchBtnDisable() {
randomMatchBtn.setEnabled(false);
}
#Override
public void randomMatchBtnEnable() {
randomMatchBtn.setEnabled(true);
progressBar.setVisibility(View.INVISIBLE);
}
#Override
public void showProgressCircle() {
progressCircle.setVisibility(View.VISIBLE);
searchingText.setVisibility(View.VISIBLE);
}
#Override
public void hideProgressCircle() {
progressCircle.setVisibility(View.INVISIBLE);
searchingText.setVisibility(View.INVISIBLE);
}
#Override
public void goAuthActivity() {
Intent intent = new Intent(getContext(), AuthActivity.class);
intent.putExtra("isSanctioned", true);
startActivity(intent);
assert getActivity() != null;
getActivity().finish();
}
#Override
public void onResume() {
super.onResume();
matchPresenter.checkIsSan();
}
#Override
public void onPause() {
super.onPause();
if(isThreadRunning) {
timeCheckThread.interrupt();
}
}
}
Cause of error is 'Fragment is not attached to its Activity'. Yeah I know. I'm making a randomChatting app with firebase. In this MatchFragment, I'm searching other users. When other users start searching, matched with me then let me know by go to 'ChatActivity'.
But if I'm in other fragment of activity, searching is activating, it can't go ChatActivity. 'Fragment is not attached to its Activity'.
Because I'm in other activity not in this MatchFragment. MatchFragment detached to its Activity.
How go to ChatActivity even if I'm in other activity.
You can either try using requireActivity() instead of getActivity() but since you only need a Context object and not necessarily an Activity object, I suggest you replace getActivity() with requireContext().
If that doesn't work out then you can try following this answer: https://stackoverflow.com/a/30498143
PS: I know this should be shared as a comment but my reputation is currently only 41 and I can't post a comment so writing this as an answer.
I am writing an android app using android studio. So far I have created a tabbed activity to be my main activity, and another activity that would be opened on a click of a button in one of the tabs in my main tabbed activity. The problem is that I have tried to accomplish this in a few ways but it seems like the code in my public View onCreateView just doesn't get executed at all. This is the code I'm trying to run:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
Button mainSignInButton = (Button) view.findViewById(R.id.mainSignInButton);
mainSignInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getActivity() ,LoginActivity.class);
startActivity(i);
}
});
return view;
}
I have also tried to add a simple toast message to this block of code to see if it gets executed but I didnt see the toast pop up as well...
First of all, delegate to Activity the startActivity(). Try something like follow on your fragment:
public class FragmentMain extends Fragment {
private OnInteractionListener mListener;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
Button mainSignInButton = (Button) view.findViewById(R.id.mainSignInButton);
mainSignInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListener.onClickSignInButton()
}
});
return view;
}
public interface OnInteractionListener {
void onClickSignInButton();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null
}
}
On your Activity try like follow:
public class MyActivity extends AppCompatActivity implements FragmentMain.OnInteractionListener {
...
#Override
public void onClickSignInButton() {
Intent i = new Intent(this, LoginActivity.class);
startActivity(i);
}
}
I have multiple instances of the same CustomView inside one fragment.
I implemented savedInstance for this CustomView but the problem is since there are multiple instances of this CustomView, savedInstance of the last one, overrides them all.
for example, if there are 3 instances of this CustomView which has a recyclerview inside, If I scroll the last one, it applies to them all. because i'm using key value pairs and the key is the same for all of them. (I can change the key to differ for each one but I think there is a better way)
Here is the code for savedInstance saving and restoring inside my CustomView:
#Nullable
#Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(SavedInstanceKey.SUPERSTATE.name(), super.onSaveInstanceState());
bundle.putParcelable(SavedInstanceKey.RECYCLERVIEW.name(), recyclerView.getLayoutManager().onSaveInstanceState()); // ... save stuff
return bundle;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) // implicit null check
{
Bundle bundle = (Bundle) state;
this.recyclerView.getLayoutManager().onRestoreInstanceState(bundle.getParcelable(SavedInstanceKey.RECYCLERVIEW.name())); // ... load stuff
state = bundle.getParcelable(SavedInstanceKey.SUPERSTATE.name());
}
super.onRestoreInstanceState(state);
}
and here is my fragment's OnCreateView:
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_artist, container, false);
final GridListView gv_new = view.findViewById(R.id.gridlist_new_songs);
final GridListView gv_best = view.findViewById(R.id.gridlist_best);
final GridListView gv_singles = view.findViewById(R.id.gridlist_singles);
final GridListView gv_feats = view.findViewById(R.id.gridlist_feats);
final RecyclerView rc_albums = view.findViewById(R.id.rcview_album);
if(!alreadyInitialized) {
alreadyInitialized = true;
apiService = new ApiService(getContext());
try {
artistID = getArguments().getString(KeyIntent.ARTIST.name());
} catch (Exception e) {
Log.e(TAG, "onCreateView: Artist Fragment doesnt have args.\t", e);
}
apiService.getArtist(artistID, new ApiService.OnArtistReceived() {
#Override
public void onSuccess(Artist artist) {
ArtistFragment.this.artist=artist;
setArtistToViews(artist, view);
}
#Override
public void onFail() {
Toast.makeText(getContext(), "Error on receiving artist.", Toast.LENGTH_LONG).show();
}
});
apiService.getNewSongs(artistID, new ApiService.OnSongsReceived() {
#Override
public void onSuccess(List<Song> songs) {
ArtistFragment.this.newSongs=songs;
List<GridListable> gridListables = new ArrayList<>();
gridListables.addAll(songs);
gv_new.load(gridListables, 1);
}
#Override
public void onFail(ApiService.ApiResponse response) {
Toast.makeText(getContext(), "Error on receiving artist.", Toast.LENGTH_LONG).show();
}
});
apiService.getBestSongs(artistID, new ApiService.OnSongsReceived() {
#Override
public void onSuccess(List<Song> songs) {
ArtistFragment.this.bestSongs=songs;
List<GridListable> gridListables = new ArrayList<>();
gridListables.addAll(songs);
gv_best.load(gridListables, 1);
}
#Override
public void onFail(ApiService.ApiResponse response) {
Toast.makeText(getContext(), "Error on receiving artist.", Toast.LENGTH_LONG).show();
}
});
apiService.getSingleSongs(artistID, new ApiService.OnSongsReceived() {
#Override
public void onSuccess(List<Song> songs) {
ArtistFragment.this.singleSongs=songs;
List<GridListable> gridListables = new ArrayList<>();
gridListables.addAll(songs);
gv_singles.load(gridListables, 1);
}
#Override
public void onFail(ApiService.ApiResponse response) {
}
});
apiService.getFeats(artistID, new ApiService.OnSongsReceived() {
#Override
public void onSuccess(List<Song> songs) {
ArtistFragment.this.feats=songs;
List<GridListable> gridListables = new ArrayList<>();
gridListables.addAll(songs);
gv_feats.load(gridListables, 1);
}
#Override
public void onFail(ApiService.ApiResponse response) {
}
});
apiService.getAlbums(artistID, new ApiService.OnAlbumsReceived() {
#Override
public void onSuccess(List<Album> albums) {
ArtistFragment.this.albums=albums;
List<Projective> projectives = new ArrayList<>();
projectives.addAll(albums);
rc_albums.setAdapter(new AlbumAdapter(getContext(), projectives));
rc_albums.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, true));
}
#Override
public void onFail(ApiService.ApiResponse response) {
Toast.makeText(getContext(), "Loading albums failed.", Toast.LENGTH_SHORT).show();
}
});
}else {
Log.i(TAG, "onCreateView: Fragment already initialized, restoring from existing artist");
setArtistToViews(artist,view);
gv_new.load(new ArrayList<>(newSongs),1);
gv_best.load(new ArrayList<>(bestSongs),1);
gv_singles.load(new ArrayList<>(singleSongs),1);
gv_feats.load(new ArrayList<>(feats),1);
rc_albums.setAdapter(new AlbumAdapter(getContext(), new ArrayList<>(albums)));
rc_albums.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, true));
}
return view;
}
I think the problem is the Keys that you use for your Bundles. All your instances of the custom view use the same SavedInstanceKey.SUPERSTATE.name().
You could try to have the Fragment pass a different key to each of the custom views (BEST, NEW...). This way, each of your GridView has its own unique key to use in the saveInstanceState and restoreInstanceState methods.
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
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.