Friday, September 23, 2011

SuperSQLiteOpenHelper

Every Android developer has to work with databases at some point.  And every time, each developer has to go through the motions of not just designing the database schema, but setting up the SQLiteOpenHelper to make it work with your application.  Every time, developers need to create the same functions to create, upgrade, and interface to the database.  There are plenty of libraries out there that do import and export but most of them require custom code each time as well.  After one or two databases implementations, I kinda got tired of it (I know, I'm really impatient).  I wanted to know why some of this stuff was easier to do.  I set out to make it so.

Introducing SuperSQLiteOpenHelperhttp://code.google.com/p/supersqliteopenhelper/

Using this library, the developer no longer needs to remake code.  The library supports automatic creation, upgrade, and even downgrade of the database.  Any database can be imported from and exported a file or a DOM element that can be included in an application-wide import/export.  A few other database tools allow the user to focus on the one thing that makes a database so useful: the schema.

With SuperSQLiteOpenHelper, developers only need to create a schema and whatever custom interface methods they need in their application.  The schema is saved in an easy to understand format and can handle versioning automatically. Table-wide constraints can also be added to make each table more intelligent.

I welcome all Android developers to come take a look at the library.  Check out the code, download the library, try it out, and let me know what you think.  Anyone interested in helping me test, let me know.  I want to make this library as powerful and as helpful as I can.  If there are any more functions or ideas out there of what to add, comment here or on the Google Code site.

Thanks to all for any future input and happy coding!

Friday, April 8, 2011

IWST v1.4: This weekend

Version 1.4 is ready for release this weekend but I am trying to roll in a few bug fixes.  Spring finally decided to show up so I've been busy with yard work and tiling my fireplace so I apologize.  Otherwise I could have had the new version out earlier this week.  I will elaborate on the new updates but I'm at my real job right now, shhhh.

Update: As promised, I am about to get a new screen shot and upload the new version.  The new updates include sorting capabilities based on release date, rating, or movie name (ascending or descending as well).  These are found in preferences and only affect the home screen.  At this point, I am expecting the sort coming from thdb.org to have a better relevance sorting (even if that relevance seems elusive at times).  I also added view selections on the home screen.  You can now select a drop-down icon and view all movies, watched movies, or unwatched movies.  In your preferences, you can also select which one will open by default.  I also address every single error I had seen in my error log.  A lot of them were being caught already but it should make some things more graceful.

Another Update:  So far I have seen a single error come in from the new version.  I have only seen it 5 times total from 2 different people.  It happens on the home screen and has something to do with the movie poster.  Oddly, it doesn't happen when searching for the movie or looking at its information, just when you get back to the home screen.  I have done my darnedest to replicate the error but can't seem to do it.  Deleting files in the background, loading a few dozen movies into my list, etc.  If anyone comes across an error, it would help if you let me know via email or reply to this post.  Please include the movie(s) you had in your list and generally what you were doing when it happened.  I'd also like to know if it happens every time you open the application (if it goes away if you close and reopen).  Thanks in advance to anyone that is able to help.

Friday, March 25, 2011

Complete Custom List Example

Listviews are a very useful part of Android applications.  However, they are much more useful when you create a custom listview.  With a custom listview, you can extend all the standard classes to very easily show more complex information in a simple way.  In creating my application, I combined several bits of code from many different places from the web to get my listview to act the way I wanted.  I thought there might be a few people out there that might find this stuff helpful so I figured I'd share a simple example I came up with.

My example will show a list of countries.  If you click on them, it will tell you the capitol.  If you long click, it will give a few simple options.  This is obviously not that useful and overly complicated but it provides a good framework for more complex implementations.

First, I created a custom Countries class to hold each object.
1:  public class Country {  
2:       public String name;  
3:       public String capitol;  
4:  }  
Code Block 1

Well that was pretty simple.  Next, create your activity and some global variables.
1:  public class CustomListSuperDemo extends Activity {  
2:       private final String[] countryList = {  
3:            "Afghanistan:Kabul",  
4:            ...  
5:            "United States:Washington D.C.",  
6:            ...  
7:            "Zimbabwe:Harare"  
8:       };  
9:       private static List<Country> myCountries = new LinkedList<Country>();  
10:       private MovieAdapter myAdapter;  
11:       private int selectedMovieIndex;  
12:       private static final int MENU_UPP = 0;  
13:       private static final int MENU_LOW = 1;  
Code Block 2

The countryList will be used later to create all the Country objects, which are held in the myCountries list.  You can get the full list from the full code.  Everything else are used for saving information when the user clicks a list item.  Next I define the behavior or the listview adapter.
1:       private static class MovieAdapter extends BaseAdapter {  
2:            private final LayoutInflater mInflater;  
3:            public MovieAdapter(Context context) {  
4:                 mInflater = LayoutInflater.from(context);  
5:            }  
6:            public int getCount() {  
7:                 return myCountries.size();  
8:            }  
9:            public Object getItem(int position) {  
10:                 return position;  
11:            }  
12:            public long getItemId(int position) {  
13:                 return position;  
14:            }  
15:            public View getView(int position, View convertView, ViewGroup parent) {  
16:                 ViewHolder holder;  
17:                 if (convertView == null) {  
18:                      convertView = mInflater.inflate(R.layout.listitem, null);  
19:                      holder = new ViewHolder();  
20:                 } else {  
21:                      holder = (ViewHolder) convertView.getTag();  
22:                 }  
23:                 holder.name = (TextView) convertView  
24:                      .findViewById(R.id.name);  
25:                 convertView.setTag(holder);  
26:                 holder.name.setText( myCountries.get(position).name );  
27:                 return convertView;  
28:            }  
29:            static class ViewHolder {  
30:                 TextView name;  
31:            }  
32:       }  
Code Block 3

Most of that is pretty simple but the getView function is where it gets fun.  This function is used to map your list of objects to individual views (what the user sees).  You can move lines 23-24 into the if statement (after line 19).  Be careful with this though.  I had an issue when doing this with an imageView because these are cached differently.  You can randomly get images show up in the wrong list item.  I just like my stuff like I show above just to be on the safe side.

Next I set up the UI and load the list.
1:       public void onCreate(Bundle savedInstanceState){  
2:            super.onCreate(savedInstanceState);  
3:            setContentView(R.layout.main);  
4:            new loadList().execute();  
5:    }  
6:       class loadList extends AsyncTask<Void, Movie, Void> {  
7:            ProgressDialog dialog;  
8:            protected void onPreExecute(){  
9:                 dialog = ProgressDialog.show(CustomListSuperDemo.this, "",  
10:                           "Loading. Please wait...", true);  
11:            }  
12:            protected Void doInBackground(Void... unused) {  
13:                 Arrays.sort( countryList );  
14:                 for( int i=0; i< countryList.length; ++i){  
15:                      //add it to the country list  
16:                      Country newCountry = new Country();  
17:                      newCountry.name = countryList[i].split(":")[0];  
18:                      newCountry.capitol = countryList[i].split(":")[1];  
19:                      myCountries.add(newCountry);  
20:                 }  
21:                 return(null);  
22:            }  
23:            protected void onPostExecute(Void unused){  
24:                 if( myCountries.size() == 0 ){  
25:                      ((TextView)findViewById(R.id.empty)).setVisibility(View.VISIBLE);  
26:                 }else{  
27:                      ((TextView)findViewById(R.id.empty)).setVisibility(View.GONE);  
28:                      ListView lv = (ListView) findViewById(R.id.movieList);  
29:                      lv.setAdapter(new MovieAdapter(CustomListSuperDemo.this));  
30:                      lv.setDivider(new ColorDrawable(Color.DKGRAY));  
31:                      lv.setDividerHeight(2);  
32:                      lv.setOnItemClickListener(new AdapterView.OnItemClickListener(){  
33:                           public void onItemClick(AdapterView<?> av, View v, int pos, long id){  
34:                                Toast.makeText(CustomListSuperDemo.this,  
35:                                     myCountries.get(pos).capitol + " is my capitol.", Toast.LENGTH_SHORT).show();  
36:                           }  
37:                      });  
38:                      lv.setOnCreateContextMenuListener(new OnCreateContextMenuListener(){  
39:                           public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo){  
40:                             AdapterView.AdapterContextMenuInfo info =  
41:                               (AdapterView.AdapterContextMenuInfo) menuInfo;  
42:                             selectedMovieIndex = info.position;  
43:                             menu.setHeaderTitle("Options");  
44:                             menu.add(0, MENU_UPP, 0, "To Upper");  
45:                             menu.add(0, MENU_LOW, 0, "To Lower");  
46:                           }  
47:                      });  
48:                      myAdapter = (MovieAdapter)lv.getAdapter();  
49:                 }  
50:                 try{  
51:                      dialog.dismiss();  
52:                 }catch(Exception e){}  
53:            }  
54:       }  
Code Block 4

In onCreate, I load the UI and call an instance of AsyncTask to load the data.  This is useful when object data takes a while to load (load from database or download from web).  Once this is done, I set up the display and add the click events.  This is where I use the two MENU constants.  When the user longClicks, they are used to create the buttons.  These are also use one more time below.  I also save a reference to myAdapter and the selected position to make things easier later on.

Only one bit of code left: processing the long click.
1:       public boolean onContextItemSelected(MenuItem item) {  
2:            new processClick().execute(item.getItemId());  
3:            return true;  
4:       }  
5:       class processClick extends AsyncTask<Integer, Void, Void> {  
6:            ProgressDialog dialog;  
7:            protected void onPreExecute(){  
8:                 dialog = ProgressDialog.show(CustomListSuperDemo.this, "",  
9:                           "Loading. Please wait...", true);  
10:            }  
11:            protected Void doInBackground(Integer... tmpbtnID){  
12:                 try {  
13:                      Thread.sleep(1000);  
14:                 } catch (InterruptedException e){  
15:                      e.printStackTrace();  
16:                 }  
17:                 switch(tmpbtnID[0]){  
18:                 case MENU_UPP:  
19:                      myCountries.get(selectedMovieIndex).name =  
20:                           myCountries.get(selectedMovieIndex).name.toUpperCase();  
21:                      break;  
22:                 case MENU_LOW:  
23:                      myCountries.get(selectedMovieIndex).name =  
24:                           myCountries.get(selectedMovieIndex).name.toLowerCase();  
25:                      break;  
26:                 }  
27:                 return(null);  
28:            }  
29:            protected void onPostExecute(Void unused){  
30:                 myAdapter.notifyDataSetChanged();  
31:                 dialog.dismiss();  
32:            }  
33:       }  
Code Block 5

I process the click in another AsyncTask because some actions may take a while.  Once I'm all done, I notify the saved adapter that it should update.

If anyone needs something explained a little more, just let me know.  You can get the full code here: Custom ListView Example.zip

Sunday, March 20, 2011

I Wanna See That: v1.3 coming soon

I am working on one last function for v1.3.  Keep an eye out for it to hit the market tomorrow.  Updates in version 1.3 include:

  1. Ability to check off (watch) movies
  2. Update movie info
You can now long-click a movie from the home screen to get new options.

In the next few versions, I will be adding user preferences including sorting capability based on release date, alphabetical, or rating.  I also want to add the capability to view movie lists such as watched, unwatched, or all.  I will also try to take care of some of the random errors I see come in via error reports.  I think things should get pretty interesting in the coming weeks.

On a side note, I am still seeing some error come in from version 1.0, which any user that jumped on board that early knows, didn't work at all.  I think I got another 1 star review because of this.  I'm not sure how people are still getting it but please make sure you are on the most current version before commenting that it doesn't work.  As always, if you notice any error please let me know and I will work to resolve them.

Sunday, March 13, 2011

My first android app: I Wanna See That

Alpha version released to Android Market.
Get it here: market.android.com/details?id=com.I_Wanna_See_That
Or scan this:

This app is for every person who sees a movie preview and says "Hey, that looks good.  I want to see it."  Just open the app, search for the movie, and add it to your to-watch list.  It doesn't have to be a new release.  You can also manage a list of movies that you would like to catch up on.  This is the only app on the market now specifically designed to keep track of a to-watch list.

This is an alpha version of the app.  It is not very pretty yet and not all functionality is ready.  It is mostly for testing.

Thanks to those who try it out and help me test.

For the alpha version only basic functionality is added: view saved movies, search for new movies, and view movie info.

Here are some ideas I have been working on and would like to eventually add to the app:

  1. The ability to check movies off in the list
  2. Come up with a good-looking theme for the app (or several and let the user pick)
  3. Update movie info if it was incomplete when the user saved it
  4. Several movie lists managed by user (ie Romantic, With Kids, Action, etc)
  5. Alerts every week for movies coming out
  6. View local movie times (and maybe even buy tickets)
Feel free to make your own suggestions and help make the app better.

Saturday, March 5, 2011

Intro

This blog is dedicated to the many DIY projects I start and sometimes finish in my own free time.  Projects are usually technology related but also include home improvement.

These are some of my past projects:

  • Set up a home web server with Railo and Postgres.
  • Custom circuit design and pcb population
  • Home automation
  • Installing wood floors
  • Tiling and countertops
As you can see, the projects cover a wide range.  I will be using this blog to record some of what I do for my projects.  If I revisit any of my past projects, I will try my best to write down what I've done but feel free to ask any questions about them and I'll try to answer.  Otherwise, I'll just write about whatever project I'm doing at the time.

Some of the stuff you will be seeing in the near future
  • Android applications
    • How to get started
    • How to get it out there for people to download/buy
    • How to add ads to your applications
  • Designing and installing a yard shed
More coming soon!