I am implmenting a Fragment activity that implements ActionBar.TabListener, so I have 3 tabs that each have ListFragments which have a list populated with data obtained through the server. I have been facing this issue for a while now, and I couldn't find an answer no matter how many questions I looked into regarding this particular issue or how many tutorials I looked at in regarding implementing ListFragments with custom array adapters.
The issue I'm having is that I couldn't get the data on the Listview to display on the app. I have managed to obtain the data through the server that I needed to populate the Custom Array Adapter before setting the adapter to the ListView. I even debugged the code and it says that the data is populated in the Adapter as well as in the Listview after making the call to set the array adapter to that Listview. Yet, I couldn't get the data in the Listview to show up in the app. I have been looking into this issue for a while now and I looked into this issue through tutorials and questions posted in forums for any suggestions(Even this one) and I have yet to find anything that has helped me resolve my issue. If anyone could point out on what I did wrong and offer suggestions to fix this issue, I'd gladly appreciate any input.
Code for the ListFragment Activity
public class MyJobsActivity extends ListFragment{
private ArrayList<Job> myJobs;
private static ListView listView;
private static ArrayList<Job> jobList;
ActionBar titleBar;
MyJobsActivity disAllList;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myJobs = (ArrayList<Job>) getArguments().getSerializable(Constants.MYJOBS);
jobList = new ArrayList<Job>();
Job datJob;
for(int i = 0; i < myJobs.size(); i++){
datJob = new Job();
datJob.setJobId(myJobs.get(i).getJobId());
datJob.setJobTitle(myJobs.get(i).getJobTitle());
datJob.setCompany(myJobs.get(i).getCompany());
datJob.setLocation(myJobs.get(i).getLocation());
jobList.add(datJob);
}
MyJobsAdapter datAdapter = new MyJobsAdapter(getActivity(), R.layout.job_row, jobList);
listView.setAdapter(datAdapter);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
try{
Intent datIntent = new Intent(getActivity(),JobActivity.class);
Job job = jobList.get(position);
datIntent.putExtra(Constants.JOBID, job.getJobId());
datIntent.putExtra(Constants.JOBTITLE, job.getJobTitle());
startActivity(datIntent);
}
catch(RuntimeException e){
e.printStackTrace();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View rootView = inflater.inflate(R.layout.activity_my_jobs, container, false);
listView = (ListView) rootView.findViewById(android.R.id.list);
return rootView;
}
}
XML file for ListFragment Activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:background="#FFFFFF">
<ListView
android:id="@android:id/list"
android:drawSelectorOnTop="false"
android:tag="my_jobs"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent" />
</LinearLayout>
Code for the custom array adapter
public class MyJobsAdapter extends ArrayAdapter<Job> {
private Activity activity;
private ArrayList<Job> data;
private HashMap<Integer, Boolean> selection;
private static LayoutInflater inflater=null;
private TextView jobPosition, company, location;
private CheckBox jobChecked;
private View actionView;
private int height, prevSize;
private ActionMode datMode;
public MyJobsAdapter(Activity a, int layoutResourceId, ArrayList<Job> jobs) {
super (a, layoutResourceId, jobs);
this.selection = new HashMap<Integer, Boolean>();
this.activity = a;
this.data = jobs;
}
private class ViewHolder {
TextView jobTitle;
TextView companyName;
TextView location;
}
/*public void setData(ArrayList<Job> d){
data = d;
if(data != null){
for (Job job : d){
add(job);
}
}
this.notifyDataSetChanged();
} */
public void setNewSelection(int position, boolean value){
prevSize = selection.size();
selection.put(position, value);
this.notifyDataSetChanged();
}
public boolean isPositionChecked(int position, boolean value){
boolean result = selection.get(position);
return result == true ? result : false;
}
public void removedSelection(int position){
prevSize = selection.size();
selection.remove(position);
this.notifyDataSetChanged();
}
public void clearSelection(){
prevSize = 0;
selection = new HashMap<Integer, Boolean>();
this.notifyDataSetChanged();
}
@Override
public int getCount() {
return data.size();
}
@Override
public long getItemId(int position) {
return position;
}
public void setMode(ActionMode mode){
datMode = mode;
}
public int getSelectedNumberOfItems(){
return selection.size();
}
public HashMap<Integer, Boolean> getSelectedList(){
return selection;
}
public ArrayList<Job> getData(){
return data;
}
public int getHeight(){
return height;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder jobHolder = null;
Job rowItem = getItem(position);
if(convertView==null){
convertView = inflater.inflate(R.layout.job_row, parent, false);
convertView.setBackgroundResource(R.drawable.list_selector);
jobHolder = new ViewHolder();
jobHolder.jobTitle = (TextView) convertView.findViewById(R.id.Position);
jobHolder.companyName = (TextView) convertView.findViewById(R.id.Company);
jobHolder.location = (TextView) convertView.findViewById(R.id.Location);
convertView.setTag(jobHolder);
} else{
jobHolder = (ViewHolder) convertView.getTag();
}
/* jobPosition = (TextView)vi.findViewById(R.id.Position);
company = (TextView)vi.findViewById(R.id.Company);
location = (TextView)vi.findViewById(R.id.Location);
jobChecked = (CheckBox)vi.findViewById(R.id.JobSelected);
jobChecked.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
StringBuilder lSelectedString = new StringBuilder(selection.size()).append(Constants.SELECTED);
if(isChecked){
setNewSelection(position,true);
datMode.setTitle(lSelectedString.toString());
}
else{
removedSelection(position);
datMode.setTitle(lSelectedString.toString());
if(selection.size() < 1)
datMode.finish();
}
}
});
if(selection.size() == 0){
jobChecked.setVisibility(View.GONE);
}
else{
jobChecked.setVisibility(View.VISIBLE);
jobChecked.setChecked(selection.get(position) == null ? false : true);
}
vi.setBackgroundResource(selection.get(position) == null ? color.white_color : color.holo_blue_bright);
*/
jobHolder.jobTitle.setText(rowItem.getJobTitle());
jobHolder.companyName.setText(rowItem.getCompany());
jobHolder.location.setText(rowItem.getLocation());
return convertView;
}
}
Code for each row in the ListView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/light_gray"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:descendantFocusability="blocksDescendants">
<RelativeLayout
android:id="@+id/JobRow"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<CheckBox
android:id="@+id/JobSelected"
android:layout_centerVertical ="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/Position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/dark_gray_position"
android:layout_toRightOf="@+id/JobSelected"
android:typeface="sans"
android:fontFamily="Roboto Regular"
android:textSize="22sp"
android:paddingLeft="4dip"/>
<TextView
android:id="@+id/Company"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="@color/blue_company"
android:textSize="18sp"
android:fontFamily="Roboto Regular"
android:paddingLeft="4dip"
android:layout_below="@+id/Position"
android:layout_toRightOf="@+id/JobSelected"/>
<TextView
android:id="@+id/Location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/Company"
android:layout_toRightOf="@+id/JobSelected"
android:paddingBottom="8dip"
android:paddingLeft="4dip"
android:textColor="@color/steel_gray_location"
android:fontFamily="Roboto Regular"
android:textSize="14sp"/>
</RelativeLayout>
</RelativeLayout>
Well there are a few issues you might have with the fragment lifecycle due to the statics in your MyJobsActivity, but as for showing the data itself:
In your MyJobsActivity.onActivityCreated (or wherever you end up associating your custom adapter with the underlying ListFragment), you need to use setListAdapter instead of setAdapter.
From the ListFragment docs (see Binding to Data):
You must use ListFragment.setListAdapter() to associate the list with an adapter. Do not directly call ListView.setAdapter() or else important initialization will be skipped.
To be a bit more clear, one of the many benefits of using/extending a ListFragment is that it will internally handle the binding between your custom adapter and the underlying ListView, but the adapter must be added to the ListFragment itself (i.e., setListAdapter), not on the ListView.
A few other observations:
In fact, unless you need a custom layout, I would recommend completely removing your implementation of onCreateView. This will allow the ListFragment to use its default layout, initialization, and handling for its internal ListView and you'll get (default) handling of an empty list, a loading progress bar, etc. as well.
Given the code you've posted, I would recommend against using a private ListView member in your MyJobsActivity - its parent ListFragment already maintains a copy of the underlying ListView for you, and if you're properly setting the adapter via setListAdapter, you don't need the explicit object (and if you do, use ListFragment's getListView()).
Regardless, if my own trials and challenges are any indication, the static ListView and ArrayList members will most certainly cause you grief when the fragment is destroyed and recreated (on orientation change, on restore of your app from the Recents list if the process has been torn down in the interim, etc.).