Android. Lection 4

ListView and SQLite

Expected result

Navigating through activities

Top level activities

These are the activities your user will encounter first, so they go at the top. 

Category activities

Your users will navigate from the top-level activity to the category activities. In complex apps, you might have several layers of categories and subcategories. 

Details/Edit activities

These form the bottom layer of the activity hierarchy. Users will navigate to these from the category activities. 

Structure

Steps

  1. Add the Drink class and image resources
  2. Create MainActivity and it's layout
  3. Create DrinkCategoryActivity
  4. Create DrinkActivity and it's layout
public class Drink {
    private String name;
    private String description;
    private int imageResId;

    public Drink(String name, String description, int imageResId) {
        this.name = name;
        this.description = description;
        this.imageResId = imageResId;
    }


    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public int getImageResId() {
        return imageResId;
    }

    @Override
    public String toString() {
        return name;
    }
}

​Drink

Structure

Resources

<resources>
    <string name="app_name">Recipes</string>

    <string-array name="main_activity_menu">
        <item>Drinks</item>
        <item>Food</item>
        <item>Stores</item>
    </string-array>
</resources>
<resources>
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="title_size">100dp</dimen>
    <dimen name="image_size_default">150dp</dimen>
</resources>

dimens.xml

strings.xml

MainActivity layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.cadacademy.sutula.lection4.MainActivity">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="@dimen/title_size"
        android:id="@+id/imageView"
        android:src="@drawable/title_logo"
        android:longClickable="false" />

    <ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/listView"
        android:entries="@array/main_activity_menu"/>
</LinearLayout>

ListView

OnItemClickListener

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent,
                                    View view,
                                    int position,
                                    long id) {
                switch (position) {
                    case 0:
                        Intent intent
                                = new Intent(MainActivity.this, DrinkCategoryActivity.class);
                        startActivity(intent);
                        break;
                    default:
                        break;
                }
            }
        });

Butter Knife

class ExampleActivity extends Activity {
  @Bind(R.id.title) TextView title;
  @Bind(R.id.subtitle) TextView subtitle;
  @Bind(R.id.footer) TextView footer;

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.simple_activity);
    ButterKnife.bind(this);
    // TODO Use fields...
  }
}
public void bind(ExampleActivity activity) {
  activity.subtitle = (android.widget.TextView) activity.findViewById(2130968578);
  activity.footer = (android.widget.TextView) activity.findViewById(2130968579);
  activity.title = (android.widget.TextView) activity.findViewById(2130968577);
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.jakewharton:butterknife:7.0.1'
}

How to install

MainActivity.java

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

import butterknife.Bind;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.listView) ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent,
                                    View view,
                                    int position,
                                    long id) {
                switch (position) {
                    case 0:
                        Intent intent
                                = new Intent(MainActivity.this, DrinkCategoryActivity.class);
                        startActivity(intent);
                        break;
                    default:
                        break;
                }
            }
        });
    }
}

ListActivity

A list activity is type of activity that specializes in working with a list. It’s automatically bound to a list view, so you don’t need to create one yourself. Here’s what one looks like: 

For nonstatic data, use an adapter 

If you need to display data in a list view that comes from a nonstatic source such as a Java array or database, you need to use an adapter. An adapter acts as a bridge between the data source and the list view: 

How to use

Drink[] drinks = {
            new Drink("Bloody Mary", "Bloody Mary desc", R.drawable.blood_marry),
            new Drink("Sazerac", "Sazerac drink", R.drawable.sazarac),
            new Drink("B52", "B52 drink", R.drawable.b52),
            new Drink("Cider", "Cider drink", R.drawable.sydr)
    };

ArrayAdapter<Drink> listAdapter = new ArrayAdapter<Drink>(this,
        android.R.layout.simple_expandable_list_item_1,
        drinks);

ListView listView = getListView();
listView.setAdapter(listAdapter);

What happens

OnListItemClick

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    Intent intent = new Intent(this, DrinkActivity.class);
    intent.putExtra(DrinkActivity.DRINK_NO, (int) id);
    startActivity(intent);
}

DrinkCategoryActivity

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class DrinkCategoryActivity extends ListActivity {

    public final static Drink[] drinks = {
            new Drink("Bloody Mary", "Bloody Mary desc", R.drawable.blood_marry),
            new Drink("Sazerac", "Sazerac drink", R.drawable.sazarac),
            new Drink("B52", "B52 drink", R.drawable.b52),
            new Drink("Cider", "Cider drink", R.drawable.sydr)
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ArrayAdapter<Drink> listAdapter = new ArrayAdapter<Drink>(this,
                android.R.layout.simple_expandable_list_item_1,
                drinks);

        ListView listView = getListView();
        listView.setAdapter(listAdapter);
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        Intent intent = new Intent(this, DrinkActivity.class);
        intent.putExtra(DrinkActivity.DRINK_NO, (int) id);
        startActivity(intent);
    }
}

Drink layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.cadacademy.sutula.lection4.DrinkActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/tvTitle"
        android:layout_gravity="center_horizontal" />

    <ImageView
        android:layout_width="@dimen/image_size_default"
        android:layout_height="@dimen/image_size_default"
        android:id="@+id/photo"
        android:layout_gravity="center_horizontal" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:id="@+id/tvDescription"
        android:layout_gravity="center_horizontal" />
</LinearLayout>

DrinkActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;

import butterknife.Bind;
import butterknife.ButterKnife;

public class DrinkActivity extends AppCompatActivity {

    public final static String DRINK_NO = "DRINK_NO";

    @Bind(R.id.tvTitle)         TextView tvTitle;
    @Bind(R.id.photo)           ImageView ivPhoto;
    @Bind(R.id.tvDescription)   TextView tvDesc;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drink);
        ButterKnife.bind(this);

        int drinkNo = getIntent().getIntExtra(DRINK_NO, -1);
        if (drinkNo != -1) {
            Drink drink = DrinkCategoryActivity.drinks[drinkNo];
            tvTitle.setText(drink.getName());
            ivPhoto.setImageResource(drink.getImageResId());
            tvDesc.setText(drink.getDescription());
        }
    }
}

Database

SQLite

Where database stored

Create SQLite Helper

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class RecipeDatabaseHelper extends SQLiteOpenHelper{

    private static final String DB_NAME = "recipe";
    private static final int DB_VERSION = 1;

    public RecipeDatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

Inside Database

Datatypes

Create Table

Insert data using insert() method

ContentValues drinkValues = new ContentValues();
drinkValues.put("NAME", "Sazerac");
drinkValues.put("DESCRIPTION", "Sazerac descr drink");
drinkValues.put("IMAGE_RESOURCE_ID", R.drawable.sazarac);

db.insert("DRINK", null, drinkValues);
_id NAME DESCRIPTION IMAGE_RESOURCE_ID
1 Sazerac Sazerac descr drink 54545453

Update()

public int update (String table, ContentValues values,
                   String whereClause, String[] whereArgs)
ContentValues testValue = new ContentValues();
testValue.put("DESCRIPTION", "Very tasty");
db.update("DRINK", testValue, "_id = ?", new String[]{"1"});
_id NAME DESCRIPTION IMAGE_RESOURCES_ID
1 Sazerac Sazerac descr drink
Very tasty
54545453

Full code of Helper

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class RecipeDatabaseHelper extends SQLiteOpenHelper{

    private static final String DB_NAME = "recipe";
    private static final int DB_VERSION = 1;

    public RecipeDatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE DRINK ("
                + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
                + "NAME TEXT, "
                + "DESCRIPTION TEXT, "
                + "IMAGE_RESOURCE_ID INTEGER);");
        
        insertDrink(db, "Bloody Mary", "Bloody Mary desc", R.drawable.blood_marry);
        insertDrink(db, "Sazerac", "Sazerac drink", R.drawable.sazarac);
        insertDrink(db,"B52", "B52 drink", R.drawable.b52);
        insertDrink(db,"Cider", "Cider drink", R.drawable.sydr);
    }

    private void insertDrink(SQLiteDatabase db, String name, String description, int imageResId) {
        ContentValues drinkValues = new ContentValues();
        drinkValues.put("NAME", name);
        drinkValues.put("DESCRIPTION", description);
        drinkValues.put("IMAGE_RESOURCE_ID", imageResId);
        db.insert("DRINK", null, drinkValues);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

Query()

A database query gives you a way of saying exactly which records you want access to from the database. As an example, you can say you want to access all the data from the DRINK table, or just those drinks whose name begins with “L”. The more you can restrict the data you return, the more efficient your query will be. 

Example

Cursor cursor = db.query("DRINK", new String[] {"NAME", "DESCRIPTION"},
                            null, null, null, null, null);

The simplest type of database query you can create is to return all the records for particular columns without specifying criteria. 

NAME DESCRIPTION
Bloody Mary   Bloody Mary desc
Sazerac Sazerac drink
B52 B52 drink
Cider Cider drink

Example

Cursor cursor = db.query("Drink",
                         new String[] {"_id", "NAME", "DESCRIPTION"},
                         "_id = ?",
                         new String[] {Integer.toString(1)}, 
                         null, null, null);
_id NAME DESCRIPTION
1 Bloody Mary Bloody Mary desc

getReadableDatabase() versus getWritableDatabase() 

How to get info from Cursor

//Move to the first record in the Cursor 
if (cursor.moveToFirst()) {
//Get the drink details from the cursor 
    String nameText = cursor.getString(0); 
    String descriptionText = cursor.getString(1); 
    int photoId = cursor.getInt(2);

    // process data
}

cursor.close();
db.close();

Cursor Adapter

Closing Cursor and Database

@Override
public void onDestroy(){ 
    super.onDestroy(); 
    cursor.close(); 
    db.close();
}

Final structure

Copy of Android

By Sania Sutula

Copy of Android

  • 381