how to load a Master/Detail flow from a recycle view - java

The issue i have is that if i leave the adapter as an inner class of the MainActivity.I have no issues, it loads properly. If I move it out to a separate java file, then instead of populating the detail view, it launches the details activity.
Constructor
public MoviesAdapter(MovieListActivity activity, List<DummyContent.DummyItem> items, boolean twoPane) {
mActivity = activity;
mValues = items;
mTwoPane = twoPane;
}
This is how I load the details view. its in an onClick() event.
if (mTwoPane) {
Bundle arguments = new Bundle();
arguments.putString(MovieDetailFragment.ARG_ITEM_ID, holder.mItem.id);
MovieDetailFragment fragment = new MovieDetailFragment();
fragment.setArguments(arguments);
mActivity.getSupportFragmentManager().beginTransaction()
.replace(R.id.movie_detail_container, fragment)
.commit();
} else {
Context context = v.getContext();
Intent intent = new Intent(context, MovieDetailActivity.class);
intent.putExtra(MovieDetailFragment.ARG_ITEM_ID, holder.mItem.id);
context.startActivity(intent);
}
Is this common functionality or am I missing something?

Related

How to refresh the fragment onResume

I am a newbie in Android development. I am facing an issue. I need some help from you guys.
Firstly, I am working on an application that is similar to BookMyShow.
I have an activity that contains a fragment. The activity contains a list of timeslots in a recycler view.
When I click on one of the timeslots, I go to new activity where I book the show with the specific details like username, id, timeslot_selected, etc and once he submits the "SUBMIT" button in the activity, it should come back to the same fragment that he was in, earlier, and show his details on the fragment. Initial there is nobody in the recycler view, now the user should see himself in that recycler view at the selected timeSlot as an icon.
I have the next button as well. When the user clicks on it, I am replacing the fragment with the following date. If the user clicks on one of the slots, he would be redirected to the same booking activity and once he submits, he should come back to the previous fragment with the same date that he was on earlier and with an updated icon of himself.
Now, I am unable to show that updated icon in the previous fragment once he clicks submit on the booking activity. Can you please suggest what should I do?
I tried detaching and attaching the fragment but to no avail. Please help me with a solution. Thanks in Advance!
SampleActivity.java:
public class SampleActivity extends AppCompatActivity {
TextView text;
Person person;
String id, name, date;
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
Intent intent = getIntent();
id = intent.getStringExtra("id");
name= intent.getStringExtra("name");
date= intent.getStringExtra("date");
person= (Person) getIntent().getSerializableExtra("person");
text= findViewById(R.id.name);
text.setText(name);
Bundle bundle = new Bundle();
bundle.putString("id", id);
bundle.putString("name", name);
bundle.putString("date", date);
bundle.putSerializable("Person", person);
FragmentA newFragment = new FragmentA();
newFragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction().replace(R.id.mainFrameLayout, newFragment, "main_fragment").commit();
}
FragmentA.java:
public class FragmentA extends Fragment implements View.OnClickListener {
RecyclerView recyclerView;
public FragmentA() {
}
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_new, container, false);
recyclerView = view.findViewById(R.id.slots);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
requestQueue = VolleySingleton.getmInstance(getActivity()).getRequestQueue();
newList = new ArrayList<>();
next = view.findViewById(R.id.nextButton);
timeView = view.findViewById(R.id.timeOn);
dateText= view.findViewById(R.id.date);
Bundle bundle = getArguments();
assert bundle != null;
id= bundle.getString("id");
name = bundle.getString("name");
date = bundle.getString("date");
person = (Person) bundle.getSerializable("Person");
next.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
if (v.getId()== R.id.nextButton) {
replaceFragment();
}
}
private void replaceFragment() {
Bundle bundle = new Bundle();
bundle.putString("id", id);
bundle.putString("name", name);
bundle.putString("date", date);
bundle.putSerializable("Person", person);
bundle.putSerializable("hashmap", (Serializable) hashmap);
fm = requireActivity().getSupportFragmentManager();
ft = fm.beginTransaction();
f = new FragmentFirst();
f.setArguments(bundle);
ft.replace(R.id.fragmentLayout, f, "main_fragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void refreshData() {
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
Fragment currentFragment = fragmentManager.findFragmentByTag("main_fragment");
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if(currentFragment != null) {
fragmentTransaction.detach(currentFragment);
fragmentTransaction.attach(currentFragment);
fragmentTransaction.commit();
}
}
}
As I see you are trying to go to a new instance of FragmentA in your booking activity. If you want to send data to an activity, process the data and return the result, in your case you could do it by starting new activity for result by startForActivityResult and also set the result before finish the activity with setResult method in your booking activity. In this case you can use the result via onActivityResult method. But I suggest you to use fragment for the booking process as well instead of activity.

fragmentTransaction.replace().commit() calls onCreate of parent Activity

I have a parent activity that stores several fragments, in the activity's onCreate I launch the first fragment
FatherFragment fatherFragment = new FatherFragment ();
RegisterActivity.this.getSupportFragmentManager (). BeginTransaction ().add (R.id.fragmentContainer, parentFragment, "RegisterParentFragment").commit ();
In the application the fragment is displayed correctly, but this fragment has a button that calls another fragment to replace it
MapsFragment mapsFragment = new MapsFragment();
Bundle bundle = new Bundle();
bundle.putString("idPersona", idPersona);
mapsFragment.setArguments (bundle);
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, mapsFragment, "mapaFragment")
.commit();
The problem resides in that, when making the fragment change (which if it is done) the onCreate method of the parent activity is launched again and shows me the first fragment over of the fragment that has just changed.
I have to assume that it is the view that is running again, but I would like to know if someone could help me find the solution to this problem.
I add that it is a series of steps between fragments and every time I switch, the same problem reappears.
Greetings and thanks for your time. Sorry for bad english.
Adding onClick method.
btnSgtPadre.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
guardarPersona(objPersona);
MapsFragment mapsFragment = new MapsFragment();
Bundle bundle = new Bundle();
bundle.putString("idPersona", idPersona);
mapsFragment.setArguments(bundle);
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, mapsFragment,"mapaFragment")
.commit();
}
});
Try this code :
in your Activity create method, which will add this fragment :
public void switchToSecondFragment(Object idPersona){
MapsFragment mapsFragment = new MapsFragment();
Bundle bundle = new Bundle();
bundle.putString("idPersona", idPersona);
mapsFragment.setArguments(bundle);
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, mapsFragment,"mapaFragment")
.commit();
}
And call it like this :
btnSgtPadre.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
guardarPersona(objPersona);
((<YourActivityName>) getActivity()).switchToSecondFragment(idPersona);
}
});
Most likely reason could be : App is restarting due to crash. Sometimes we don't get logs as well if app restarts.. try this and let me know.
Crash reason :
replace() method finds the ID inside your current fragment's layout, as you are passing "R.id.fragmentContainer", and your current fragment doesn't contain this "id", so you might me getting crash that this doesn't contain this id called "R.id.fragmentContainer". So you will have to add this fragment by writing method inside Activity itself.
If you want to confirm , add TryCatch :
try{
MapsFragment mapsFragment = new MapsFragment();
Bundle bundle = new Bundle();
bundle.putString("idPersona", idPersona);
mapsFragment.setArguments(bundle);
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, mapsFragment,"mapaFragment")
.commit();
}catch(Exception e){
e.printStackTrace();
}

Intent to activity is not working while using fragment for card view on click

I am using a fragment to hold 4 card views, which should start a new activity on click. It can display the toast I generate which shows that the click function is working but it is unable to activate the intent.
I have tried using several names for the activity and also
Intent intent = new Intent (getActivity(), activity name.class)
code to start activity
package com.example.eb.ui.home;
import ...
public class HomeFragment extends Fragment implements View.OnClickListener{
private HomeViewModel homeViewModel;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
View root = inflater.inflate(R.layout.fragment_home, container, false);
final CardView java = root.findViewById(R.id.javacardId);
final CardView html = root.findViewById(R.id.htmlcardId);
final CardView c_prog = root.findViewById(R.id.C_cardId);
final CardView cpp = root.findViewById(R.id.cppcardId);
//set on click listener
java.setOnClickListener(this);
html.setOnClickListener(this);
cpp.setOnClickListener(this);
c_prog.setOnClickListener(this);
return root;
}
#Override
public void onClick(View v) {
Intent i;
switch(v.getId()){
case R.id.javacardId :
i = new Intent(this,html.class);
startActivity(i);
break;
case R.id.htmlcardId :
i = new Intent(this,html_prog.class);
startActivity(i);
break;
case R.id.cppcardId :
i = new Intent(this,cpp_prog.class);
startActivity(i);
break;
case R.id.C_cardId :
i = new Intent(this,c_prog.class);
startActivity(i);
break;
default: break;
}
}
}
---
I expect the card view in that fragment to open up new activity
Try changing the "this" keyword to getContext()
"i = new Intent(this,html.class);"
should be
i = new Intent(getContext,html.class);
or initialize and set the clicklistener in onViewCreated() lifecycle method of Fragment.
You have to use getActivity() instead of 'this' in a fragment for context like below.
#Override
public void onClick(View v) {
Intent i;
switch(v.getId()){
case R.id.javacardId :
i = new Intent(getActivity(),html.class);
startActivity(i);
break;
default: break;
}
The first parameter required by Intent is Context
As mentioned in the Android documentation (Here):
packageContext Context: A Context of the application package implementing this class.
Hence, you need to pass getContext() or getActivity() (since Activity extends Context) as follows:
i = new Intent(getActivity(), html.class);
startActivity(i);
I tried building and launching an app using your code (after making the change above) and it worked fine.

Refresh Activity from ViewPager Fragment

I have a BaseActivity which has a ViewPager with some Fragments in it. In one of these Fragments I have 2 buttons which change the language of the app.
The thing I want to accomplish is that, on the click of the button, refresh BaseActivity to the selected language but still have the ViewPager set on Settings(name of the fragment). Right now it's reloading the entire app and starts on the fragment which I set it to start on.
Code for changing the language and refreshing the Activity
public void setLocale(String lang) {
Locale myLocale = new Locale(lang);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
SharedPreferences ensharedPreferences = getActivity().getSharedPreferences("selectedLanguage", MODE_PRIVATE);
SharedPreferences.Editor eneditor = ensharedPreferences.edit();
eneditor.putString("language", lang);
eneditor.apply();
SharedPreferences pref = getActivity().getSharedPreferences(lang,MODE_PRIVATE);
Intent refresh = new Intent(getContext(), BaseActivity.class);
getActivity().overridePendingTransition(0,0);
startActivity(refresh);
getActivity().overridePendingTransition(0,0);
}
I have only found methods on doing this the reverse way, to reload a fragment from the activity, but I want to do it the other way.
You can pass the ViewPager's selected position to the Activity using getCurrentItem() and pass it to the new Intent as an extra and reselect the item number when relaunching the Activity through getIntent() and move to the previously selected Fragment by using setCurrentItem(int position)
// Restarting the Activity passing the position of the currently selected Fragment
Intent intent = new Intent(getContext(), BaseActivity.class);
intent.putExtra(EXTRA_POSITION, viewPager.getCurrentItem());
startActivity(intent);
#Override
protected void onCreate(Bundle savedInstanceState) {
...
Intent intent = getIntent();
if(intent != null) {
int position = intent.getIntExtra(EXTRA_POSITION, 0);
viewPager.setCurrentItem(position);
}
}

Fragment Arguments are null

I am trying to send data from one fragment to another, I am using bundle for that. But, whenever, I try to get any information from that bundle in the second fragment, I get an error message saying that I am trying to get a null object. I have set the arguments of the second fragment before I create it, and I have also add information to the bundle before sending it. I could not find out what is the problem. Here is the interface code in the main fragment which should open the details fragment,
public interface ListClickHandler {
public void onlistElementClicked ( Bundle args); //we'll have to override it in the parent activity.
}//end interface.
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (ListClickHandler) activity;
}//end try
catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement ListClickHandler interface");
}//end catch
}
Also, I create the bundle in two places, once in the main fragment, which contains a list, if any item is clicked the bundle is created, info is added to the bundle, and that bundle is passed to the method inside the interface as the following,
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_todo_list, container, false);
mSimpleCursorAdapter=new SimpleCursorAdapter(getActivity(),R.layout.notes_row,null, from, to,0);
getLoaderManager().initLoader(LOADER_ID, null, this); //once this is done onCreateLoader will be called.
ListView listView = (ListView) rootView.findViewById(R.id.notes_list); //findViewById must be called using the rootView because we are inside a fragment.
listView.setAdapter(mSimpleCursorAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Cursor cursor = mSimpleCursorAdapter.getCursor();
if (cursor != null && cursor.moveToPosition(position)) {
String category= cursor.getString(1);
String summary= cursor.getString(2);
String description=cursor.getString(3);
long id= cursor.getLong(cursor.getColumnIndex(NotesContract.NotesTable._ID));
int locationId= cursor.getInt(cursor.getColumnIndex(NotesContract.NotesTable.COLUMN_LOCATION));
String [] retrievedData= {category, summary, description};
if (getActivity().findViewById (R.id.fragment_container)!=null){
//two pane layout:
Bundle args = new Bundle();
args.putStringArray("data",retrievedData);
/*args.putInt("update", 1);*/
args.putLong("id", id);
args.putInt("locationId", locationId);
mCallback.onlistElementClicked(args );/*this is available in the parent activity*/
}
else {
// one pane layout:
Intent intent = new Intent(getActivity(), NotesDetails.class);
intent.putExtra(Intent.EXTRA_TEXT, retrievedData);
/*intent.putExtra("update", 1); */ //to indicate that the query should be update not insert.
intent.putExtra("id", id);
intent.putExtra("locationId", locationId); //whether it is 0 or 1
startActivity(intent);
}
}//end outer cursor if.
}
});
return rootView;
}
The second place where I create and call the bundle is in the main activity (which contains the main fragment) when some items of the options menu are selected as the following,
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {//open the settings activity to enable the user to change the settings.
//open settings activity via intent here.
startActivity(new Intent (this, Settings.class));
return true;
}
if (id==R.id.text_note){ //open the details activity where the user can enter their notes and save it.
if (twoPane) {
args.putBoolean("location", false);
mCallBack.onlistElementClicked(args);
}
else {
Intent intent = new Intent(this, NotesDetails.class);
startActivity(intent);
return true; //this line is necessary
}
}//end if
if (id==R.id.location_note)
{
if (twoPane) {
args.putBoolean("location", true);
mCallBack.onlistElementClicked(args);
}
else {
//prepare intent here:
Intent intent = new Intent(this, NotesDetails.class);
intent.putExtra("location", true);
startActivity(intent);
}
}
return super.onOptionsItemSelected(item);
}
This is how I override onlistElementClicked in the main activity,
#Override
public void onlistElementClicked(Bundle args) {
DetailsFragment detailsFragment = new DetailsFragment();
detailsFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, detailsFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}//end interface method.
And this is how I get the information inside the arguments of the details fragment (The fragment that should be opened from the main fragment).
Bundle args=this.getArguments();
After that I use args to get any information in the bundle, but I am getting the error which I mentioned previously.
Can any one please help me? I've checked several solutions on the web and nothing worked for me.
Thank you.
You should assign the value of Bundle like this:
public void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
youtBandGlobalMember = getArguments();
}
Bundle args=this.getArguments();
actually, I didn't call it in any method, it is called in the body of fragment class, and its value is assigned to a global variable. Is that wrong?
It's too early. Member variables are initialized when the object is constructed and that is before you can call setArguments() on the fragment object.
Postpone the getArguments() call to one of the on...() lifecycle callbacks in the fragment.

Categories