Intro to Backbone.js Lightning Talk


About a week ago I gave a lightning talk on Intro to Backbone.js at Condg. Here are the slides and the demo project I used. The project requires Asp.Net MVC 4. Don’t be wary of the links, they are just paths to public files in dropbox.

Visual Studio Project:

https://dl.dropboxusercontent.com/u/39163933/Blog/BackbonePresentation/BackboneDemo.zip

PowerPoint Presentation:

https://dl.dropboxusercontent.com/u/39163933/Blog/BackbonePresentation/IntroToBackbone.pptx

author: John Nastase | posted @ Saturday, August 03, 2013 9:37 AM | Feedback (1)

Dynamic Controls and View State


Glad to see the title hasn’t scared you off as talking about just one of these topics can get pretty hairy. The reason for this post comes from an issue I was looking into last week. I don’t want to go into all the details but the problem was that a grid that had view state was not repopulating it values during postbacks. I also don’t want to go into too many details about view state and dynamic controls so I suggest reading the following posts by Dave Reed on view state and dynamic controls. The one is pretty lengthy and the other is a four part post so make sure you set aside some time before diving into these. The thing to take away from those is that view state does not store the controls that are on the page or ones that are added to the page.

Back to the issue. To demonstrate I made a created a new page with a few controls so it will be easier to follow. Below is the markup I will use in this post.

<%@ Page Title="Home Page" Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ViewStateAndDynamicControls._Default" %>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Viewstate test
    </title>
</head>
<body>
    <div>
        <form runat="server">
            <asp:Label Text="before panel, set in markup" runat="server" ID="lblBeforePanel" />
            <asp:Panel runat="server" ID="pnlHolder" BorderWidth="1">
                <asp:Label Text="first in panel, set in markup" runat="server" ID="lblFirstInPanel" />
                <asp:GridView runat="server" ID="gvInPanel" AutoGenerateColumns="false">
                    <Columns>
                        <asp:TemplateField>
                            <ItemTemplate>
                                <asp:Label runat="server" ID="lblName" Text='<%# Eval("Name") %>' />
                            </ItemTemplate>
                        </asp:TemplateField>
                    </Columns>
                </asp:GridView>
                <asp:Label runat="server" ID="lblAfterGridInPanel" Text="after grid in panel, set in markup" />
            </asp:Panel>
 
            <asp:GridView runat="server" ID="gvOutside" AutoGenerateColumns="false">
                <Columns>
                    <asp:TemplateField>
                        <ItemTemplate>
                            <asp:Label runat="server" ID="lblName" Text='<%# Eval("Name") %>' />
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
            <asp:Button runat="server" ID="btnPostback" Text="post page" OnClick="btnPostback_Click" />
        </form>
    </div>
</body>
</html>
As you can see I have a label, a panel with some labels before and after a grid view, and then I have the pretty much the same grid view outside of the panel. It should be noted that view state is on all of the controls by default. Now here is the code in the code behind.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
 
namespace ViewStateAndDynamicControls
{
    public partial class _Default : Page
    {
 
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                gvInPanel.DataSource = GetPeople();
                gvInPanel.DataBind();
 
                gvOutside.DataSource = GetPeople();
                gvOutside.DataBind();
 
                var dynLabel = new Label();
                dynLabel.Text = "dynamic label in page load<br />";
                pnlHolder.Controls.AddAt(2, dynLabel);
 
                lblFirstInPanel.Text = "first in panel, set in code";
                lblAfterGridInPanel.Text = "after grid in panel, set in code";
            }
        }
 
        private List<Person> GetPeople()
        {
            return new List<Person> { new Person { Name = "foo bar"},
                                        new Person { Name = "john doe"},
                                        new Person { Name = "jane smith"},
                                        new Person { Name = "bill gates"}
            };
        }
 
        protected void btnPostback_Click(object sender, EventArgs e)
        {
        }
 
    }
 
    class Person
    {
        public string Name { get; set; }
    }
 
}

Nothing too crazy here. The thing to point out is the control we are creating and then inserting into the control tree of the panel in the page load. Notice we are inserting it between the first label and the grid and only creating it if the page is not posted back. This will create problems for the grid the follows it inside of the panel after the postback. The following is a picture of the page when it is first loaded and the second picture is what the page looks like after a postback has occurred.

Notice that after the postback the grid inside of the panel does not get repopulated. In fact if you look close you notice the label after the grid does not get set from view state either. But why is this? If you have read the previous links you will know that view state does not store the controls added to the page. So the control we added in the page load is not there when the page is posted back. But the first time we request the page the control is in the control tree and its value is saved into view state. When the page is posted back, load view state is called but the control tree from when view state was saved is now different from when it is loaded. It’s hard to explain and I don’t know the exact technical reason but here is why I think this is. There is a value where the label was in the tree but since it is not there it tries to set the value to the control now in that spot. This happens to be the grid. The grid cannot be set with the value that was in the label so it just ignores it. This then has a chain effect on the rest of the controls inside the current container, which happens to be the panel. The grid is no longer in the same place in the control tree and neither are any of the controls that come after it in the panel. This is why the grid that is outside of the panel is able to retain its values after the postback.

I didn’t show it but if I added the label in the page init then the page would behave as you would expect since view state is loaded after the init. As the linked posts mention, avoid dynamic controls whenever you can but if you have to use them, make sure you use them properly. Hope this was useful and that you never run into this in your coding.

author: John Nastase | posted @ Tuesday, February 05, 2013 12:00 AM | Feedback (1)

Disabling the Wrong HTML Elements


Again, it has been a while since I have blogged about anything but I came across something interesting the other day at work. To help you understand my problem I should give a little background about how my client’s system operates. They have a code base that is used for a few hundred front end sites. Since the code handles this many sites it has to be flexible enough to handle different types of input based on the information required for each site. For this post, lets assume that one site requires first and last name while some other site doesn’t. What the code will do when a form is submitted is see if first and last name are part of the values submitted and if they are, makes sure validation is run on those fields to make sure they have values in them. If they are not there then the site assumed they are not required and validation is not done on those fields.

To the problem I was trying to solve. The site I was looking into had some Ajax stuff that would find an address based on zip code and house number and return the results into a drop down for you to select. Once you selected a drop down and clicked a button the address fields that were in a hidden div would be filled in a the div would be displayed. While hidden, this div with the address information was also being disabled by having the disabled attribute added to it. Read that last sentence carefully as it is the entire point of this post.

Normally I would assume a disabled div is nothing to worry about, but what was happening is that when Internet Explorer users would search for an address but not explicitly select one from the drop down, the address div remained hidden and disabled when the form was submitted. This was causing unexpected behavior on the page because things that were suppose to be there and be validated were assumed to not be required and the rather than return the validation errors the page continued executing, throwing an errors farther down the pipeline.

As I mentioned before the problem had to do with the div that contained the address inputs being disabled. When run in Firefox and Chrome, the page behaved as expected and this error was limited to Internet Explorer. I should note that I am using the latest versions of each browser. At first I didn’t know where to start and it was only after discovering the script used to do the address lookup did I find what I needed. I noticed that after each step it was disabling and hiding the divs that were not part of the current step. I thought this might be the problem so I set up a simple test to test my theory. I created a simple Asp.Net project and created the markup below inside the form tag.

   1: <div disabled>
   2:     <table border="0" cellpadding="0" cellspacing="0">
   3:         <tr>
   4:             <td>
   5:                 First Name:
   6:             </td>
   7:             <td>
   8:                 <input name="txtFirstName" type="text" />
   9:             </td>
  10:         </tr>
  11:         <tr>
  12:             <td>
  13:                 Last Name:
  14:             </td>
  15:             <td>
  16:                 <input name="txtLastName" type="text" />
  17:             </td>
  18:         </tr>
  19:     </table>
  20: </div>
  21: <asp:Button ID="btnSubmit" Text="Submit" runat="server" 
  22:     onclick="btnSubmit_Click" />

I then added a breakpoint inside the click event of the button to see how many values came up with the form. Even though the div is disabled you can still type into the textboxes. When I submitted the browser in IE, first and last name were not there. When I submitted it in Chrome and Firefox, the values were there. As it turns out, according to the W3C, divs are not valid elements to be disabled and the default behavior for inputs that are disabled is for their values to not be submitted with the form. Since they were not generating valid HTML I assume it was up to each browser how they wanted to handle it. IE decided to not submit the values since they were in a disabled element and Chrome and Firefox decided to submit them since the inputs themselves were not disabled. While this is not something you should ever have to worry about if you generate valid HTML I still think it is interesting and maybe something worth knowing.

author: John Nastase | posted @ Sunday, May 06, 2012 10:03 PM | Feedback (0)

My First Visual Studio Extension


Recently one of my friends on twitter mentioned they were looking for a Visual Studio extension that would keep the cursor a few lines away from the edge of the editor window to allow you to preview the upcoming text when using the arrows to move the cursor. After looking for one myself and not being able to find one, I decided to take a shot at creating an extension to do just that. It seemed like something that would be pretty easy to make. So I downloaded the Visual Studio SDK and got started. A few hours later I had the basic functionality down and sent it off to my friend to see if that was what he was looking for.

After hearing back that it was what he was looking for, he encouraged me to publish it to the Visual Studio Extension Library, which I did. The extension is called Padded Cursor. If you have VS 2010, please download it and let me know what you think of it.

author: John Nastase | posted @ Sunday, January 22, 2012 5:44 PM | Feedback (3)

Custom Android ListActivity


In a previous post I demonstrated the concept of “master pages” in Android. Essentially what this did was allow you to have a base layout so that you didn’t have to repeat the same layout on all views that had the same things at the top and bottom of the layout. In the comments someone asked how this could be applied to the ListActivity. I haven’t done much with Android the last few months and have not had the chance to use this activity type yet so I decided to look into it.

After throwing some simple pages together I am not sure the master page concept can be directly applied to this situation. The reason being is that any class the extends the ListActivity class needs to have a ListView with the id @android:id/list. If we want to have a base layout with items above and below then we don’t want to have the list in that view.

The alternative is to create a ListActivity with a customize layout. Looking at the documentation the requirements are very simple. As mentioned earlier your layout must include a ListView with an id of @android:id/list. Then in the onCreate you call setContentView and pass in the id of your layout. See below.

Here is the layout for my activity:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   3:     android:layout_width="wrap_content" android:layout_height="fill_parent"
   4:     android:orientation="vertical">
   5:     <ListView android:id="@android:id/list" android:layout_width="wrap_content"
   6:         android:layout_height="wrap_content" android:layout_weight="1" />
   7:     <LinearLayout android:orientation="horizontal"
   8:         android:layout_width="wrap_content" android:layout_height="wrap_content">
   9:         <Button android:layout_width="wrap_content" android:id="@+id/button1"
  10:             android:layout_height="wrap_content" android:text="Press Me" />
  11:         <Button android:layout_width="wrap_content" android:id="@+id/button2"
  12:             android:layout_height="wrap_content" android:text="Press Me" />
  13:     </LinearLayout>
  14: </LinearLayout>

And here is the activity.

   1: public class MyListView extends ListActivity {
   2:  
   3:     Button button1, button2;
   4:  
   5:     @Override
   6:     protected void onCreate(Bundle savedInstanceState) {
   7:         super.onCreate(savedInstanceState);
   8:  
   9:         setContentView(R.layout.my_list_layout);
  10:  
  11:         button1 = (Button) findViewById(R.id.button1);
  12:         button2 = (Button) findViewById(R.id.button2);
  13:         
  14:         button1.setOnClickListener(button1Listener);
  15:         button2.setOnClickListener(button2Listener);
  16:  
  17:         String[] names = new String[] { "Item1", "Item2", "Item3", "Item4",
  18:                 "Item5", "Item6", "Item7", "Item8" };
  19:         this.setListAdapter(new ArrayAdapter<String>(this,
  20:                 android.R.layout.simple_list_item_1, names));
  21:     }
  22:  
  23:     private OnClickListener button1Listener = new OnClickListener() {
  24:  
  25:         public void onClick(View v) {
  26:             String[] names = new String[] { "Item1", "Item2", "Item3", "Item4",
  27:                     "Item5", "Item6", "Item7", "Item8" };
  28:             setListAdapter(new ArrayAdapter<String>(getBaseContext(),
  29:                     android.R.layout.simple_list_item_1, names));
  30:         }
  31:     };
  32:  
  33:     private OnClickListener button2Listener = new OnClickListener() {
  34:  
  35:         public void onClick(View v) {
  36:             String[] names = new String[] { "Blah1", "Blah2", "Blah3", "Blah4",
  37:                     "Blah5", "Blah6", "Blah7", "Blah8" };
  38:             setListAdapter(new ArrayAdapter<String>(getBaseContext(),
  39:                     android.R.layout.simple_list_item_1, names));
  40:         }
  41:     };
  42:  
  43: }

I added some buttons to show you how to change the items in the list by clicking one or the other. Obviously you would want to get your data from a data store of something other than a static list. As always I hope this helps and if anyone comes up with a way to have a base activity and layout I would be very interested in how you accomplished that. Here is the Android documentation for some more info.

http://developer.android.com/reference/android/app/ListActivity.html

author: John Nastase | posted @ Monday, August 08, 2011 11:45 PM | Feedback (27)

Compiled Linq Queries


For the past few months at work I have been working on importing records from one system to another. For the data access we have been using Ling to SQL. For the one system we had to perform some pretty tricky queries to make sure we got only non deleted records. To do this for all the tables we had pretty much the same query everywhere in our class, modified of course to get the different types out. When we started running the program to moves records the first thing we noticed was that it was pretty slow, and by slow I mean a record every couple seconds. Since we were processing tens of thousand of records we needed to find a way to speed this up. Our first thought was to put indexes on the database but this yielded no noticeable gain at all. We weren’t doing anything fancy in the code so I decided to do a quick Bing search for link performance tips. The search returned tons of links to blogs with 5 or 10 tips on how to improve the performance. Some of the tips didn’t seem to be relevant or feasible for our application but the one tip that I kept seeing was compiling your queries.

I had read about being able to compile your queries but never thought of it as a practical solution. Being skeptical I started to compile some of my queries and and then ran the program with and without the compiled queries. To my surprise the program run much faster with the compiled queries. Having proved that they were indeed faster I decided to replace all of my inline queries with compiled ones. After replacing all the queries we started importing records again. The performance increase was noticed immediately, we went from an average of one every two seconds to about 2 every second. I read that this could speed up performance 3-5 times which seemed to be the case here.

What is happening with compiled queries, or at least what I think is happening, is that the first time the query is run the expression tree is created and the next time it is run all it has to do is plug in the parameter(s) from the delegate. This way the expression tree only has to be created once, which is why this is great for queries that will be run over and over in your application.

 

Here are a couple links I used find this info:

http://www.sidarok.com/web/blog/content/2008/05/02/10-tips-to-improve-your-linq-to-sql-application-performance.html

http://davidhayden.com/blog/dave/archive/2008/02/19/HighPerformanceLINQToSQLCompiledQueriesORMappersEcommerceWebsites.aspx

author: John Nastase | posted @ Thursday, February 17, 2011 6:32 PM | Feedback (5)

Review of Professional Android 2 Application Development


For those of you who have been following some of my recent posts you have noticed that I have been doing quite a bit of Android development lately. Nathan suggested in the comments of one of my posts that I review the book I used to get started.

I bought the book Professional Android 2 Application Development over the summer shortly after buying an Android phone. I had tried to get started by just using the Android website, but I am not one for browsing all over a site to learn all the features of a language or platform. I wanted a book so that I would be able to learn what certain features of the platform were called and this book allowed me to do just that. The book starts with an intro and how to setup your environment to start development and then goes on to discuss views, activities, intents, menus, preferences, storage and so on. Like I mentioned, I wanted a book that would explain to mean what the features of the platform were called. By that I mean I didn’t know that the menus that show up when you long press an item are context menus or that intents are used to start one activity from another. This book did a good job of explaining exactly those things and was just what I was looking for when I purchased it.

I read the first 10 or so chapters since those contained most of the topics I was interested in and relied on the Android site and Bing for the rest of my questions. I would definitely recommend this book to anyone who has some programming experience and is looking to get started with the Android platform.

author: John Nastase | posted @ Sunday, January 09, 2011 10:08 PM | Feedback (2)

“Master Pages” in Android


The title of this post may be a little confusing because there aren’t master pages in Android. I have done a lot of development in Asp.Net which has the concept of master pages. A master page in Asp.Net allows you to put content that will be the same into the master page file and use place holders to the content that will be different for each page. The runtime then combines the master page with the requested page at runtime.

I have been working on a project for a client and the wanted their logo to be at the top of every activity. Since there were more than a couple activities I wanted have something like this master page functionality just in case they didn’t like the way it looked and wanted to change it. The solution was pretty easy. To start I created an a base Activity and derived it from the activity class. Then I overrode the onCreate and setContentView methods. In the onCreate I called the parents onCreate method and assigned any layout objects that needed to be used. In the setCotentView I created an inflater class and used it to inflate the view they passed in into a layout object on my base layout. My base layout only had a few LinearLayouts and an image for the logo. Then in my other activities I had them derived from my base Activity instead of the normal Activity class. When these activities called setContentView they were really causing their layout to be placed inside of my base layout. That was all there was to it. The only thing I noticed so far was that when requesting a progress bar (requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS)) this needs to be done before calling super.onCreate. I think this is because nothing can be drawn yet before calling this function. The code for my base activity and layout are below.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <LinearLayout
   3:       xmlns:android="http://schemas.android.com/apk/res/android"
   4:       android:layout_width="fill_parent"
   5:       android:layout_height="fill_parent"
   6:       android:orientation="vertical"
   7:       android:background="#000000"
   8:       android:padding="15dp" >
   9:       <LinearLayout android:orientation="horizontal" android:background="#000000"
  10:             android:layout_width="fill_parent" android:layout_height="wrap_content"
  11:             android:minHeight="50dp" android:paddingLeft="10dp">
  12:             <ImageView android:layout_width="wrap_content" android:id="@+id/ImageView01"
  13:                 android:adjustViewBounds="true" android:layout_height="wrap_content"
  14:                 android:scaleType="fitCenter" android:maxHeight="50dp" />
  15:     </LinearLayout>
  16:     <LinearLayout android:id="@+id/linBase"
  17:       android:layout_width="fill_parent"
  18:         android:layout_height="fill_parent" >
  19:     </LinearLayout>      
  20: </LinearLayout>

and the code for the activity:

   1: public class BaseActivity extends Activity {
   2:  
   3:     ImageView image;
   4:     LinearLayout linBase;
   5:     
   6:     public void onCreate(Bundle savedInstanceState) {
   7:         super.onCreate(savedInstanceState);
   8:         
   9:         super.setContentView(R.layout.base_layout);
  10:         
  11:         image = (ImageView)findViewById(R.id.ImageView01);
  12:         image.setImageResource(R.drawable.header);
  13:         
  14:         linBase = (LinearLayout)findViewById(R.id.linBase);
  15:     }
  16:     
  17:     @Override
  18:     public void setContentView(int id) {
  19:         LayoutInflater inflater = (LayoutInflater)getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  20:         inflater.inflate(id, linBase);
  21:     }
  22:         
  23: }

To use this you simply have you class derived from your base Activity

   1: public class SomeActivity extends BaseActivity {
   2:     
   3:     public void onCreate(Bundle savedInstanceState) {
   4:         super.onCreate(savedInstanceState);
   5:         
   6:         super.setContentView(R.layout.some_layout);
   7:         
   8:         //rest of code
   9:     }
  10:         
  11: }

This worked great for me and hopefully you will find this useful in your own coding.

author: John Nastase | posted @ Saturday, January 08, 2011 12:09 PM | Feedback (6)

Custom Adapter for AutoComplete


In my last post I showed how to create your own Adapter to display items how you want to in a ListView. In this post I will show you how to extend that example to allow you to set your adapter to an AutoComplete box in android. You can’t bind just any Adapter to an AutoComplete in android. In addition to deriving from the BaseAdapter class it also has to implement the Filterable interface. I thought that this would be a piece of cake and that simply extending the interface would cause some magic to happen and I would be done. Unfortunately this wasn’t the case. The interface has one method called getFilter() which simply returns an object of type Filter.

Again simple enough except that Filter is an abstract class and in order to get this to work I had to create my own Filter class. I did some research and found that the preferred approach seems to be a nested class inside of the Adapter so I went from there. I created my class and created a constructor and the stubs of the two methods we need to override from the base class.

   1: private class GameFilter extends Filter {
   2:  
   3:     public GameFilter() {
   4:         
   5:     }
   6:     
   7:     @Override
   8:     protected FilterResults performFiltering(CharSequence constraint) {
   9:  
  10:     }
  11:  
  12:     @SuppressWarnings("unchecked")
  13:     @Override
  14:     protected void publishResults(CharSequence constraint, FilterResults results) {
  15:  
  16:     }
  17:  
  18: }

After that I had to make a minor change to our Adapter class. I needed to add another ArrayList that would be responsible for keeping track of the original data and an object of our newly created class that will be returned in the getFilter method required for the interface. All that was left was to implement the methods in our Filter class. The performFilter method was easy since we simply had to look through the list and find games whose name contained the constraint parameter and and them to a temporary list. Once we were finished, we assigned this list to the values member on the FIlterResults class we were returning. Then in the publishResults method we assigned that list to our games list, which is the list the AutoComplete is binding to and notify it of the change. This method is called asynchronously from the main thread which is why it is void. Here is the complete code for the completed adapter class.

   1: public class GameAdapter extends BaseAdapter implements Filterable {
   2:  
   3:     Context _context;
   4:     ArrayList<Game> games;
   5:     
   6:     public GameAdapter(Context context, ArrayList<Game> _games) {
   7:         _context = context;
   8:         games = _games;
   9:         orig = games;
  10:         filter = new GameFilter();
  11:     }
  12:     
  13:     @Override
  14:     public int getCount() {
  15:         if (games != null)
  16:             return games.size();
  17:         else
  18:             return 0;
  19:     }
  20:  
  21:     @Override
  22:     public Object getItem(int arg0) {
  23:         return games.get(arg0);
  24:     }
  25:  
  26:     @Override
  27:     public long getItemId(int arg0) {
  28:         return games.get(arg0).getID();
  29:     }
  30:  
  31:     @Override
  32:     public View getView(int arg0, View arg1, ViewGroup arg2) {
  33:         GameView gv;
  34:         if (arg1 == null)
  35:             gv = new GameView(_context, games.get(arg0));
  36:         else {
  37:             gv = (GameView) arg1;
  38:             gv.setID(games.get(arg0).getID());
  39:             gv.setName(games.get(arg0).getName());
  40:         }
  41:         return gv;
  42:     }
  43:  
  44:     @Override
  45:     public Filter getFilter() {
  46:         return filter;
  47:     }
  48:     
  49:     private GameFilter filter;
  50:     ArrayList<Game> orig;
  51:     
  52:     private class GameFilter extends Filter {
  53:  
  54:         public GameFilter() {
  55:             
  56:         }
  57:         
  58:         @Override
  59:         protected FilterResults performFiltering(CharSequence constraint) {
  60:             FilterResults oReturn = new FilterResults();
  61:             ArrayList<Game> results = new ArrayList<Game>();
  62:             if (orig == null)
  63:                 orig = games;
  64:             
  65:             if (constraint != null)
  66:             {
  67:                 if (orig != null && orig.size() > 0) {
  68:                     for (Game g : orig) {
  69:                         if (g.getName().contains(constraint))
  70:                             results.add(g);
  71:                     }
  72:                 }
  73:                 oReturn.values = results;
  74:             }
  75:             return oReturn;
  76:         }
  77:  
  78:         @SuppressWarnings("unchecked")
  79:         @Override
  80:         protected void publishResults(CharSequence constraint, FilterResults results) {
  81:             games = (ArrayList<Game>)results.values;
  82:             notifyDataSetChanged();
  83:         }
  84:     }
  85:  
  86: }

Here is how to set the Adapter.

   1: public class ScoreKeeper extends Activity {
   2:  
   3:     ArrayList<Game> games;
   4:     AutoCompleteTextView txtGames;
   5:     GameAdapter myAdapter;
   6:     
   7:     /** Called when the activity is first created. */
   8:     @Override
   9:     public void onCreate(Bundle savedInstanceState) {
  10:         super.onCreate(savedInstanceState);
  11:         setContentView(R.layout.main);
  12:         
  13:         txtGames = (AutoCompleteTextView)findViewById(R.id.txtGames);
  14:        
  15:         games = getAllGames();
  16:  
  17:         myAdapter = new GameAdapter(this, games);
  18:         txtGames.setAdapter(myAdapter);
  19:     }
  20: }

If you run this the AutoComplete list will now look like the list from the previous example. I had hoped to be able to use the same list for both a ListView and an AutoComplete but was unable to do so. The ListView’s items would be narrowed down as I typed into the AutoComplete box. I can’t think of any way to do this of the top of my head but it would be cool to be able to use the same adapter for two different things. I would be very interested if anyone else has done this or has any ideas on how to do it. I will definitely post a follow up if I am able to do so.

author: John Nastase | posted @ Sunday, December 19, 2010 10:38 PM | Feedback (10)

Custom Android ListAdapter


This article  will explain how to make a custom adapter for a ListView used to display a list of items. For those of you not familiar with how to bind a ListView to a list of items here is a brief overview. First you need an ArrayList of a certain type and an ArrayAdapter of the same type. In the constructor of the ArrayAdapter you pass in the context, a layout id and the ArrayList of the same type and set the lists adapter to the ArayAdapter. This simply displays a list calling toString() on every item which means you have to override toString()  on your type or the objects memory reference will be displayed.

This approach is good for displaying a simple list but what if we wanted to display the name and number of a contact or just two pieces of data from the same type in each list item. For those of you familiar with Asp.Net and the GridView we could just put binding tags in our markup but that isn’t the case with Android. To start we need to make a class the extends the BaseAdapter class and override a few methods. For this example we will be displaying a list of games. We will just be displaying the game id and its name.

The first thing we need to do is create the View we will be using in the adapter. For this will we be creating a simple class that extends LinearLayout that contains two TextViews for our display. This class is very simple, it contain two TextViews with methods to set their text and a constructor that defines the layout of the items. In the constructor all we do is instantiate the TextViews and set their text. Here is the View class.

   1: public class GameView extends LinearLayout {
   2:  
   3:     TextView txtName;
   4:     TextView txtID;
   5:     
   6:     public GameView(Context context, Game game) {
   7:         super(context);
   8:         this.setOrientation(VERTICAL);
   9:         
  10:         txtName = new TextView(context);
  11:         txtID = new TextView(context);
  12:         
  13:         txtID.setText(String.valueOf(game.getID()));
  14:         txtName.setText(game.getName());
  15:         
  16:         addView(txtID, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
  17:         addView(txtName, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
  18:     }
  19:     
  20:     public void setID(long value) { txtID.setText(String.valueOf(value)); }
  21:     public void setName(String value) { txtName.setText(value); }
  22:  
  23: }

 

Next we need to make our class that overrides the BaseAdapter class. Here is the start of our class and the methods we need.

   1: public class GameAdapter extends BaseAdapter {
   2:     
   3:     @Override
   4:     public int getCount() {
   5:             return 0;
   6:     }
   7:  
   8:     @Override
   9:     public Object getItem(int arg0) {
  10:         return 0;
  11:     }
  12:  
  13:     @Override
  14:     public long getItemId(int arg0) {
  15:         return 0
  16:     }
  17:  
  18:     @Override
  19:     public View getView(int arg0, View arg1, ViewGroup arg2) {
  20:         
  21:     }
  22: }

 

The first thing we need to do is create a constructor. We will pass in the context and a list of games to be used by the Adapter.

   1: Context _context;
   2: ArrayList<Game> games;
   3:  
   4: public GameAdapter(Context context, ArrayList<Game> _games) {
   5:     _context = context;
   6:     games = _games;
   7: }

 

Now that we have all the data we need we just need to fill in the methods we overrode. The most important one is getView which will instantiate an instance of our custom view class and assign it the appropriate values. The other three methods are used to get the current item or count of items. Again we are doing nothing special other than creating a view and assigning its values. Here is the complete code for the Adapter class.

   1: public class GameAdapter extends BaseAdapter {
   2:  
   3:     Context _context;
   4:     ArrayList<Game> games;
   5:     
   6:     public GameAdapter(Context context, ArrayList<Game> _games) {
   7:         _context = context;
   8:         games = _games;
   9:     }
  10:     
  11:     @Override
  12:     public int getCount() {
  13:         if (games != null)
  14:             return games.size();
  15:         else
  16:             return 0;
  17:     }
  18:  
  19:     @Override
  20:     public Object getItem(int arg0) {
  21:         return games.get(arg0);
  22:     }
  23:  
  24:     @Override
  25:     public long getItemId(int arg0) {
  26:         return games.get(arg0).getID();
  27:     }
  28:  
  29:     @Override
  30:     public View getView(int arg0, View arg1, ViewGroup arg2) {
  31:         GameView gv;
  32:         if (arg1 == null)
  33:             gv = new GameView(_context, games.get(arg0));
  34:         else {
  35:             gv = (GameView) arg1;
  36:             gv.setID(games.get(arg0).getID());
  37:             gv.setName(games.get(arg0).getName());
  38:         }
  39:         return gv;
  40:     }
  41: }

 

To use this in an activity simply crate a ListView, the custom adapter and set the ListView’s adapter to our custom adapter and see the results. Here is some code to get you going.

   1: public class ScoreKeeper extends Activity {
   2:  
   3:     ArrayList<Game> games;
   4:     GameAdapter myAdapter;
   5:     
   6:     /** Called when the activity is first created. */
   7:     @Override
   8:     public void onCreate(Bundle savedInstanceState) {
   9:         super.onCreate(savedInstanceState);
  10:         setContentView(R.layout.main);
  11:  
  12:         lstGames = (ListView)findViewById(R.id.lstGames);
  13:         
  14:         games = db.getAllGames();
  15:  
  16:         myAdapter = new GameAdapter(this, games);
  17:         lstGames.setAdapter(myAdapter);
  18:     }
  19: }

 

That’s all there is to it. I know this is pretty much the android’s example minus putting creating your own ListView class but I wanted to show how to do this since it will lead into my next post on creating your own Adapter for handling AutoCompletes in android. Plus it shows you can use the default ListView rather than creating your own. Hope you will find this useful.

author: John Nastase | posted @ Sunday, December 19, 2010 10:03 PM | Feedback (13)