I have implemented a swipey tabs app using viewpager by using this template in Eclipse
Now i get an activity which extends FragmentActivity like this
package com.example.abcd2;
import java.util.Locale;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.NavUtils;
import android.support.v4.view.ViewPager;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class MainActivity extends FragmentActivity {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {#link android.support.v4.app.FragmentPagerAdapter} derivative, which
* will keep every loaded fragment in memory. If this becomes too memory
* intensive, it may be best to switch to a
* {#link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {#link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(
getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
if(position==0)
{
Fragment frag2=new ShowFrag2();
return frag2;}
else
{
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;}
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}
}
/**
* A dummy fragment representing a section of the app, but that simply
* displays dummy text.
*/
public static class DummySectionFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_number";
public DummySectionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_dummy,
container, false);
TextView dummyTextView = (TextView) rootView
.findViewById(R.id.section_label);
dummyTextView.setText(Integer.toString(getArguments().getInt(
ARG_SECTION_NUMBER)));
return rootView;
}
}
}
In this, to create a new fragment in one of the tabs, i use if-else based on position in the getItem() method as shown.
The fragment showfrag2 is this
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ShowFrag2 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.frag2, container, false);
}
}
My question is, how do i create a listview in one of this fragments . I would like to use a simple listview only in this manner
LevelAdapter adapter = new LevelAdapter(this,
R.layout.list_item, weather_data);
listView1 = (ListView)findViewById(R.id.listView1);
listView1.setAdapter(adapter);
But this has been done in an activity. How can i use something like this in the fragment above. Also, i cannot use ListFragment as the getView() method is returning a fragment.
Please help regarding how to implement this.
Thanks
EDIT:
Here is my adapter code :
package com.example.abcd3;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class LevelAdapter extends ArrayAdapter<Level> {
static Context context;
static int layoutResourceId;
static Level data[] = null;
/* public LevelAdapter(Context context, int layoutResourceId, Level[] data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}*/
public LevelAdapter(ShowFrag1 showFrag1, int listItem,
Level[] weather_data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
// TODO Auto-generated constructor stub
}
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
WeatherHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new WeatherHolder();
holder.imgIcon = (ImageView)row.findViewById(R.id.imgIcon);
holder.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
// holder.imgIcon2=(ImageView)row.findViewById(R.id.imgIcon2);
row.setTag(holder);
}
else
{
holder = (WeatherHolder)row.getTag();
}
Level weather = data[position];
holder.txtTitle.setText(weather.title);
holder.imgIcon.setImageResource(weather.icon);
return row;
}
static class WeatherHolder
{
ImageView imgIcon;
TextView txtTitle;
// ImageView imgIcon2;
}
}
Make sure you have ListView defined in R.layout.frag2 and set the adapter to listview in onCreateView of ShowFrag2. (Similar to the way its done in activity)
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentLayout = inflater.inflate(R.layout.frag2, container, false);
ListView listView1 = (ListView) fragmentLayout.findViewById(R.id.mylistview);
LevelAdapter adapter = new LevelAdapter(this, R.layout.list_item, weather_data);
listView1 = (ListView)findViewById(R.id.listView1);
listView1.setAdapter(adapter);
return fragmentLayout;
}
Related
I've been looking for an answer for a while now, but I haven't been able to find the same situation, so I'll try asking it here.
I'm currently creating an app with an Activity, 2 fragments and viewpager functionality. Fragment 1 has a button that will update the list on fragment 2 (the usual way, frag 1 -> activity -> frag 2) and when it reaches that method and calls notifyDataSetChanged it crashes because the adapter is null. Apparently the adapter is null and the existing List to fill the listview is empty (which isn't a huge problem because it gets filled again, but I'd like to keep the original items).
How can I update my list and why is my adapter null?
My code:
MainActivity
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
public class MainActivity extends FragmentActivity implements FirstFragment.OnUpdatedListListener {
private ViewPager viewPager;
private TestAdapter mAdapter;
//Lifecycle functions
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.TestPager);
mAdapter = new TestAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
#Override
public void onPageSelected(int position) {}
#Override
public void onPageScrollStateChanged(int state) {}
});
}
#Override
public void onListUpdated() {
logcat("Click received in main");
SecondFragment sf = SecondFragment.newInstance();
if (sf == null || !sf.isInLayout()) {
logcat("frag == null || !frag.isInLayout()");
SecondFragment newFragment = SecondFragment.newInstance();
Bundle args = new Bundle();
newFragment.setArguments(args);
android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.second_fragment, newFragment);
transaction.addToBackStack(null);
transaction.commit();
newFragment.receiver();
} else {
logcat("frag bestaat");
sf.receiver();
}
}
}
ListItemAdapter:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.List;
public class ListItemAdapter extends ArrayAdapter<ListItem> {
private final Context context;
private List<ListItem> items;
public ListItemAdapter(Context context, int resource, List<ListItem> values) {
super(context, R.layout.list_items, values);
this.context = context;
this.items = values;
}
private static class ViewHolder {
TextView tvName;
TextView tvDescription;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.list_items, parent, false);
ViewHolder viewholder = new ViewHolder();
viewholder.tvName = (TextView) rowView.findViewById(R.id.tvName);
viewholder.tvDescription = (TextView) rowView.findViewById(R.id.tvDescription);
rowView.setTag(viewholder);
}
ViewHolder holder = (ViewHolder) rowView.getTag();
holder.tvName.setText(items.get(position).getName());
holder.tvDescription.setText(items.get(position).getDescription());
return rowView;
}
}
SecondFragment:
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class SecondFragment extends Fragment {
private final static String TAG = "SecondFragment";
private List<ListItem> items = new ArrayList<>();
private ListView lv;
private ListItemAdapter adapter;
public SecondFragment() {}
public static SecondFragment newInstance() {
Bundle args = new Bundle();
secondFragment.setArguments(args);
return secondFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
items.add(new ListItem(1, "Willem", "Willemkeurige beschrijving"));
items.add(new ListItem(2, "Jos", "De Klos"));
items.add(new ListItem(3, "Leo", "Pold"));
adapter = new ListItemAdapter(getActivity(), 0, items);
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_second, container, false);
lv = (ListView) v.findViewById(R.id.lvSecond);
lv.setAdapter(adapter);
return v;
}
public void receiver() {
items.add(new ListItem(4, "Willem2", "Willemkeurige beschrijving"));
items.add(new ListItem(5, "Jos2", "De Klos"));
items.add(new ListItem(6, "Leo", "Pold3"));
adapter.notifyDataSetChanged();
}
}
You can try this:
In MyActivity add:
public class MyActivity extends FragmentActivity {
//...
private ListItemAdapter mAdapter;
public ListItemAdapter getAdapter(){
if (mAdapter==null){
mAdapter = new ListItemAdapter();
}
return mAdapter;
}
}
In your Fragment you can get the Adapter using:
((MyActivity)getActivity()).getAdapter();
This way you can "share" your Adapter.
The problem is that your calling receiver() before the fragment has been added. The fragment has its own lifecycle, so there is not guarantee that onCreate and onCreateView has been called. This is why your adapter is null. To fix this you can do:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_second, container, false);
lv = (ListView) v.findViewById(R.id.lvSecond);
lv.setAdapter(adapter);
receiver();
return v;
}
public void receiver(){
//add your strings as normal
if(adapter != null){
adapter.notifyDataSetChanged();
}
}
Here's my UI hierarchy:
Main Fragment -> Fragment with ActionBar.TabListener -> Fragment with FragmentStatePagerAdapter -> ListFragment
The issue is that the ListFragment does display the first time I go into the tab of the ListFragment, but it does not display the second time (so going to tab 2 displays it, but then going to tab 1 and then tab 2 it doesn't display itself. The ListFragment is in tab 2).
This layout works fine if I remove the FragmentStatePagerAdapter, but now my project requires pages, so I needed to add the FragmentStatePagerAdapter to make the paging work.
However, at this point I dont really know what the problem is. I dont know if the issue is in the FragmentStatePagerAdapter, the ListFragment or if the phone just for some reason looses the data of the ListFragment.
I do know that getItem in FragmentStatePagerAdapter does not get called again when switching tabs.
Here's my code for the TrendsPagerHolder and FragmentStatePagerAdapter (as inner class):
import java.util.ArrayList;
import java.util.Collections;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Fragment;
import android.os.Bundle;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class TrendsPagerHolder extends Fragment
{
private ArrayList<String>testArray = new ArrayList<String>();
private Context context;
private SharedPreferences preferences;
private Bundle applicationStatus;
// The number of pages to display
private static final int NUM_PAGES = 3;
private ViewPager pager;
//The pager adapter, which provides the pages to the view pager widget
private PagerAdapter pagerAdapter;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
context = getActivity().getApplicationContext();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
context = inflater.getContext();
applicationStatus = savedInstanceState;
View rootView = (View) inflater.inflate(R.layout.trends_screen_slider, container, false);
System.out.println("in TrendsPagerHolder onCreateView");
pager = (ViewPager) rootView.findViewById(R.id.trends_pager);
pagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
pager.setAdapter(pagerAdapter);
pager.setCurrentItem(0);
return rootView;
}
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter
{
TrendsLV[] arrayOfTrendsFragments;
public ScreenSlidePagerAdapter(FragmentManager fragmentManager)
{
super(fragmentManager);
testArray.add("One");
testArray.add("Two");
testArray.add("Three");
arrayOfTrendsFragments = new TrendsLV[NUM_PAGES];
arrayOfTrendsFragments[0] = new TrendsLV(testArray, 0);
arrayOfTrendsFragments[1] = new TrendsLV(testArray, 1);
arrayOfTrendsFragments[2] = new TrendsLV(testArray, 2);
}
#Override
public Fragment getItem(int position)
{
System.out.println("in getItem. Position = " + position);
return arrayOfTrendsFragments[position];
}
#Override
public int getCount()
{
return NUM_PAGES;
}
}
}
Here's the code for my ListFragment:
import java.util.ArrayList;
import java.util.Collections;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.ListFragment;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.AsyncTask.Status;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class TrendsLV extends ListFragment
{
private Context context;
private ArrayList<String>testArray;
private Bundle applicationStatus;
private int pageIndex;
public TrendsLV(ArrayList<String> test, int index)
{
testArray = test;
pageIndex = index;
}
public TrendsLV()
{
// required
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
context = inflater.getContext();
applicationStatus = savedInstanceState;
System.out.println("in TrendsLV onCreateView");
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
{
if (testArray != null)
{
TrendsListAdapter adapter = new TrendsListAdapter(context, testArray, pageIndex);
setListAdapter(adapter);
}
}
return super.onCreateView(inflater, container, savedInstanceState);
}
}//end class TrendsLV
And here's the code for the Adapter that is called from the ListFragment:
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class TrendsListAdapter extends ArrayAdapter<String>
{
private Context context;
private ArrayList<String>testArray;
private int pageIndex;
public TrendsListAdapter (Context c, ArrayList<String> test, int index)
{
super(c, R.layout.trends_row, test);
context = c;
testArray = test;
pageIndex = index;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.trends_row, parent, false);
TextView label_totalArea = (TextView) rowView.findViewById(R.id.trends_labelTotalArea);
label_totalArea.setText(context.getResources().getString(R.string.stringTotalArea));
return rowView;
}
}
Let me know if you need additional information to solve this issue.
I am testing it on a device using Android 4.4.4.
Thank you.
If you are inflating Fragment inside Fragment you should use getChildFragmentManager() instaed of getFragmentManager().
Here is the doc : http://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager()
public class TrendsPagerHolder extends Fragment
{
private ArrayList<String>testArray = new ArrayList<String>();
private Context context;
private SharedPreferences preferences;
private Bundle applicationStatus;
// The number of pages to display
private static final int NUM_PAGES = 3;
private ViewPager pager;
//The pager adapter, which provides the pages to the view pager widget
private PagerAdapter pagerAdapter;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
context = getActivity().getApplicationContext();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
context = inflater.getContext();
applicationStatus = savedInstanceState;
View rootView = (View) inflater.inflate(R.layout.trends_screen_slider, container, false);
System.out.println("in TrendsPagerHolder onCreateView");
pager = (ViewPager) rootView.findViewById(R.id.trends_pager);
pagerAdapter = new ScreenSlidePagerAdapter(getChildFragmentManager());
pager.setAdapter(pagerAdapter);
pager.setCurrentItem(0);
return rootView;
}
I think you should create the instance of ListFragment and use that instance in FragmentStatePagerAdapter.. some thing like this..
In Your TrendsLV class , remove the constructor and add below method to create the instance of fragment..
public static TrendsLV newInstance(ArrayList<String> test, int index) {
TrendsLV fragment = new TrendsLV();
testArray = test;
pageIndex = index;
return fragment;
}
Then update your ScreenSlidePagerAdapter as follow..
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter
{
TrendsLV[] arrayOfTrendsFragments;
public ScreenSlidePagerAdapter(FragmentManager fragmentManager)
{
super(fragmentManager);
testArray.add("One");
testArray.add("Two");
testArray.add("Three");
arrayOfTrendsFragments = new TrendsLV[NUM_PAGES];
arrayOfTrendsFragments[0] = TrendsLV.newInstance(testArray, 0);
arrayOfTrendsFragments[1] = TrendsLV.newInstance(testArray, 1)
arrayOfTrendsFragments[2] = TrendsLV.newInstance(testArray, 2)
}
#Override
public Fragment getItem(int position)
{
System.out.println("in getItem. Position = " + position);
return arrayOfTrendsFragments[position];
}
#Override
public int getCount()
{
return NUM_PAGES;
}
}
or instead of creating the array of fragments.. you can replace the in getItem() method like this..
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter
{
public ScreenSlidePagerAdapter(FragmentManager fragmentManager)
{
super(fragmentManager);
testArray.add("One");
testArray.add("Two");
testArray.add("Three");
}
#Override
public Fragment getItem(int position)
{
System.out.println("in getItem. Position = " + position);
Fragment instanceFragment = null;
switch (position) {
case 0:
instanceFragment =TrendsLV.newInstance(testArray, 0);;
break;
case 1:
instanceFragment =TrendsLV.newInstance(testArray, 1);;
break;
case 2:
instanceFragment =TrendsLV.newInstance(testArray, 2);;
break;
default:
break;
}
return instanceFragment;
}
#Override
public int getCount()
{
return NUM_PAGES;
}
}
I don't know what is the use of testArray so i haven't made any changes for it.
Hope it helps..!! :)
I have a ViewPager setup with 3 fragment Classes, and a pageadapter class.
MainActivity class
package com.example.swipeview;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
public class MainActivity extends FragmentActivity {
ViewPager viewpager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewpager = (ViewPager) findViewById(R.id.viewpagers);
com.example.swipeview.PagerAdapter padapter = new com.example.swipeview.PagerAdapter(getSupportFragmentManager());
viewpager.setAdapter(padapter);
}
}
PageAdapter class
package com.example.swipeview;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
public class PagerAdapter extends FragmentPagerAdapter {
public PagerAdapter(FragmentManager fm) {
super(fm);
// TODO Auto-generated constructor stub
}
#Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
switch(arg0){
case 0:
return new FragmentOne();
case 1:
return new FragmentTwo();
case 2:
return new FragmentThree();
default:
break;
}
return null;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return 3;
}
}
and my first FragmentClass as an example
package com.example.swipeview;
import com.example.swipeview.R;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FragmentOne extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
return inflater.inflate(R.layout.fragment_one_layout, container, false);
}
}//end of class
I've tried my usual methods for creating a listview inside of an Activity class but that doesn't work with the fragment class. I was wondering if anyone could show me how to code a listview into a fragment class.
An example with a custom adapter (using a List as source):
public class ItemsFragment extends Fragment {
/* Must be populated later. */
private final List<Item> items = new ArrayList<>();
private ItemAdapter adapter;
private ListView listView = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.fragment_items_list, container, false);
adapter = new ItemAdapter(this.getActivity(), items);
listView = (ListView) layout.findViewById(R.id.listview_items);
return layout;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Item currentItem = adapter.getItem(position);
// (...)
}
});
}
/* (...) */
}
I am trying to make the Contact tab in my app to list the users address book's name and phone number, however when I set the adapter for contactlist the app no longer shows its tabs and the fragment is empty.
Code:
package com.spgrn.smsim;
import java.util.ArrayList;
import java.util.Locale;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.FragmentPagerAdapter;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {#link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {#link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {#link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
String phoneNumber;
ListView contactlist;
ArrayList <String> aa= new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contactlist= (ListView) findViewById(R.id.contactv);
getNumber(this.getContentResolver());
// Set up the action bar.
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
Log.v("I", "curtab="+ mSectionsPagerAdapter.getCount() + "i=" + i);
if (i != 1)
actionBar.addTab(
actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this),
false);
if (i == 1)
actionBar.addTab(
actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this),
true);
}
}
public void getNumber(ContentResolver cr)
{
Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, null);
while (phones.moveToNext())
{
String name=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
System.out.println(name + phoneNumber);
aa.add(name + "\n" + phoneNumber);
}
Log.v("Contacts", "Total= " + phones.getCount());
phones.close();// close cursor
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,aa);
contactlist.setAdapter(adapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#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();
if (id == R.id.action_settings) {
return true;
}
if (id == R.id.action_compose) {
Intent intent = new Intent(this, NewMessage.class);
this.startActivity(intent);
}
return super.onOptionsItemSelected(item);
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
//return PlaceholderFragment.newInstance(position + 1);
switch (position){
case 0:
Fragment fragmentContacts = new FragmentContacts();
return fragmentContacts;
case 1:
Fragment fragmentMessages = new FragmentMessages();
return fragmentMessages;
case 2:
Fragment fragmentAccounts = new FragmentAccounts();
return fragmentAccounts;
}
return null;
}
#Override
public int getCount() {
// Show 5 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}
}
//Make fragments for each tab
public static class FragmentContacts extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_number";
public FragmentContacts() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_contacts,
container, false);
return rootView;
}
}
public static class FragmentMessages extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_number";
public FragmentMessages() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main,
container, false);
return rootView;
}
}
public static class FragmentAccounts extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_number";
public FragmentAccounts() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_accounts,
container, false);
return rootView;
}
}
//End of Tab Fragments
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
}
Also, in the debugger I noticed the main activity was suspended due to a run time exception. Here is the stack:
Thread [<1> main] (Suspended (exception RuntimeException))
<VM does not provide monitor information>
ActivityThread.performLaunchActivity(ActivityThread$ActivityClientRecord, Intent) line: 2195
ActivityThread.handleLaunchActivity(ActivityThread$ActivityClientRecord, Intent) line: 2245
ActivityThread.access$800(ActivityThread, ActivityThread$ActivityClientRecord, Intent) line: 135
ActivityThread$H.handleMessage(Message) line: 1196
ActivityThread$H(Handler).dispatchMessage(Message) line: 102
Looper.loop() line: 136
ActivityThread.main(String[]) line: 5017
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object...) line: 515
ZygoteInit$MethodAndArgsCaller.run() line: 779
ZygoteInit.main(String[]) line: 595
XposedBridge.main(String[]) line: 126
NativeStart.main(String[]) line: not available [native method]
Thanks!
Edit: Looking more, I think the list needs to be generated in the fragments class, but I am not sure what to do with the context. I keep getting a NullPointerException.
Code:
public static class FragmentContacts extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_number";
public FragmentContacts() {
}
Context context;
String phoneNumber;
ListView contactlist;
ArrayList <String> aa= new ArrayList<String>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_contacts,
container, false);
contactlist = (ListView) rootView.findViewById(R.id.contactv);
getNumber(context.getContentResolver());
return rootView;
}
public void getNumber(ContentResolver cr)
{
Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, null);
while (phones.moveToNext())
{
String name=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
System.out.println(name + phoneNumber);
aa.add(name + "\n" + phoneNumber);
}
Log.v("Contacts", "Total= " + phones.getCount());
phones.close();// close cursor
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity()
.getApplicationContext(),
android.R.layout.simple_list_item_1,aa);
contactlist.setAdapter(adapter);
}
}
write
context=container.getContext();
in onCreateView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_contacts,
container, false);
contactlist = (ListView) rootView.findViewById(R.id.contactv);
context=container.getContext();
getNumber(context.getContentResolver());
return rootView;
}
I've written a few listView activities, as a proof of concept for myself that I could do it. Now, I'm having trouble loading a listView activity into a single tab for an app with multiple tabs, that allows both swiping and tab selection for navigation. I get the error "The constructor ListView_Adapter(MainActivity.DummySectionFragment) is undefined" when I try to write the code for it. I'm a beginner, and I've lurked pretty hard here for the past few days. Any help is appreciated.
TL;DR : I'm a n00b, and I can't figure out this problem.
My Custom List Adapter
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class CustomListViewAdapter extends ArrayAdapter<String> {
public CustomListViewAdapter (Context c) {
super(c, R.layout.list_cell);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ListView_Text holder = null;
if (row == null)
{
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.list_cell, parent, false);
holder = new ListView_Text(row);
row.setTag(holder);
}
else
{
holder = (ListView_Text) row.getTag();
}
holder.populateFrom(getItem(position));
return row;
}
static class ListView_Text {
private TextView cell_name = null;
ListView_Text(View row) {
cell_name = (TextView) row.findViewById(R.id.list_cell_name);
}
void populateFrom(String index) {
cell_name.setText(index);
}
}
}
My Main Activity
import java.util.Locale;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.FragmentTransaction;
import com.example.twigglebeta2.ListView_Adapter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.NavUtils;
import android.support.v4.view.ViewPager;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
private static ListView_Adapter listViewAdapter;
private ListView listView;
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create adapter
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// Switch tab selection to match current page when swiped
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// Create a tab for each 'count' in the activity from getCount()
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
Tab thisTab = actionBar.newTab();
thisTab.setText(mSectionsPagerAdapter.getPageTitle(i));
thisTab.setTabListener(this);
actionBar.addTab(thisTab);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onTabSelected(ActionBar.Tab tab,FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab,FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab,FragmentTransaction fragmentTransaction) {
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}
}
/**
* A dummy fragment representing a section of the app, but that simply
* displays dummy text.
*/
public static class DummySectionFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_number";
public DummySectionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_dummy,container, false);
switch(getArguments().getInt(ARG_SECTION_NUMBER)){
case 1:
//The constructor ListView_Adapter(MainActivity.DummySectionFragment) is undefined
listViewAdapter = new ListView_Adapter(this);
ListView listView = (ListView) rootView.findViewById(R.id.listView1);
for (int i=0;i<20;i++)
{
listViewAdapter.add("this Index : "+i);
}
return listView;
}
TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
dummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
return rootView;
}
}
}
Instead of listViewAdapter = new ListView_Adapter(this);, you should instead try listViewAdapter = new ListView_Adapter(getActivity().getBaseContext());
The Issue is that you are passing a Fragment to the constructor, and not an Activity context.