couchbase mobile 101 – couchbase live new york 2015

52
©2015 Couchbase Inc. Couchbase Mobile 101: How to Build Your First Mobile App William Hoang | Mobile Developer Advocate | @sweetiewill

Upload: couchbase

Post on 27-Jan-2017

624 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Couchbase Mobile 101:How to Build Your First Mobile App

William Hoang | Mobile Developer Advocate |

@sweetiewill

Page 2: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Introduction to Couchbase Lite

Demo: Installing and running a Sample App

Code: Tour of Couchbase Lite’s Architecture and API

Next Steps

Overview:

Getting Started with Couchbase Mobile

Page 3: Couchbase Mobile 101 – Couchbase Live New York 2015

Couchbase Sync Gateway…will be introduced in Couchbase Mobile 102

Page 4: Couchbase Mobile 101 – Couchbase Live New York 2015

Couchbase Peer to Peer…will be introduced in Couchbase Mobile 103

Page 5: Couchbase Mobile 101 – Couchbase Live New York 2015

Couchbase Lite

Page 6: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Couchbase LiteEmbedded database library for mobile appsFlexible, schemaless data model (“NoSQL”)Querying by map/reduce viewsActive change notifications, for reactive UIsFull-strength multi-master replication

6

Page 7: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Couchbase Mobile ReplicationAvoid network latency for data accessOffline support (if you want it)Control over conflict resolutionArbitrary topologies, including P2POpen protocol

7

Page 8: Couchbase Mobile 101 – Couchbase Live New York 2015

Running Your First App

Page 9: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Running Your First iOS AppInstall Xcode 6 from Mac App StoreDownload Couchbase LiteDownload Grocery Sync sample codeCopy framework into sample app folderBuild & Run the Xcode project

9

Page 10: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

2. Download Couchbase Litecouchbase.com/nosql-databases/downloads

Click “Couchbase Mobile”

10

Page 11: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

3. Download Grocery Sync Source Codegithub.com/couchbaselabs/Grocery-Sync-iOS

11

Page 12: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

4. Plug In The Framework

12

Page 13: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

5. Open The Project

13

Page 14: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Running Your First Android AppInstall Android Studio with Android SDK 19 &

Build Tool 19Check out Grocery Sync sample code repoImport Grocery Sync gradle file into Android

StudioPress Debug or Run button

14

Page 15: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

2. Download Grocery Sync Source Code

15

Page 16: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

3. Import ‘build.gradle’ into Android Studio

16

Page 17: Couchbase Mobile 101 – Couchbase Live New York 2015

Quick Demo

Page 18: Couchbase Mobile 101 – Couchbase Live New York 2015

A Tour Of The CodeAnd The API

Page 19: Couchbase Mobile 101 – Couchbase Live New York 2015

1. Initialization & Insertion

Page 20: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

InitializationDemoAppDelegate.m:61

// Initialize Couchbase Lite and find/create my database: NSError* error; self.database = [[CBLManager sharedInstance] databaseNamed: kDatabaseName error: &error]; if (!self.database) { [self showAlert: @"Couldn't open database" error: error fatal: YES]; return NO; }

20

Page 21: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

InitializationMainActivity.java:118

manager = new Manager(new AndroidContext(this), Manager.DEFAULT_OPTIONS);

database = manager.getDatabase(DATABASE_NAME);

21

Page 22: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

ManagerTop-level object, usually a singletonA collection of named databasesLocates databases in filesystem

22

Page 23: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Databases And Documents

Database

“to-do”

“doc1”

“doc3”

Document “doc2”{ “text”: “Vacuum kitchen”, “created”: “2015-09–06”, “check”: false, “tags”:[“William”,“chore”]}

thumb.jpg

23

“doc2”

“to-do”

Page 24: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

DatabaseNamespace for documentsContains views and their indexesContains validation functionsSource and target of replication

24

Page 25: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Document“_id” is unique within database, immutableJSON allows nested data structures (arrays,

maps)Schemaless — Documents needn’t have the

same structureDifferent types of docs can coexist in a

database“type” property is a common convention

Documents are versionedOptimistic concurrency control (MVCC)

25

Page 26: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Adding New ItemsRootViewController.m:243

// Create the new document's properties: NSDictionary *document = @{@"text": text, @"check": @NO, @"created_at": [CBLJSON JSONObjectWithDate: [NSDate date]]}; // Save the document: CBLDocument* doc = [database createDocument]; NSError* error; if (![doc putProperties: document error: &error]) { [self showErrorAlert: @"Couldn't save new item" forError: error]; }

26

Page 27: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Adding New ItemsMainActivity.java:343

SimpleDateFormat dateFormatter = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); UUID uuid = UUID.randomUUID(); Calendar calendar = GregorianCalendar.getInstance(); long currentTime = calendar.getTimeInMillis(); String currentTimeString = dateFormatter.format(calendar.getTime()); String id = currentTime + "-" + uuid.toString();

Document document = database.createDocument(); Map<String, Object> properties = new HashMap<String, Object>(); properties.put("_id", id); properties.put("text", text); properties.put("check", Boolean.FALSE); properties.put("created_at", currentTimeString);

document.putProperties(properties); 27

Page 28: Couchbase Mobile 101 – Couchbase Live New York 2015

2. Views & Queries

Page 29: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Creating A Database ViewRootViewController.m:101

// Define a view with a map function that indexes to-do items by creation date: [[theDatabase viewNamed: @"byDate"] setMapBlock: MAPBLOCK({ id date = doc[@"created_at"]; if (date) emit(date, nil); }) version: @"1.1"];

Not a UIView —a database “view”is like an index.

29

Page 30: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Map/Reduce ViewsConcept from functional programming, via

GoogleApp-defined map function operates on

documentsdoc ⟼ { (key, value) …}

Its output generates an index ordered by keyIndex rows can be aggregated by a reduce

functionIndex is queried by key or key range

30

Page 31: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Map/Reduce Indexing

emit(doc.created, doc.title)

key value docID“2013-03-12” “taxes” “doc17”

“2013-09-30”

“call mom” “doc62”

“2013-10-17” “cat food” “doc82”

“2013-10-17”

“tea bags” “doc83”

“2013-10-22” “upgrade” “doc90”

index

all documents

map function

View“byDate”

31

Page 32: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Creating A Database ViewRootViewController.m:101

// Define a view with a map function that indexes to-do items by creation date: [[theDatabase viewNamed: @"byDate"] setMapBlock: MAPBLOCK({ id date = doc[@"created_at"]; if (date) emit(date, nil); }) version: @"1.1"];

Not a UIView —a database “view”is like an index.

32

Page 33: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Creating A Database ViewMainActivity.java:122

com.couchbase.lite.View viewItemsByDate = database.getView(String.format("%s/%s", designDocName, byDateViewName)); viewItemsByDate.setMap(new Mapper() { @Override public void map(Map<String, Object> document, Emitter emitter) { Object createdAt = document.get("created_at"); if (createdAt != null) { emitter.emit(createdAt.toString(), null); } } }, "1.0");

Not a UIView —a database “view”is like an index.

33

Page 34: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Driving the Table from a View QueryRootViewController.m:101

// Create a query sorted by descending date, i.e. newest items first: CBLLiveQuery* query = [[[database viewNamed:@"byDate"] query] asLiveQuery]; query.descending = YES;

// Plug the query into the CBLUITableSource, which uses it to drive the table. // (The CBLUITableSource uses KVO to observe the query's .rows property.) self.dataSource.query = query; self.dataSource.labelProperty = @"text";

@property(nonatomic, strong) IBOutlet UITableView *tableView;@property(nonatomic, strong) IBOutlet CBLUITableSource* dataSource;

RootViewController.h:41

34

Page 35: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Driving the Table from a View QueryRootViewController.m:101

liveQuery = view.createQuery().toLiveQuery();

liveQuery.addChangeListener(new LiveQuery.ChangeListener() { public void changed(final LiveQuery.ChangeEvent event) { runOnUiThread(new Runnable() { public void run() { grocerySyncArrayAdapter.clear(); for (Iterator<QueryRow> it = event.getRows(); it.hasNext();) { grocerySyncArrayAdapter.add(it.next()); } grocerySyncArrayAdapter.notifyDataSetChanged();

35

Page 36: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

LiveQuery

Querying a View

36

key value docID“2013-03-12” “taxes” “doc17”

“2013-09-30”

“call mom” “doc62”

“2013-10-17” “cat food” “doc82”

“2013-10-17”

“tea bags” “doc83”

“2013-10-22” “upgrade” “doc90”

index

} Query QueryRowQueryRowQueryRow

.limit = 3

.offset = …

.reverse = …

.startKey = …

.endKey = …

Page 37: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

LiveQuery Driving An iOS UITableView

37

LiveQueryQuery

CBLUITable-Source

UITableViewYour

Controller

data source

delegate

Page 38: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

LiveQuery Driving An iOS UITableView

38

Page 39: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Displaying Table CellsDemoAppDelegate.m:131- (void)couchTableSource:(CBLUITableSource*)source willUseCell:(UITableViewCell*)cell forRow:(CBLQueryRow*)row{ // Set the cell background and font: ……… // Configure the cell contents. Map function (above) copies the doc properties // into its value, so we can read them without having to load the document. NSDictionary* rowValue = row.value; BOOL checked = [rowValue[@"check"] boolValue]; if (checked) { cell.textLabel.textColor = [UIColor grayColor]; cell.imageView.image = [UIImage imageNamed:@"checked"]; } else { cell.textLabel.textColor = [UIColor blackColor]; cell.imageView.image = [UIImage imageNamed: @"unchecked"]; } // cell.textLabel.text is already set, thanks to setting up labelProperty} 39

Called by the CBLUITableSource when it’s told to display a cell.

Page 40: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Displaying Table CellsGrocerySyncArrayAdapter.java:33

public View getView(int position, View itemView, ViewGroup parent) {//...TextView label = ((ViewHolder)itemView.getTag()).label;QueryRow row = getItem(position);SavedRevision currentRevision = row.getDocument().getCurrentRevision();// Check boxObject check = (Object) currentRevision.getProperty("check");boolean isGroceryItemChecked = false;if (check != null && check instanceof Boolean) isGroceryItemChecked = ((Boolean)check).booleanValue();// TextString groceryItemText = (String) currentRevision.getProperty("text");label.setText(groceryItemText);

40

Page 41: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Responding To TapsDemoAppDelegate.m:131- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ // Ask CBLUITableSource for the corresponding query row, and get its document: CBLQueryRow *row = [self.dataSource rowAtIndex:indexPath.row]; CBLDocument *doc = row.document;

// Toggle the document's 'checked' property: NSMutableDictionary *docContent = [doc.properties mutableCopy]; BOOL wasChecked = [docContent[@"check"] boolValue]; docContent[@"check"] = @(!wasChecked);

// Save changes: NSError* error; if (![doc.currentRevision putProperties: docContent error: &error]) { [self showErrorAlert: @"Failed to update item" forError: error]; }}

41

Called by the UITableView itself

Page 42: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Responding To TapsMainActivity.java:243

public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { QueryRow row = (QueryRow) adapterView.getItemAtPosition(position); Document document = row.getDocument(); Map<String, Object> newProperties = new HashMap<String, Object>(document.getProperties());

boolean checked = ((Boolean) newProperties.get("check")).booleanValue(); newProperties.put("check", !checked);

try { document.putProperties(newProperties); grocerySyncArrayAdapter.notifyDataSetChanged(); } catch (Exception e) { // ... 42

Page 43: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Change NotificationsThree types:DatabaseChanged: Any document updatedDocumentChanged: A specific document

updatedLiveQuery: Change in query result set

Enables reactive programming

Controller Model(Database)GUI View

User event Update doc

DocumentChanged

Redraw

43

Replication(pull)

Page 44: Couchbase Mobile 101 – Couchbase Live New York 2015

3. Replication

Page 45: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Replication

46

Replication

(push)

Replication

(pull)https://exam.pl/dblocal_db

Page 46: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

ReplicationReplication is asynchronousUse database notifications to detect changes

A Replication can be one-shot or continuousOne-shot runs only until it “catches up”Continuous keeps going till stopped or app

quitsContinuous handles online/offline transitions

gracefullyReplications can be filtered

47

Page 47: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Creating ReplicationsDemoAppDelegate.m:74

_pull = [database createPullReplication: serverDbURL]; _push = [database createPushReplication: serverDbURL]; _pull.continuous = _push.continuous = YES; // Observe replication progress changes, in both directions: NSNotificationCenter* nctr = [NSNotificationCenter defaultCenter]; [nctr addObserver: self selector: @selector(replicationProgress:) name: kCBLReplicationChangeNotification object: _pull]; [nctr addObserver: self selector: @selector(replicationProgress:) name: kCBLReplicationChangeNotification object: _push]; [_push start]; [_pull start];

48

Page 48: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Creating ReplicationsMainActivity.java:150

Replication pullReplication = database.createPullReplication(syncUrl); pullReplication.setContinuous(true);

Replication pushReplication = database.createPushReplication(syncUrl); pushReplication.setContinuous(true);

pullReplication.start(); pushReplication.start();

pullReplication.addChangeListener(this); pushReplication.addChangeListener(this);

49

Page 49: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Monitoring ReplicationsDemoAppDelegate.m:98- (void) replicationProgress: (NSNotificationCenter*)n { if (_pull.status == kCBLReplicationActive || _push.status == kCBLReplicationActive) { // Sync is active -- aggregate the progress of both replications and compute a fraction: unsigned completed = _pull.completedChangesCount + _push.completedChangesCount; unsigned total = _pull.changesCount+ _push.changesCount; NSLog(@"SYNC progress: %u / %u", completed, total); // Update the progress bar, avoiding divide-by-zero exceptions: [self.rootViewController showSyncStatus: (completed / (float)MAX(total, 1u))]; } else { // Sync is idle -- hide the progress bar and show the config button: NSLog(@"SYNC idle"); [self.rootViewController hideSyncStatus]; }

// Check for any change in error status and display new errors: NSError* error = _pull.lastError ? _pull.lastError : _push.lastError; if (error != _syncError) { _syncError = error; if (error) { [self showAlert: @"Error syncing" error: error fatal: NO]; } }}

50

Page 50: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Monitoring ReplicationsMainActivity.java:381 public void changed(Replication.ChangeEvent event) { Replication replication = event.getSource(); Log.d(TAG, "Replication : " + replication + " changed."); if (!replication.isRunning()) { String msg = String.format("Replicator %s not running", replication); Log.d(TAG, msg); } else { int processed = replication.getCompletedChangesCount(); int total = replication.getChangesCount(); String msg = String.format("Replicator processed %d / %d", processed, total); Log.d(TAG, msg); } if (event.getError() != null) { showError("Sync error", event.getError()); } } 51

Page 51: Couchbase Mobile 101 – Couchbase Live New York 2015

Next Steps

Page 52: Couchbase Mobile 101 – Couchbase Live New York 2015

©2015 Couchbase Inc.

Getting Started: Next StepsTry connecting Grocery Sync to your own Sync

Gateway

Couchbase Mobile Blog:Blog.couchbase.com

Visit our mobile developer forums

53