How to refresh Fragment and pass info based on its position? - java

I`ve got an activity with ViewPager. There is 1 Fragment class - ScheduleFragment and a BroadcastReceiver in it. What I need is to get info and fill up the list in the fragment, based on its position.
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
ScheduleFragment scheduleFragment = new ScheduleFragment();
return scheduleFragment.newInstance(position + 1);
}
#Override
public int getCount() {
// Show 5 total pages.
return 5;
}
#Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getString(R.string.descr_monday);
case 1:
return getString(R.string.descr_tuesday);
case 2:
return getString(R.string.descr_wednesday);
case 3:
return getString(R.string.descr_thursday);
case 4:
return getString(R.string.descr_friday);
}
return null;
}
And here the ScheduleFragment`s methods:
public ScheduleFragment newInstance(Integer day) {
ScheduleFragment fragment = new ScheduleFragment();
Bundle args = new Bundle();
args.putInt("day", day);
fragment.setArguments(args);
return fragment;
}
private class ScheduleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ArrayList<Lesson> result = (ArrayList<Lesson>) intent.getSerializableExtra("schedule");
ArrayList<Lesson> dataToInsert = new ArrayList<>();
Log.i("ASSSSSSSSSSSS", day.toString());
for (Lesson lesson : result) {
if (Objects.equals(lesson.getDay(), day)) {
dataToInsert.add(lesson);
}
}
adapter = new ScheduleListAdapter(context, result);
SwingBottomInAnimationAdapter swingBottomInAnimationAdapter = new SwingBottomInAnimationAdapter(adapter);
swingBottomInAnimationAdapter.setAbsListView(schedule_listView);
schedule_listView.setAdapter(swingBottomInAnimationAdapter);
adapter.notifyDataSetChanged();
}
}
I also have a Spinner in Toolbar with weeks. So also I want to update the fragment when I pick another week.
Please, guys. Help me. I`ve tried some solutions, but none of them helped me!
Hope for you assistance

I'm probably not an expert on this, but I just completed a project full of fragments. The 'dirty' way I passed data between them was accomplished by using a singleton class in my project. This probably isn't the best solution, though.
For instance, my project included a fragment which I updated based on options in a settings activity. The FamilyMap (familyMap) class is my singleton, and I kept a settings model containing maps of needing information within that object. The code shown here is updating that settings model based on user interaction.
public void mapTypeSelection(String selection)
{
Log.d("Map Selection", selection);
switch(selection)
{
case "Normal":
familyMap.getMapFrag().getmMap().setMapType(GoogleMap.MAP_TYPE_NORMAL);
familyMap.getSettings().setMapType(new Pair<String, Integer>("Normal", GoogleMap.MAP_TYPE_NORMAL));
break;
case "Satellite":
familyMap.getMapFrag().getmMap().setMapType(GoogleMap.MAP_TYPE_SATELLITE);
familyMap.getSettings().setMapType(new Pair<String, Integer>("Satellite", GoogleMap.MAP_TYPE_SATELLITE));
break;
case "Hybrid":
familyMap.getMapFrag().getmMap().setMapType(GoogleMap.MAP_TYPE_HYBRID);
familyMap.getSettings().setMapType(new Pair<String, Integer>("Hybrid", GoogleMap.MAP_TYPE_HYBRID));
break;
case "Terrain":
familyMap.getMapFrag().getmMap().setMapType(GoogleMap.MAP_TYPE_TERRAIN);
familyMap.getSettings().setMapType(new Pair<String, Integer>("Terrain", GoogleMap.MAP_TYPE_TERRAIN));
break;
default:
break;
}
}
//private method of your class
private int getIndex(Spinner spinner, String myString)
{
int index = 0;
for (int i=0;i<spinner.getCount();i++){
if (spinner.getItemAtPosition(i).toString().equalsIgnoreCase(myString)){
index = i;
break;
}
}
return index;
}
public Pair<String, Integer> colorLineSelection(String selection)
{
Log.d("Map Selection", selection);
switch(selection)
{
case "Red":
return new Pair<String, Integer>("Red", Color.RED);
case "Blue":
return new Pair<String, Integer>("Blue", Color.BLUE);
case "Green":
return new Pair<String, Integer>("Green", Color.GREEN);
default:
return null;
}
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch(parent.getId()){
case R.id.mapTypeSpinner:
mapTypeSelection((String)parent.getItemAtPosition(position));
break;
case R.id.lifeLineSpinner:
FamilyMap.getInstance().getSettings().setLifeColor(colorLineSelection((String)parent.getItemAtPosition(position)));
familyMap.getMapFrag().drawLines();
break;
case R.id.spouseLineSpinner:
FamilyMap.getInstance().getSettings().setSpouseColor(colorLineSelection((String) parent.getItemAtPosition(position)));
familyMap.getMapFrag().drawLines();
break;
case R.id.familyLineSpinner:
FamilyMap.getInstance().getSettings().setFamilyColor(colorLineSelection((String) parent.getItemAtPosition(position)));
familyMap.getMapFrag().drawLines();
break;
default:
break;
}
}
The other thing I did was I retained the instance of my fragment - it was the main portion of my app, so it made sense for my situation. That allowed me to be able to update the original fragment when an option was selected. I also set the fragment to update when a certain result was reached by using startActivityForResult().
I think a better (cleaner, more acceptable) option for sending the data to your fragment would be object serialization, but at least in my case, that proved to be more work than I could afford at the time.
Hopefully this at least helps to point you in the right direction!

So, after trying, trying and a lot of trying I figured it out!
In newInstance method, where I create new instance of Fragment I`ve added a bundle with day, according to fragments position
public ScheduleFragment newInstance(Integer day) {
ScheduleFragment fragment = new ScheduleFragment();
Bundle args = new Bundle();
args.putInt("day", day);
fragment.setArguments(args);
return fragment;
}
Then, in fragment's onCreateView I get this argument with getArguments().getInt("day"); and put it into private Integer dayglob; field, which means, that its different for every fragment.
Now, when I have 'day' variable in my fragment I can put info into list according to provided day:
private class ScheduleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ArrayList<Lesson> result = (ArrayList<Lesson>) intent.getSerializableExtra("schedule");
ArrayList<Lesson> dataToInsert = new ArrayList<>();
for (Lesson lesson : result) {
if (Objects.equals(lesson.getDay(), dayglob)) {
dataToInsert.add(lesson);
}
}
adapter = new ScheduleListAdapter(context, dataToInsert);
SwingBottomInAnimationAdapter swingBottomInAnimationAdapter = new SwingBottomInAnimationAdapter(adapter);
swingBottomInAnimationAdapter.setAbsListView(schedule_listView);
schedule_listView.setAdapter(swingBottomInAnimationAdapter);
try {
getActivity().unregisterReceiver(mScheduleBroadcastReceiver);
} catch (IllegalArgumentException e) {
Log.i("Unregister", e.toString());
}
}
}
Every fragment got its own "onReceive" and wor on data from service for specific fragment.
Also, about the week spinner and updating the lists according to its value: I've made a static field public static Spinner week_spinner;, initialized it it onCreate method of my Activity and then, in fragment's "onCreateView" I made a request to my database like this:
requestQueue.add(connectionManager.getSchedule(this, savedUser.getGroup(), MainActivity.week_spinner.getSelectedItemPosition() + 1));
The only matter thing here is getting value by accessing spinner via static reference.
And, also, I've set Listener which says to fragments something like
Hey, guys! You are not up to date! Update yourself!
week_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mViewPager.getAdapter().notifyDataSetChanged();
}
});
And a little trick which make it possible is to change getItemPositionin FragmentPagerAdapter class (SectionsPagerAdapter in my case)
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
It`s kinda tricky, I guess, but its the only way i can figure it out
I hope, this will help someone!

Related

How to select specific data in a list in android?

Hello how do I select a specific data in a list?
I have this list
for example I clicked on Kaiser (which is not in first nor last in the list)
I set this on the fragment
name.setText(obj.getName());
but the one that shows up is Mogul (which is the last on the list)
so how do I select the name specifically? any ideas?
edit:
here's the fragment and adapter
public class LivestockDetailFragment extends Fragment {
private Livestock livestock;
private View view;
private ImageButton pencil;
private EditText name;
private ImageButton save;
public static LivestockDetailFragment newInstance(Livestock livestock) {
LivestockDetailFragment fragment = new LivestockDetailFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(DVBoerConstants.DV_LIVESTOCK_EXTRA, livestock);
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Inflate the layout for this fragment_packages
view = inflater.inflate(R.layout.fragment_livestock_detail, container, false);
livestock = (Livestock) getArguments().getSerializable(DVBoerConstants.DV_LIVESTOCK_EXTRA);
//initLivestockDetailsView(view);
initializeEdit();
ViewPager pager = (ViewPager) view.findViewById(R.id.viewPager);
pager.setAdapter(new MyPagerAdapter(getActivity().getSupportFragmentManager()));
name.setText(livestock.getName());
return view;
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: return LivestockDetailPageFragment.newInstance(livestock);
case 1: return LivestockMedicalHistoryPageFragment.newInstance(livestock);
case 2: return LivestockGalleryPageFragment.newInstance(livestock);
default: return LivestockDetailPageFragment.newInstance(livestock);
}
}
#Override
public int getCount() {
return 3;
}
private String tabtitles[] = new String[]{"Details", "Medical History", "Gallery"};
Context context;
#Override
public CharSequence getPageTitle(int position) {
return tabtitles[position];
}
}
/*RecyclerView recyclerView = (RecyclerView)view.findViewById(R.id.livestock_detail_recycler_view);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(),1);
recyclerView.setLayoutManager(layoutManager);
LivestockDetailAdapter adapter = new LivestockDetailAdapter(getActivity(), livestock);
recyclerView.setAdapter(adapter);*/
private void initializeEdit(){
pencil = (ImageButton) view.findViewById(R.id.editName);
name = (EditText) view.findViewById(R.id.nameTextView);
save = (ImageButton) view.findViewById(R.id.saveName);
save.setOnClickListener(buttonList);
pencil.setOnClickListener(buttonList);
}
private View.OnClickListener buttonList = new View.OnClickListener(){
public void onClick(View view) {
switch (view.getId()){
case R.id.editName:
save.setVisibility(View.VISIBLE);
name.setFocusableInTouchMode(true);
KeyboardUtility.openKeyboard(getActivity());
pencil.setVisibility(View.INVISIBLE);
break;
case R.id.saveName:
pencil.setVisibility(View.VISIBLE);
name.setFocusableInTouchMode(false);
name.setFocusable(false);
save.setVisibility(View.INVISIBLE);
KeyboardCloseUtility.hideKeyboard(getActivity());
break;
}
}
};
}
for every list, there's an index and you can get your specific item from index list. In your case you can also get the position from that list.
Based on your comment i guess you are not creating new object everytime .. if you are looping through array put Object generation code inside of loop. if thats not the case i cant help without looking at code
Looking at you problem, there can be two problems that I can see.:
you are not initializing your obj every time before adding it to the List.
Example: List<Object> lst= new ArrayList<Object>();
Object obj = new Object();
obj.setParam();
list.add();
obj.setparam();
list.add();
In this example before every setParam() you must do obj = new Object();
Otherwise every time you will be setting same Param to all the obj and
that param will be none other than the last one. So every list.add();
will add same object to the list.
you added obj outside of a loop in which you are setting the parameters
(all the names) so it will add only the last object to the list.
example:Object obj =null;
while(some condition is true){
obj = new object();
obj.setParam();
}
lst.add(obj);
In this example you might initialize obj every time but you are adding
only last obj to the list. Here you will have to put lst.add(obj);
inside the loop.
I hope your case is among these only.

How to generate random fragments in Android?

I have this project, a quiz app to be specific. I have 10 questions to be asked and I want it to be randomly appear in my app. As of now, I put those questions on Fragments using Tabbed Activity. I have no idea how to randomize it.
Should I use Activity rather than fragments?
This is the code where I call those fragments:
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: return new FirstFragment();
case 1: return new SecondFragment();
case 2: return new ThirdFragment();
}
return null;
}
}
Any recommendations/suggestions? I really need this app to be done. Thanks!
Try to create an array for those Fragments:
Class[] classes=new Class[numberOfDirrefentFragmenTypes];
Class c1 = FirstFragment.class;
Class c2 = SecondFragment.class;
classes[0]=c1;
classes[1]=c2;
Then you can pick a random class and instantiate it:
Random random=new Random();
Class randomClass=classes[random.nextInt(classes.size())];
So you can create a random fragment at any time:
Constructor<?> ctor = randomClass.getConstructor();
Object object = ctor.newInstance(new Object[] { ctorArgument });
It might not be the optimal solution, but it should work.
I hope it helps (I did not compile the code).
Sorry for the late answer, I hope to help others who have the same needs
Fragments have a special (static) method called instantiate(Context, String) that you can use like this:
CustomFragment cf = Fragment.instantiate(getApplicationContext(), CustomFragment.class.getName())
So if you need to generate a random fragment from a list of fragments, you can do it like this:
ArrayList<String> fragList = new ArrayList<>();
fragList.add(FirstCustomFragment.class.getName());
fragList.add(SecondCustomFragment.class.getName());
fragList.add(ThirdCustomFragment.class.getName());
int r = new Random().nextInt(fragList.size());
Fragment cf = Fragment.instantiate(getApplicationContext(), fragList.get(r));
You can also pass a series of params with the bundle argument (Fragment.instantiate(Context, String, Bundle)) . Its an option args that you can use in the fragment's onCreate method like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
customData = getArguments().getString("data");
}
}
if you want to see how it works under the hood take a look here, you'll see that is not heavier for the device and its a good way to not use the reflection by yourself

Android ViewPager: Destroy Fragment on Slide?

I am basically playing an animation on each fragment of the view pager. The animation plays when the user slides to the specific fragment. However, certain fragments don't play the animation the second time I visit them. That's because the view pager keeps them in memory.
I need to destroy each fragment after the user slides to another fragment. This way, the animations play every time I revisit those fragments.
Main View:
pager = (ViewPager) findViewById(R.id.guidepager);
mAdapter = new NewUserGuideAdapter(getSupportFragmentManager());
pager.setAdapter(mAdapter);
pager.setOffscreenPageLimit(0); //Tried this too. Didnt work
Fragment:
public class NewUserPage_Two extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_new_user_page__two, container, false);
//Play animation, etc
Animation animation_1 = AnimationUtils.loadAnimation(NewUserPage_Two.this.getActivity(), R.anim.abc_slide_in_bottom);
person1.setAnimation(animation_1);
return rootView;
}
Adapter:
public class NewUserGuideAdapter extends FragmentPagerAdapter {
public NewUserGuideAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new NewUserPage_One();
case 1:
return new NewUserPage_Two();
case 2:
return new NewUserPage_Three();
case 3:
return new NewUserPage_One();
case 4:
return new NewUserPage_One();
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 5;
}
}
How can I amend my code guys?
ViewPager provide a method mViewPager.setOffscreenPageLimit(0);
Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.
Try this inside the fragment:
((BaseAdapter) *YourContainer*.getAdapter()).notifyDataSetChanged();
You can refer to: Refresh Current Fragment (ListView Data) remaining in the same activity
public void setOffscreenPageLimit(int limit) {
if (limit < DEFAULT_OFFSCREEN_PAGES) {
Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
DEFAULT_OFFSCREEN_PAGES);
limit = DEFAULT_OFFSCREEN_PAGES;
}
if (limit != mOffscreenPageLimit) {
mOffscreenPageLimit = limit;
populate();
}
}
That's the method body,DEFAULT_OFFSCREEN_PAGES=1by the way.I think google add this limits cause you need at least the 2 views between current item while you are sliding.
You can try using addOnPageChangeListener() and start your animation on onPageSelected.

How do I assign one task for multiple Spinners?

I am a new learner in Android Programming and now I am studying how to use spinner. With Button by using onClickListener, to assign one task for multiple buttons, I can use this form below
switch (v.getId()) {
case (R.id.button1) :
do something;
break;
...
I wonder whether I can apply the same thing for spinner or not? Or because my way of applying is not proper. Here I have my code, at first I thought the transportation for data does not run properly, then I try to put a Toast to check and obviously there is no String assigned. I also tried with using directly spinner1, spinner2,... instead of parent but It didn't seem more optimistic.
private class Shoes implements OnItemSelectedListener {
private boolean isFirst = false;
#Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
if (isFirst == false) {
isFirst = true;
}
else {
switch (view.getId()) {
case (R.id.spinner1) :
choosen_item[0] = parent.getItemAtPosition(position).toString();
Toast.makeText(getBaseContext(), choosen_item[0], Toast.LENGTH_SHORT).show();
bundle.putString("item1", choosen_item[0]);
break;
case (R.id.spinner2) :
choosen_item[1] = parent.getItemAtPosition(position).toString();
bundle.putString("item2", choosen_item[1]);
break;
case (R.id.spinner3) :
choosen_item[2] = parent.getItemAtPosition(position).toString();
bundle.putString("item3", choosen_item[2]);
break;
}
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
}

Android : FragmentPagerAdapter don't saved the state of Fragment?

I have a problem with the FragmentPagerAdapter .
I can not save the state of the Fragment and then there is the view that within the Fragment . Whenever I use the swipe left and right , the Fragment is recreated by overriding the method getItem ( int position ) in the static class that extends the FragmentPagerAdapter .
public static class GraphicsCollectionPagerAdapter extends FragmentPagerAdapter {
final int NUM_ITEMS = 3; // number of tabs
public GraphicsCollectionPagerAdapter(FragmentManager fm) {
super(fm);
fragmentList = new AnalyzeFragmentPageListWithDate();
fragment1 = new AnalyzeFragmentPage1();
fragment2 = new AnalyzeFragmentPage2();
}
#Override
public Fragment getItem(int position) {
//Log.i(TAG, "getItem() -> New fragment at position " + position);
switch (position) {
case 0:
return fragmentList;
case 1:
return fragment1;
case 2:
return fragment2;
}
return null;
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Fragm1";
case 1:
return "Fragm2";
case 2:
return "Fragm3";
}
return "OBJECT " + (position + 1);
}
}
Within the method OnCreateView of each instance of the Fragment there are several steps to the SQLite database and this causes a saturation of the Database Connection Pool.
The warning found whenever change dynamically fragment is: "W / SQLiteConnectionPool (1111 ) : A SQLiteConnection object for database ' / data / data / com.myapp / databases / mydb ' was leaked ! Please fix your application to end transactions in progress properly and to close the database When it is no longer needed . "
I already tried to use the FragmentStatePagerAdapter without success.
Could you kindly tell me how to proceed ? I do not want the Fragment is regenerated each time, causing problems to the database. Have you got an example for save Fragment/View sate?
I have not found any suggestion for now .
thank you very much
use setOffscreenPageLimit property for your ViewPager object.
ViewPager pager = (ViewPager) findViewById(R.id.viewPagerId);
pager.setOffscreenPageLimit(2);
First of all create a new instance of Fragment every time the getItem() is called
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new FragmentList();
case 1:
return new AnalyzeFragmentPage1();
case 2:
return new AnalyzeFragmentPage2();
}
return null;
}
Note that FragmentPagerAdapter does not work exactly like normal Adapter meaning it does NOT use an empty vessel Fragment and then refills it with different data.
Instead it creates a new Fragment whenever it is needed. So you should pass data (if any) when the Fragment is created. Please study the example in the Android docs.
In a real time projects instead of passing current position to a new Fragment you could pass the actual ID of the entry that a Fragment should refer to.

Categories

Resources