session #5 content providers

Post on 12-Apr-2017

62 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Android Academy TLV4/12/2016Britt Barak

WIFI: pUp3EkaP

Content Providing#5

First,

Britt BarakBritt Barak

Figure 8

Android AcademyWomen Techmakers

Jonathan Yarkoni

Android Developer & Advocate Ironsource

Android Academy Staff

Yonatan LevinGoogle Developer

Expert & Android @ Gett

Britt BarakAndroid Lead

Figure8

Yossi SegevAndroid Developer

Crave

What Do We Do?

●Android Fundamentals

●Android UI / UX

●Community Hackathon

●Android Performance

●Mentors Program●Active community

Community Mentors

Erez Pickman

Data In Apps

Application

Content Provider

Database (SQLite)

Road Map

Road Map

Last time:Activity Life Cycle

Today: Data Integration

Next time:Load Data To Activity

Database

Database

Database: A structured set of data

Relational database: A Database which uses tables and relations to organize the data, Usually uses SQL for operations

Relational Database management system:A program (or less) that implements a Relational Database.Common vendors:PostgreSQL, Oracle, MySQL, Microsoft SQL Server

When to use a Database

- Large datasets- Structured data- Cache / Preload data

Better loading times, Better battery utilization

Our Database

SQLite is a mini-RDBMS. Unlike most:

- Serverless (Runs in your process, not on its own)

- Zero-Configuration

- Most widely deployed database

Get to know it better: https://www.sqlite.org/

Our Database

Most widely deployed database:Every Android deviceEvery iPhone and iOS deviceEvery MacEvery Windows 10 machineEvery Firefox, Chrome, and Safari web browserEvery instance of SkypeEvery instance of iTunesEvery Dropbox clientMost television sets and set-top cable boxesMost automotive multimedia systemsCountless millions of other applicationsSource: https://www.sqlite.org/mostdeployed.html

SQL - Structured Query Language

the language to communicate with

database.

Consider this table

Data taken from: http://www.meetup.com/TLV-Android-Academy/events/ ☺* Not really how dates are represented

_ID Date* Title Lecturer Floor

1 1/11 Intro And Basics Yonatan 29

2 8/11 Basics and ListViews Britt 29

3 13/11 Off threading Yarkoni 34

4 20/11 New Activities and Intents Yonatan 34

5 27/11 Lifecycles Yarkoni 34

6 4/12 Databases and stuff Britt Unknown

7 11/12 Loaders Yossi Unknown

Actions:

- Select - gets part of the table- Update - modifies values in existing records- Insert - Adds records to tables.- Delete - Removes records from tables.

Select - gets part of the table

SELECT ( * | [column, column]) FROM (table)WHERE (condition)ORDER BY (column) (ASC | DESC)

This is uber-simplified. Read more: https://www.sqlite.org/lang_select.html

Select

SELECT * FROM Sessions WHERE floor=’34’

_ID Date* Title Lecturer Floor

3 13/11 Off threading Yarkoni 34

4 20/11 New Activities and Intents Yonatan 34

5 27/11 Lifecycles Yarkoni 34

Select

SELECT Date, Title FROM Sessions WHERE floor=’34’

Date* Title

13/11 Off threading

20/11 New Activities and Intents

27/11 Lifecycles

Select

SELECT Date, Title FROM Sessions WHERE floor=’34’ORDER BY date DESC

Date* Title

27/11 Lifecycles

20/11 New Activities and Intents

13/11 Off threading

Select

SELECT * FROM Sessions WHERE title LIKE ’% and %’

_ID Date* Title Lecturer Floor

1 1/11 Intro and Basics Yonatan 29

2 8/11 Basics and ListViews Britt 29

4 20/11 New Activities and Intents Yonatan 34

6 4/12 Databases and stuff Britt Unknown

Select

SELECT * FROM Sessions WHERE lecturer LIKE ’Yo%’

_ID Date* Title Lecturer Floor

1 1/11 Intro And Basics Yonatan 29

4 20/11 New Activities and Intents Yonatan 34

7 11/12 Loaders Yossi Unknown

Select

SELECT * FROM Sessions WHERE lecturer LIKE ’Yo%’AND floor = ‘34’

_ID Date* Title Lecturer Floor

4 20/11 New Activities and Intents Yonatan 34

Select

SELECT * FROM Sessions_ID Date* Title Lecturer Floor

1 1/11 Intro And Basics Yonatan 29

2 8/11 Basics and ListViews Britt 29

3 13/11 Off threading Yarkoni 34

4 20/11 New Activities and Intents Yonatan 34

5 27/11 Lifecycles Yarkoni 34

6 4/12 Databases and stuff Britt Unknown

7 11/12 Loaders Yossi Unknown

UPDATE (table) SET (column)=(expr) [, (column)=(expr) [,...]WHERE (condition)

Update - Modifies values in existing records.

Again, Super simplified. Read more: https://www.sqlite.org/lang_update.html

UPDATE Sessions SET lecturer=’Britt’, floor=29WHERE _id = 6

Update

_ID Date* Title Lecturer Floor

6 4/12 Databases and stuff NULL NULL

_ID Date* Title Lecturer Floor

6 4/12 Databases and stuff Britt 29

INSERT INTO (table) ((column) [, (column) [,...]])VALUES

( expr [, expr [,...]])

Insert - Adds records to tables

Read more: https://www.sqlite.org/lang_insert.html

INSERT INTO Sessions (date, title, lecturer, floor)

VALUES (‘18/12’, ‘Rich and responsive layout’, null, null)

Inserting Data: Insert

Inserting Data: Insert

_ID Date* Title Lecturer Floor

1 1/11 Intro And Basics Yonatan 29

2 8/11 Basics and ListViews Britt 29

3 13/11 Off threading Yarkoni 34

4 20/11 New Activities and Intents Yonatan 34

5 27/11 Lifecycles Yarkoni 34

6 4/12 Databases and stuff Britt 29

7 11/12 Loaders Yossi Unknown

8 18/12 Rich and responsive layouts null null

Delete - Removes records from tables.

DELETE FROM (table) WHERE (condition)

Deleting Data: Delete

DELETE FROM Sessions WHERE floor = 29_ID Date* Title Lecturer Floor

1 1/11 Intro And Basics Yonatan 29

2 8/11 Basics and ListViews Britt 29

3 13/11 Off threading Yarkoni 34

4 20/11 New Activities and Intents Yonatan 34

5 27/11 Lifecycles Yarkoni 34

6 4/12 Databases and stuff Britt 34

7 11/12 Loaders Yossi Unknown

8 18/12 Rich and responsive layouts null null

Be CRUD!

Basic operations of persisting data

Read more: https://en.wikipedia.org/wiki/Create,_read,_update_and_delete

Be CRUD!

What’s important for us to know after each operation?Create - ID of the new recordRead - the record-setUpdate - # changed recordsDelete - # deleted records

Creating our table

CREATE TABLE Sessions (

_id INTEGER PRIMARY KEY, date TEXT, title TEXT, lecturer TEXT, floor INTEGER

)Read More: https://www.sqlite.org/lang_createtable.html

Delete a table.

DROP TABLE IF EXISTS (table)

Things I didn’t talk about

Using multiple tables, defining relationsDesigning databases (3NF, 5NF, Inheritance modeling)

Using indexing to improve performanceThread-safety, reader/writers, locking, ...Triggers, ViewsTransactions

Major Challenges (For us)Avoid SQL Injection

Upgrade when needed

Being up-to-date

SQL Injection

What is SQL Injection?

Users:Username Password

guest 1234

admin VeryHardPassword

Britt Dre@mB!g

Yonatan I3>starWars

Yossi @ndr0id

Yarkoni BBB4Ever!

How to log in?

Try : Strings concatenation

“SELECT * “ + “FROM users “ +“WHERE (username=’” + username + ”’) and (password=’” + password + “‘)“

Try 1: Strings concatenation

For username = “guest” and password = “1234”:

“SELECT * “ + “FROM users “ +“WHERE (username=’” + username + ”’) and (password=’” + password + “‘)“

Try 1: Strings concatenation

For username = “guest” and password = “1234”:

SELECT * FROM usersWHERE (username=’guest’) and (password=’1234‘)

Try 2: Strings concatenation

For username = “admin” and password = “a or (1=1)) --”:

“SELECT * “ + “FROM users “ +“WHERE (username=’” + username + ”’) and (password=’” + password + “‘)“

Try 2: Strings concatenation

For username = “admin” and password = “a or (1=1)) --”:

SELECT * FROM usersWHERE (username=’admin’) and (password=’a or (1=1)) -- ‘)Read more: https://en.wikipedia.org/wiki/SQL_injection

Solution: Use Query Parameters

Use this string: “SELECT * “ + “FROM users “ +“WHERE (username=?) and (password=?)“

and pass the input as Query Parameters.

Solution: Use Query Parameters

For username = “admin” and password = “a or (1=1)) --”:

“SELECT * “ + “FROM users “ +“WHERE

(username=“admin”) and (password=“a or (1=1)) --”)“

Try 2: Strings concatenation

For username = “admin” and password = “a or (1=1)) --”:

SELECT * FROM usersWHERE (username=’admin’) and (password=’a or (1=1)) -- ‘)Read more: https://en.wikipedia.org/wiki/SQL_injection

Questions ?

Upgrade

Application

Content Provider

DataBase (SQLite)

SQLiteOpenHelper

What’s hard about Upgrades?

- keep track of schema’s version.- perform upgrade steps for each schema version.- detect when to do it

- You need to think about how to upgrade the

schema, what to do with existing data, setting default values, etc.

Open DB if it exists

Create DB if doesn’t

Upgrade if necessary.

SQLiteOpenHelper for the rescue!

Reference: http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html

Subclass by implementing:- onCreate(SQLiteDatabase)- onUpgrade(SQLiteDatabase, int, int).

SQLiteOpenHelper for the rescue!

Reference: http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html

Easier for ContentProvidersto defer opening and upgrading the database until first use,to avoid blocking application startup with long-running database upgrades.

SQLiteOpenHelper for the rescue!

Reference: http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html

You have 2 methods that you use to get a SQLiteDatabase:getReadableDatabase() and getWritableDatabase()

SQLiteOpenHelper for the rescue!

Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)

long insert(String table, String nullColumnHack, ContentValues values)

What To Do With SQLiteDatabase ?

int update(String table, ContentValues values, String whereClause, String[] whereArgs)

int delete(String table, String whereClause, String[] whereArgs)

Don’t hard-code Strings

Don’t hard-code Strings

- Most Strings will be reused.- Access same resource from different objects

Good practice: extract them into a single Contract class.

Don’t hard-code Strings

The contract class contains:- Table and column names- URI Related stuff, such as

- Content Authorities

- Build methods

- Parse methods

Developer Responsibilities

Developer Responsibilities

1.extend SQLiteOpenHelper2.Implement onCreate and onUpdate3.Create a constructor,

Call the super’s constructor with:a.A Context

b.Database name

c.An optional Cursor Factory (which we won’t use, so we’ll pass null)

d.A Version

4.Extract a contract (Optionally)

1.Extend SQLiteOpenHelper

public class AndroidAcademyDatabaseHelper extends SQLiteOpenHelper {

}

2.onCreate and onUpgradepublic class AndroidAcademyDatabaseHelper extends SQLiteOpenHelper {

@Override public void onCreate(SQLiteDatabase db) {

}

@Override public void onUpgrade(SQLiteDatabase db, int oldVersion,

int newVersion) {

}}

2.onCreate and onUpgradepublic class AndroidAcademyDatabaseHelper extends SQLiteOpenHelper { String sqlCreation = "CREATE TABLE Sessions ( " + "_id INTEGER PRIMARY KEY, " + "date TEXT, " + "title TEXT, " + "lecturer TEXT, " + "floor INTEGER " + ")";

@Override public void onCreate(SQLiteDatabase db) { db.execSQL(sqlCreation); createInitialData(db); }}

2.onCreate and onUpdatepublic class AndroidAcademyDatabaseHelper extends SQLiteOpenHelper {

@Override public void onUpgrade(SQLiteDatabase db, int oldVersion,

int newVersion) { db.execSQL("DROP TABLE IF EXISTS Sessions"); onCreate(db); }}

3.Constructorpublic class AndroidAcademyDatabaseHelper extends SQLiteOpenHelper {

public AndroidAcademyDatabaseHelper(Context context){ super(context, "androidacademy.db", null, 1); }

}

4.Optional: Extract Contract

public class AndroidAcademyContract {

public static class SessionEntry implements BaseColumns {

public static final String TABLE_NAME = "Sessions";

public static final String COLUMN_DATE = "date"; public static final String COLUMN_TITLE = "title"; public static final String COLUMN_LECTURER = "lecturer"; public static final String COLUMN_FLOOR = "floor"; }}

4.Optional: Extract Contract

then, use Contract in the helper. For example:private static final int DATABASE_VERSION = 1;private static final String DATABASE_NAME = "androidacademy.db";

private static final String SQL_CREATION = "CREATE TABLE " + AndroidAcademyContract.SessionEntry.TABLE_NAME + " ( " + AndroidAcademyContract.SessionEntry._ID + " INTEGER PRIMARY KEY, " + AndroidAcademyContract.SessionEntry.COLUMN_DATE + " TEXT, " + AndroidAcademyContract.SessionEntry.COLUMN_TITLE + " TEXT, " + AndroidAcademyContract.SessionEntry.COLUMN_LECTURER + " TEXT, " + AndroidAcademyContract.SessionEntry.COLUMN_FLOOR + " INTEGER " + ")";

Demo Time

1.in onCreate we set the ListView with a cursor adapter, but with no cursor.We also create the DB helper there.

2.when we refresh, or do something,that’s when we hit the DB for the first time - and if it doesn’t exist, we create it.

3.There’s no Observing mechanism when using the dbHelper directly.

5.(Bonus!) implement CRUD on the Helper

Making the SQL Helper a full blown Data-Access-Object (or DAO). public void insertSession(SQLiteDatabase db, String date, String title, String lecturer, Integer floor) { ContentValues values = new ContentValues(); values.put(AndroidAcademyContract.SessionEntry.COLUMN_DATE, date); values.put(AndroidAcademyContract.SessionEntry.COLUMN_TITLE, title); values.put(AndroidAcademyContract.SessionEntry.COLUMN_LECTURER, lecturer); values.put(AndroidAcademyContract.SessionEntry.COLUMN_FLOOR, floor); db.insert(AndroidAcademyContract.SessionEntry.TABLE_NAME, null, values);}

Read more: https://en.wikipedia.org/wiki/Data_access_object

Application

Content Provider

DataBase (SQLite)

SQLiteOpenHelper Contract

Any questions?

The Relationship Between Apps And Data

Application

Content Provider

DataBase (SQLite)

SQLiteOpenHelper

InsertQueryUpdateDelete

Contract

the standard interface that connects data in one process with code running in another process.

Content Provider

API Guide: http://developer.android.com/guide/topics/providers/content-providers.html

Application

Content Provider

Database

InsertQueryUpdateDelete

Data Layer:

- encapsulate the data- manage access to db- mechanisms for data security.

Content Provider - Role

API Guide: http://developer.android.com/guide/topics/providers/content-providers.html

Application

Content Provider

Database

InsertQueryUpdateDelete

Data Layer:

When to use it?

- Share data between apps:- offer complex data or files to other applications

- allow users to copy complex data from your app into other apps

- use android dbs: contacts, calendar, sms...- Android Framework:

- widgets, search, sync adapter, cursor loader

- Abstraction - Of data layer, over direct SQL access

1.extend ContentProvider

2.Register in Manifest

3.Use your content provider with a Content Resolver

Content Provider Recipe

1.extend ContentProvider

implement these methods:- query- delete- update- insert- getType- onCreate

http://developer.android.com/guide/topics/providers/content-provider-creating.html#RequiredAccess

1.extend ContentProvider

Each implementation should be about 3 things:1.What’s the URI? What does the user want to

do?2.Use the datasource (if applicable)3.Notify the change to everyone (if applicable)

http://developer.android.com/guide/topics/providers/content-provider-creating.html#RequiredAccess

query()

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

This is super-easy to implement with the SQLiteOpenHelper.Also: cursor.setNotificationUri(getContext().getContentResolver(), uri);

public Uri insert(Uri uri, ContentValues values);

To create this URI, you can use the URI.BuildUpon.Also: getContext().getContentResolver().notifyChange(uri, null);

insert()

update()

public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)

Also: getContext().getContentResolver().notifyChange(uri, null);

delete()

public int delete(Uri uri, String selection,

String[] selectionArgs)

Also: getContext().getContentResolver().notifyChange(uri, null);

Returns a string, that identifies your data structure.

Format:

getType()

Read more: http://developer.android.com/guide/topics/providers/content-provider-creating.html#TableMIMETypes

itemdir /vnd.<name>.<type>

For single Items

For sets

Usually, Your app namespace

Depends on the URI

vnd.android.cursor.

onCreate

Returns true if the creation was a success.

it should be quick, (it usually runs on the UI thread)

so it’s not the right place to do a database update.

Lucky for us, SQLiteOpenHelper is ...Read More: http://developer.android.com/guide/topics/providers/content-provider-creating.html#OnCreate

1.extend ContentProvider

2.Register in Manifest

3.Use your content provider with a Content Resolver

Content Provider Recipe

2.Register in Manifest

In order for Android to find your Content Provider (given a URI), You must register it in the App’s Manifest, as such:<provider android:authorities="com.example.androidacademy.session5.nosql.provider" android:name=".NoSQLContentProvider" />

<provider android:authorities="com.example.androidacademy.session5.sql.provider" android:name=".SQLContentProvider" />

1.extend ContentProvider

2.Register in Manifest

3.Use your content provider with a Content Resolver

Content Provider Recipe

3.Using it (Part 1)

NEVER use a ContentProvider directly!

Ask a ContentResolver to do the work for you,which has all CRUD methods you’ll need.

Application

ContentResolver

Content Provider

DataBase (SQLite)

SQLiteOpenHelper

InsertQueryUpdateDelete

Contract

3.Using it (Part 1)

public void refresh(View view) { Cursor cursor = getContentResolver() .query(SQLProviderContract.NumberEntries.CONTENT_URI, null, null, null, null); adapter.swapCursor(cursor);}

3.Using it (Part 1)

public void insertARandomNumber(View view) { Random random = new Random(); int randomNumber = random.nextInt(100);

ContentValues newNumberValues = new ContentValues(); newNumberValues.put(SQLProviderContract.NumberEntries.COLUMN_NUMBER, randomNumber);

getContentResolver() .insert(SQLProviderContract.NumberEntries.CONTENT_URI, newNumberValues);}

3.Using it (Part 2) - Next Session

Next timeWe’ll see how to properly use a content provider to:

keep your activities synced with the dataperform loading on a background thread keep it safe with the Activity Lifecycle.

Any questions?

Demo Time

2 Content Providers: Both keep track of numbers.The first uses an ArrayList<Integer> as a backing store, The other uses a SQL database.

Interesting: Cursor Observation on the content provider.

So why UDACITY’s code

is so complicated?

3 things to spice-up your Provider

URI MatchingHandling URIsSQLiteQueryBuilder

URI Matching

Supporting a few kinds of URIs

content://com.example.android.sunshine.app/locationcontent://com.example.android.sunshine.app/weather/content://com.example.android.sunshine.app/weather/Londoncontent://com.example.android.sunshine.app/weather/London/15-DEC-2015

Each is treated differently

URI Matching

Each URI identifies with an IDTo choose the treatment

URI Matcher

URI URI IDURIMatcher

But There Can Be Countless URIs!content://com.example.android.sunshine.app/weather/

content://com.example.android.sunshine.app/weather/London

content://com.example.android.sunshine.app/weather/TelAviv

content://com.example.android.sunshine.app/weather/Berlin

content://com.example.android.sunshine.app/weather/Milan

URI Matcher - Set Up

matcher.addURI(authority, URI_TEMPLATE, ID);

URI Template ID

WeatherContract.PATH_WEATHER WEATHER

WeatherContract.PATH_WEATHER + "/*"

WEATHER_WITH_LOCATION

WeatherContract.PATH_WEATHER + "/*/#"

WEATHER_WITH_LOCATION_AND_DATE

URI Matcher - Useage

final int match = sUriMatcher.match(uri);

URI URI IDURIMatcher

URI Matching

What does it mean for each Content Provider method?- query- delete- update- insert- getType

Application

ContentResolver

Content Provider

DataBase (SQLite)

SQLiteOpenHelperContract

URIMatcherInsertQueryUpdateDelete

Pro Tip: Get Parameters from URI

uri.getPathSegments().get(1) → content://authority/words/party

uri.getQueryParameter(“q”)

→ content://google.com/search?q=Party

Any questions?

Thank you!!

top related