Upload
vitali-pekelis
View
60
Download
0
Embed Size (px)
Citation preview
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
Largest Android Community
Android Academy - TLV
TLV - Android Academy
~ 2000 members Join Us:
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!!