com.manning.androidhacks.hack041.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.manning.androidhacks.hack041.MainActivity.java

Source

/*
50AH-code
=========
    
50 Android Hacks (http://manning.com/sessa/) book source code
    
    
Copyright (c) 2012 Manning
    
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
    
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
    
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
    
    
*/

/*******************************************************************************
 * Copyright (c) 2012 Manning
 * See the file license.txt for copying permission.
 ******************************************************************************/
package com.manning.androidhacks.hack041;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.j256.ormlite.dao.Dao;
import com.manning.androidhacks.hack041.data.Article;
import com.manning.androidhacks.hack041.data.ArticleAuthor;
import com.manning.androidhacks.hack041.data.ArticleCategory;
import com.manning.androidhacks.hack041.data.Author;
import com.manning.androidhacks.hack041.data.Category;
import com.manning.androidhacks.hack041.data.DatabaseHelper;

/**
 * This activity will be a ListView of Categories, and any Articles that belong
 * to the Category. The purpose of this activity is to demo inserting data, as
 * well as performing queries using OrmLite.
 */
public class MainActivity extends Activity {
    private LoadArticleListTask task;
    private ProgressDialog dialog;
    private ListView listView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        listView = (ListView) findViewById(R.id.listView);

        dialog = ProgressDialog.show(this, null, "Loading Articles", true, false);
        /*
         * Kick off a task (if needed) to load the data for this activity. Note: We
         * must be mindful of screen orientation changes here.
         */
        task = (LoadArticleListTask) getLastNonConfigurationInstance();
        if (task == null) {
            task = new LoadArticleListTask(this);
            task.execute();
        } else {
            task.attach(this);
        }

    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        task.detach();
        return task;
    }

    public void handleDataLoaded(ArticleListModel model) {
        listView.setAdapter(new MainAdapter(model));
        dialog.dismiss();
    }

    private class MainAdapter extends BaseAdapter {
        private final static int TYPE_CATEGORY = 0, TYPE_ARTICLE = 1;

        private ArticleListModel model;
        private LayoutInflater inflater;
        SimpleDateFormat formatter = new SimpleDateFormat("'Created on' M/d/yyyy h:mm a");

        View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Article article = (Article) view.getTag();
                MainActivity.this.startActivity(new Intent(MainActivity.this, ArticleActivity.class)
                        .putExtra(ArticleActivity.ARTICLE_ID, article.getId()));
            }
        };

        private MainAdapter(ArticleListModel model) {
            this.model = model;
            inflater = LayoutInflater.from(MainActivity.this);
        }

        @Override
        public int getCount() {
            return model.flattenedItems.size();
        }

        @Override
        public Object getItem(int i) {
            return model.flattenedItems.get(i);
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public int getViewTypeCount() {
            return 2; // We want to show some category separators in the
                      // ListView;
        }

        @Override
        public int getItemViewType(int position) {
            Object item = getItem(position);
            return item instanceof CategoryModel ? TYPE_CATEGORY : TYPE_ARTICLE;
        }

        @Override
        public boolean isEnabled(int position) {
            return getItemViewType(position) == TYPE_ARTICLE;
        }

        @Override
        public View getView(int position, View view, ViewGroup viewGroup) {
            Object item = getItem(position);
            int itemViewType = getItemViewType(position);

            // Here we inflate/fill out the correct view based off the type of
            // the item we're processing.
            if (itemViewType == TYPE_CATEGORY) {
                CategoryModel model = (CategoryModel) item;
                if (view == null)
                    view = inflater.inflate(R.layout.list_category, null);
                // Just fill out the display text for a CategoryModel
                ((TextView) view).setText(model.getText());
            } else {
                Article article = (Article) item;
                if (view == null)
                    view = inflater.inflate(R.layout.list_item, null);
                // This demo will just show a title and created on date for
                // articles.
                ((TextView) view.findViewById(R.id.list_complex_title)).setText(article.getTitle());
                ((TextView) view.findViewById(R.id.list_complex_caption))
                        .setText(formatter.format(article.getPublishedDate()));
                // Hook up a click listener
                view.setTag(article);
                view.setOnClickListener(listener);
            }

            return view;
        }
    }

    private static class ArticleListModel {
        List<Object> flattenedItems = new ArrayList<Object>();
    }

    /**
     * A helper class for formatting our output in this Activity's ListView.
     */
    private static class CategoryModel implements Comparable<CategoryModel> {
        Category category;
        List<Article> articleList = new ArrayList<Article>();

        private CategoryModel(Category category) {
            if (category == null)
                throw new IllegalArgumentException("Passed in category must be non-null!");
            this.category = category;
        }

        public Integer getId() {
            return category.getId();
        }

        public String getText() {
            return category.formatFullName();
        }

        public void addArticle(Article a) {
            articleList.add(a);
        }

        @Override
        public int compareTo(CategoryModel that) {
            return this.category.formatFullName().compareToIgnoreCase(that.category.formatFullName());
        }
    }

    private static class LoadArticleListTask extends AsyncTask<Void, Void, ArticleListModel> {
        private MainActivity host;
        private ArticleListModel payload;
        private boolean done;

        private LoadArticleListTask(MainActivity host) {
            this.host = host;
        }

        @Override
        protected ArticleListModel doInBackground(Void... voids) {
            final DatabaseHelper helper = DatabaseHelper.getInstance(host);
            return helper.callInTransaction(new Callable<ArticleListModel>() {
                @Override
                public ArticleListModel call() throws SQLException {
                    Dao<Article, Integer> articleDao = helper.getArticleDao();
                    // Check if we need to insert our sample data.
                    if (articleDao.countOf() == 0)
                        insertSampleData(helper);

                    /*
                     * This activity will display all categories and articles. So, we will
                     * query the cross reference table, and use the ORM to fill in our
                     * data objects.
                     */
                    Dao<ArticleCategory, Void> articleCategoryDao = helper.getArticleCategoryDao();
                    Map<Integer, CategoryModel> allCategories = new HashMap<Integer, CategoryModel>();
                    for (ArticleCategory mapping : articleCategoryDao.queryForAll()) {
                        // Build a unique set of Categories from the
                        // data that was returned.
                        CategoryModel model = new CategoryModel(mapping.getCategory());
                        Integer key = model.getId();

                        if (allCategories.containsKey(key))
                            allCategories.get(key).addArticle(mapping.getArticle());
                        else {
                            model.addArticle(mapping.getArticle());
                            allCategories.put(key, model);
                        }
                    }

                    // Sort the categories, and return the data.
                    List<CategoryModel> sorted = new ArrayList<CategoryModel>(allCategories.values());
                    Collections.sort(sorted);

                    ArticleListModel returnValue = new ArticleListModel();
                    for (CategoryModel categoryModel : sorted) {
                        returnValue.flattenedItems.add(categoryModel);
                        returnValue.flattenedItems.addAll(categoryModel.articleList);
                    }

                    return returnValue;
                }
            });
        }

        /**
         * Called for the first run of the application (or when all Articles have
         * been deleted).
         * 
         * @param helper
         *          An instance of our DatabaseHelper.
         * @throws SQLException
         */
        private void insertSampleData(DatabaseHelper helper) throws SQLException {
            final int SAMPLE_COUNT = 50;
            final String SAMPLE_ARTICLE_TEXT = "Nulla nec neque sit amet libero molestie commodo sit amet quis diam. In non sapien enim. Mauris quis ipsum nec ipsum faucibus pretium sit amet blandit sapien. Nam ut magna et nisi molestie adipiscing sed eget justo. In fringilla risus in felis posuere placerat. Aenean quis orci mollis libero pellentesque euismod a nec mauris. Fusce tempus velit ut nisi lobortis congue! Pellentesque adipiscing metus luctus felis venenatis scelerisque? Praesent rhoncus iaculis nulla et sollicitudin. Proin placerat, ante vel varius vehicula, augue est cursus est, sed tristique orci quam ac massa? Mauris sodales tincidunt nibh, a sollicitudin magna volutpat vitae. Sed vitae ligula vel nibh imperdiet accumsan eu nec ipsum. Quisque laoreet, elit id dictum mollis, elit justo facilisis risus, ac interdum leo mi nec tortor.\n"
                    + "\n"
                    + "Aliquam tincidunt dapibus ipsum, sit amet varius sapien imperdiet pellentesque. Nulla vel eros est. Cras eu tellus et ipsum malesuada fermentum! Curabitur ac ipsum nec est fermentum ultrices at in felis. Pellentesque pellentesque nisi quis eros viverra porta! Integer in ipsum nulla, eu feugiat turpis. Donec pretium, urna dignissim aliquam convallis; ante nisl porttitor orci, eget eleifend tellus nisi a libero!";
            Author[] authors = new Author[] { new Author("First Author", "first@example.com"),
                    new Author("Second Author", "second@example.com"),
                    new Author("Third Author", "third@example.com") };
            Category[] topCategories = new Category[] { new Category("Android Layouts", null),
                    new Category("Databases", null), new Category("Network Communication", null),
                    new Category("Screen Rotation", null), new Category("Threading", null) };
            Category[] subCategories = new Category[] { new Category("SQL", topCategories[1]) };

            // We will need a few DAO objects from our OrmLiteSqliteOpenHelper
            // instance
            Dao<Author, Integer> authorDao = helper.getAuthorDao();
            Dao<Category, Integer> categoryDao = helper.getCategoryDao();
            Dao<Article, Integer> articleDao = helper.getArticleDao();
            Dao<ArticleAuthor, Void> articleAuthorDao = helper.getArticleAuthorDao();
            Dao<ArticleCategory, Void> articleCategoryDao = helper.getArticleCategoryDao();

            // Insert all of our sample authors. The DAO will set the database
            // generated ID, which we will need later.
            for (Author author : authors)
                authorDao.create(author);

            // Insert all sample categories
            for (Category category : topCategories)
                categoryDao.create(category);
            for (Category category : subCategories)
                categoryDao.create(category);

            for (int i = 0; i < SAMPLE_COUNT; i++) {
                // Make a new Article instance, and call create() on the DAO.
                // That call will set the ID of the object.
                Article article = new Article(new Date(), SAMPLE_ARTICLE_TEXT, "Article " + i);
                articleDao.create(article);

                // Insert cross reference(s) to set the author(s) of this
                // article
                if (i == 0) {
                    // Let's make the first article have many authors.
                    for (Author author : authors)
                        articleAuthorDao.create(new ArticleAuthor(author, article));
                } else {
                    // Otherwise, we'll assign a single author to the article.
                    Author author = authors[i % authors.length];
                    articleAuthorDao.create(new ArticleAuthor(author, article));
                }

                // Insert another cross reference to set categories for this
                // article.
                if (i == 15) {
                    // For some diversity, we will put this article in a sub
                    // category
                    articleCategoryDao.create(new ArticleCategory(article, subCategories[0]));
                } else {
                    int catIndex = i / (SAMPLE_COUNT / topCategories.length);
                    Category category = topCategories[catIndex];
                    articleCategoryDao.create(new ArticleCategory(article, category));
                }
            }
        }

        @Override
        protected void onPostExecute(ArticleListModel articleListModel) {
            done = true;
            payload = articleListModel;
            host.handleDataLoaded(articleListModel);
        }

        public void detach() {
            host = null;
        }

        public void attach(MainActivity newActivity) {
            host = newActivity;
            if (done)
                host.handleDataLoaded(payload);
        }
    }
}