I'm making an app that displays events in a list. Each event has a custom layout (with BaseAdapter). If i'm using my phone in either only portrait or only landscape its ok, but if i'm on the list and rotate my phone to change the orientation the BaseAdapter produces a NullPointerException. Here is the code:
public class ShowListAdapter extends BaseAdapter {
private Activity a;
private List<Map<String, String>> monthList;
private static LayoutInflater inflater;
public ShowListAdapter(Activity act, List<Map<String, String>> msc) {
a = act;
monthList = msc;
inflater = (LayoutInflater) a.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return monthList.size();
}
public Object getItem(int i) {
return i;
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
View v = view;
if (view == null) {
v = inflater.inflate(R.layout.list_item, null);
}
/* Some random code that formats the view goes here */
return v;
}
}
The error is thrown at getCount(), because it (i assume) can not find the list variable monthList.
This class is used in a ListFragment class
public class ListForMonth extends ListFragment {
List<Map<String, String>> eventListLoc;
public ListForMonth() {}
public ListForMonth(int i) {
eventListLoc = ShowHolder.eventList.get(i);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setListAdapter(new ShowListAdapter(this.getActivity(), eventListLoc));
return super.onCreateView(inflater, container, savedInstanceState);
}
}
The ShowHolder class has a single static variable that is "generated" in the splash screen of the application.
The main Activity has multiple tabs, each it's own ListFragment. The only important part of the code in there is this, i guess:
public Fragment getItem(int position) {
return new ListForMonth(position);
}
Why does the code throw this error? And how can i fix it? Thanks in advance!
You are right the problem is in this lines..
public Fragment getItem(int position) {
return new ListForMonth(position);
}
when ever the orientation changes Android calls the fragmnet with the default constructor..at that time your List> eventListLoc data is null..thats why it is giving NPE..
To avoid this..Change your fragment code like thiss..
public class ListForMonth extends ListFragment {
List<Map<String, String>> eventListLoc;
private int i;
public ListForMonth() {
}
public ListForMonth(int i) {
this.i = i;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
i = savedInstanceState.getInt("POSITION");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
eventListLoc = ShowHolder.eventList.get(i);
setListAdapter(new ShowListAdapter(this.getActivity(), eventListLoc));
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("POSITION", i);
}
}
Watch out because when you switch from landscape to portrait or from portrait to landscape, the activity restarts. So override the onResume() method and handle the screen orientation.
Related
Below is my Code.
Using ViewPager I have made 2 XML file for two Pages and their Class file.
Now I need if I click on First Screen of ViewPager, a new activity should launch.
I got 2 pages, so If I Click First Screen, A.class intent Called. If I click on Second Screen, B.class intent should be Called.
Codes:-
MainActvity:
public class MainActivity extends ActionBarActivity {
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.pager);
/** set the adapter for ViewPager */
mViewPager.setAdapter(new SamplePagerAdapter(
getSupportFragmentManager()));
}
/** Defining a FragmentPagerAdapter class for controlling the fragments to
be shown when user swipes on the screen. */
public class SamplePagerAdapter extends FragmentPagerAdapter {
public SamplePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
/** Show a Fragment based on the position of the current screen */
if (position == 0) {
return new SampleFragment();
} else
return new SampleFragmentTwo();
}
#Override
public int getCount() {
// Show 2 total pages.
return 2;
}
}
}
SampleFragment.java
public class SampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_one, null);
return rootView;
}
}
SampleFragmentTwo.java
public class SampleFragmentTwo extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_two, container,
false);
return rootView;
}
}
CustomSwipeAdapter:
public class CustomSwipeAdapter extends PagerAdapter {
#Override
public int getCount() {
return 0;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return false;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
return super.instantiateItem(container, position);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
}
As mentioned in one of the comments, In your fragment classes A and B put onClick listener on views and launch intent from there like below:
public class SampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_one, null);
rootView.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
// do something when the button is clicked
Intent activityA = new Intent(getActivity(),ActivityA.class);
startActivity(activityA);
}
return rootView;
}
}
similarlly goes for your second fragment.
I want to implement GridView that each cell contains an object of class. for this I implemented fragment class:
public class DayUC extends Fragment {
/*
some variables
*/
// use to create instance of class with initial parameters
public static DayUC newInstance(//initial parameters) {
DayUC dayUC = new DayUC();
/*
set parameters
*/
return dayUC;
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_layout, container, false);
initialization() //initial variables and view elemans (textView, ...)
return rootView;
}
}
and also I created GridViewAdapter:
public class GridViewAdapter extends BaseAdapter {
private ArrayList<DayUC> gridList; //list of grid DayUC objects
Context context;
public GridViewAdapter(Context context, ArrayList<DayUC> gridList) {
this.gridList = gridList;
this.context = context;
}
#Override
public int getCount() {
return gridList.size();
}
#Override
public DayUC getItem(int position) {
return gridList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return gridList.get(position).getView();
}
}
but when I create GridView it throws NullPointerException! I found that in gridView elements (DayUC) onCreateView() never called. so gridList.get(position).getView() returns null!!
could anyone help me to solve this problem? how could I force onCreateView to be called??
Edit: MainActivity onCreate method added:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DayUC[] dayUC = new DayUC[42];
monthGridView = (GridView) findViewById(R.id.month_view);
for (int i = 0; i < 42; i++) {
dayUC[i] = DayUC.newInstance(//inpute arguments)
dayUCList.add(dayUC[i]);
monthCal.add(Calendar.DATE, 1);
}
gridViewAdapter = new MonthGridViewAdapter(getActivity(), dayUCList);
monthGridView.setAdapter(gridViewAdapter);
gridViewAdapter.notifyDataSetChanged();
}
I have android application.
Application minSDK:15
I have NavigationDrawer.
When click on first Navigation drawer menu item, my new fragment appears called MainFragment.
Everything is good, like in android tutorial.
Now in this fragment I need to implement simple ViewPager.
ViewPager will page Fragments.
Here is code:
public class MainFragent extends Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_fragment_layout, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ArrayList<Books> books;
BooksPageAdapter contentPageAdapter = new BooksPageAdapter(getFragmentManager(), books);
ViewPager pager = (ViewPager) getActivity().findViewById(R.id.viewPager);
pager.setAdapter(contentPageAdapter);
}
private class BooksPageAdapter extends FragmentStatePagerAdapter {
private ArrayList<Books> books;
public BooksPageAdapter(FragmentManager fm, private ArrayList<Books> books) {
super(fm);
this.books = books;
}
#Override
public Fragment getItem(int pos) {
return BooksFragment.newInstance(books);
}
#Override
public int getCount() {
return 5;
}
} }
And BooksFragment:
public class BooksFragment extends Fragment {
private ArrayList<Books> books;
static ContentFragment newInstance(final ArrayList<Books> books) {
BooksFragment booksFragment = new BooksFragment();
Bundle args = new Bundle();
args.putSerializable("books", books);
contentFragment.setArguments(args);
return booksFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
books = (ArrayList<Books>) getArguments().getSerializable(“books”);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_books, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
updateUI(books);
}
public void updateUI(ArrayList<Books> books) {
ListView listView = (ListView)getActivity().findViewById(R.id.list_view);
listView.setAdapter(new MyArrayAdapter(getActivity(), books));
}
private class MyArrayAdapter extends ArrayAdapter<Books> {
public MyArrayAdapter(final Context context, final List<Books> list) {
super(context, R.layout.books_menu_item, R.id.title, list);
}
#Override
public View getView(final int position,
final View convertView,
final ViewGroup parent) {
final View row = super.getView(position, convertView, parent);
Book book = getItem(position);
textView.setText(book.getTitle());
return row;
}
}
}
The FirstPage looks awesome, like it should. I see list of books titles.
But on the second page, list view is empty. All other views on second page (like TextView..) are fine except ListView.
What I do wrong ?
P.S FragmentStatePageAdapter is from support13. Fragments are from android package, not from support4
I have a FragmentActivity that uses a ViewPager to flip left and right through pages of data (two ListFragments).
public class StopsActivity extends FragmentActivity {
private ViewPager mViewPager;
private PagerTabStrip mPagerTabStrip;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stops);
mPagerTabStrip =(PagerTabStrip)findViewById(R.id.pager_header);
mViewPager = (ViewPager)findViewById(R.id.pager);
mPagerTabStrip.setDrawFullUnderline(true);
mPagerTabStrip.setTabIndicatorColorResource(R.color.pagerTabStrip);
mViewPager.setAdapter(new StopsAdapter(getSupportFragmentManager()));
mViewPager.setCurrentItem(0);
}
private class StopsAdapter extends FragmentPagerAdapter {
public StopsAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return StopsFragment.newInstance(routename, Stop.FORWARD);
case 1:
return StopsFragment.newInstance(routename, Stop.BACKWARD);
}
return null;
}
#Override
public int getCount() { return 2;}
#Override
public CharSequence getPageTitle(int position) { /* implementation ... */}
}
}
Everything runs ok, but I think that the instantation of the second StopFragment invalidate the data of the first one when getItem is called.
public class StopsFragment extends ListFragment {
private StopsAdapter mStopsAdapter;
private ListView mListView;
private String routename;
private int direction;
public static StopsFragment newInstance(String routename, int direction) {
StopsFragment stopsFragment = new StopsFragment();
// Supply arguments
Bundle args = new Bundle();
args.putString("routename", routename);
args.putInt("direction", direction);
stopsFragment.setArguments(args);
return stopsFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setup the adapter
ArrayList<Stop> stops = ...
mStopsAdapter = new StopsAdapter(getActivity(), stops);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle inState) {
View rootView = inflater.inflate(R.layout.fragment_stops, container, false);
// Attach the adapter
mListView = (ListView) rootView.findViewById(android.R.id.list);
mListView.setAdapter(mStopsAdapter);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
}
The page "IDA" corresponds to StopFragment with argument Stop.FORWARD and the page "VUELTA" corresponds the StopFragment with argument Stop.BACKWARD. As you can see in the images below, just one of them (the last one instantiate) is populated:
What I'm doing wrong?
EDIT
This is StopsAdapter
class StopsAdapter extends BaseAdapter {
private ArrayList<Stop> stops;
private LayoutInflater inflater;
public StopsAdapter(Context context, ArrayList<Stop> stops) {
this.stops = stops;
this.inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return stops.size();
}
#Override
public Object getItem(int position) {
return stops.get(position);
}
#Override
public long getItemId(int position) {
return (long)position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_stop, parent, false);
}
TextView name = (TextView)convertView.findViewById(R.id.tvStopName);
TextView description = (TextView)convertView.findViewById(R.id.tvStopDescription);
Stop stop = (Stop)getItem(position);
name.setText(stop.name);
if (stop.info != null) {
description.setText(stop.info);
}
return convertView;
}
}
Ok, my fault. The code that was giving me problems is the only that I haven't posted (ArrayList<Stop> stops = ...). The code about Fragments and ViewPager works correctly.
I have a CarsFragment which is inculde cars. One page is one trade (Ferrari, Mercedes) and on every page has a list with models of actual trade.
The main view:
public class CarsFragment extends Fragment {
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.cars_fragment, container, false);
pager = (ViewPager) view.findViewById(R.id.carsPager);
adapter = new CarsPagerAdapter(getChildFragmentManager());
pager.setAdapter(adapter);
return view;
}
}
Adapter:
public class CarsPagerAdapter extends FragmentStatePagerAdapter {
private final FragmentManager fm;
private String[] cars = new String[]{"Ferrari","Mercedes"};
public MatchesPageAdapter(final FragmentManager fm) {
super(fm);
this.fm = fm;
}
#Override
public int getCount() {
return cars.length;
}
#Override
public Fragment getItem(final int position) {
return FragmentModelList.newInstance(cars[position]);
}
#Override
public void destroyItem(final ViewGroup container, final int position, final Object object) {
super.destroyItem(container, position, object);
}
}
List:
public class FragmentModelList extends Fragment {
public static FragmentModelList newInstance(String trade) {
FragmentModelList fragmentModelList = new FragmentModelList();
Bundle args = new Bundle();
args.putString("trade", trade);
fragmentModelList.setArguments(args);
return fragmentModelList;
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_matches_list_view, container, false);
list = (ListView) view.findViewById(R.id.modelList);
return view;
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
modelListAdapter = new ModelListAdapter(getActivity());
list.setAdapter(modelListAdapter);
loadModels();
}
private void loadModels() {
new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(final Void... params) {
try {
List<Model> result = Downloader.getModelsByName(getArguments().getString("trade"));
modelListAdapter.setData(result);
return true;
} catch (Exception ex) {
return false;
}
}
#Override
protected void onPostExecute(final Boolean success) {
if (!success) {
// Show error
} else {
// Update list
modelListAdapter.notifyDataSetChanged();
}
}
}.execute();
}
}
and the modelListAdapter set row where one row inculde 2 image and some textview.
And the problem:
when i swiping on the viewpager it isn't smooth :( a loged it and when created the next or previous page (depends on swipe direction) the animation will be bad, is lagging.
What is the solution?
(SGS4 android 4.2.2 - where is the project butter :(( )