It's time for the last and final step – binding our data to the user interface. This section should look very familiar for those who have gone through the entire book, so I'll try to be brief but complete.
In the previous sections, we essentially hooked all the network requests together, both on the application side as well as on the server side, so that now we should be able to seamlessly make GET requests from any mobile application. We also looked at ways in which we could parse the resulting response (again, this was left as an exercise, as the response could come back in any number of ways) and convert the data from string form back into VideoGame
object form.
So now let's think back to Chapter 6, Binding to the UI. In that chapter, we looked at two subclasses of ListAdapters
– the
BaseAdapter
and the CursorAdapter
. As you'll recall, the CursorAdapter
is used when our data is stored into a SQLite database. The subsequent query into our SQLite database is returned in the form of a Cursor
object which then gets wrapped by the CursorAdapter
class. In our VideoGame
example, we currently have a list of objects, not a Cursor
. That's not to say that we couldn't store our results into a SQLite database, effectively making a cache (remember these?) on our application side and then issuing a query into our cache to get back a Cursor
. But, for simplicity, let's stick with our list of VideoGame
objects and simply use a BaseAdapter
which is designed especially for such lists. The code for it might look like the following:
public class VideoGameBaseAdpater extends BaseAdapter { // REMEMBER CONTEXT SO THAT CAN BE USED TO INFLATE VIEWS private LayoutInflater mInflater; // LIST OF VIDEO GAMES private List<VideoGame> mItems = new ArrayList<VideoGame>(); public VideoGameBaseAdpater(Context context, List<VideoGame> items) { // HERE WE CACHE THE INFLATOR FOR EFFICIENCY mInflater = LayoutInflater.from(context); mItems = items; } public int getCount() { return mItems.size(); } public Object getItem(int position) { return mItems.get(position); } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { VideoGameViewHolder holder; // IF NULL THEN NEED TO INSTANTIATE IT BY INFLATING IT if (convertView == null) { convertView = mInflater.inflate(R.layout.list_entry, null); holder = new VideoGameViewHolder(); holder.name_entry = (TextView) convertView.findViewById(R.id.name_entry); holder.type_entry = (TextView) convertView.findViewById(R.id.number_type_entry); convertView.setTag(holder); } else { // GET VIEW HOLDER BACK FOR FAST ACCESS TO FIELDS holder = (VideoGameViewHolder) convertView.getTag(); } // EFFICIENTLY BIND DATA WITH HOLDER VideoGame v = mItems.get(position); holder.name_entry.setText(v.getName()); String type = VideoGameConsole.convertIntToString(v.getConsoleType()); holder.type_entry.setText(type); return convertView; } static class VideoGameViewHolder { TextView name_entry; TextView type_entry; } }
So just like how in Chapter 6, Binding to the UI, we implemented a custom BaseAdpater
that created a list of Contact
objects – in this case, we're doing something extremely similar but for our VideoGame
objects! Notice here that my VideoGameViewHolder
only displays the name of the game and the type of the game and that I'm not doing anything with the image URL. Again, one could easily incorporate this into each row through using an ImageView
, but that would require converting a URL into a Bitmap object – something that's not difficult to do but unnecessary in our case; you get the idea by now.
Now that this is done, we simply need to create an Activity which makes the GET request, takes the resulting list of VideoGames
, and sets them as its ListAdapter
by using the custom
VideoGameBaseAdapter
. The code for this is extremely simple:
public class VideoGameBaseAdapterActivity extends ListActivity { private List<VideoGame> games; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.list); // MAKE GET REQUEST TO RETRIEVE GAMES games = GetVideoGamesAndroid.getGamesByType(VideoGameConsole.XBOX); // USE VIDEO GAME ADAPTER VideoGameBaseAdpater vAdapter = new VideoGameBaseAdpater(this, games); // SET THIS ADAPTER AS YOUR LIST ACTIVITY'S ADAPTER this.setListAdapter(vAdapter); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); VideoGame vg = games.get(position); String name = vg.getName(); System.out.println("CLICKED ON " + name); } }
Once done, our end result looks like the following:
And voila! Pat yourself on the back, as we've now just finished our first full-scale data-centric application! Now not only do we have a fully functional backend equipped with its own set of HTTP requests, but we've also built the beginning of a promising Android application that can make HTTP requests to this backend, obtain the results, and display them in a simple list.
18.191.78.136