Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Couchbase Mobile 101 – Couchbase Live New York 2015

778 views

Published on

Bring your laptops! You’ll learn the process of building an app from scratch that works online and offline. Learn about reading & writing Data, modeling app data the NoSQL way, adding sync in less than 5 minutes, enabling authentication, restricting data access, and adding role based security. By the end of this session you will be able to design and build your own app with Couchbase Mobile.

Published in: Software

Couchbase Mobile 101 – Couchbase Live New York 2015

  1. 1. ©2015 Couchbase Inc. Couchbase Mobile 101: How to Build Your First Mobile App William Hoang | Mobile Developer Advocate | @sweetiewill
  2. 2. ©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
  3. 3. Couchbase Sync Gateway …will be introduced in Couchbase Mobile 102
  4. 4. Couchbase Peer to Peer …will be introduced in Couchbase Mobile 103
  5. 5. Couchbase Lite
  6. 6. ©2015 Couchbase Inc. Couchbase Lite Embedded database library for mobile apps Flexible, schemaless data model (“NoSQL”) Querying by map/reduce views Active change notifications, for reactive UIs Full-strength multi-master replication 6
  7. 7. ©2015 Couchbase Inc. Couchbase Mobile Replication Avoid network latency for data access Offline support (if you want it) Control over conflict resolution Arbitrary topologies, including P2P Open protocol 7
  8. 8. Running Your First App
  9. 9. ©2015 Couchbase Inc. Running Your First iOS App Install Xcode 6 from Mac App Store Download Couchbase Lite Download Grocery Sync sample code Copy framework into sample app folder Build & Run the Xcode project 9
  10. 10. ©2015 Couchbase Inc. 2. Download Couchbase Lite couchbase.com/nosql-databases/downloads Click “Couchbase Mobile” 10
  11. 11. ©2015 Couchbase Inc. 3. Download Grocery Sync Source Code github.com/couchbaselabs/Grocery-Sync-iOS 11
  12. 12. ©2015 Couchbase Inc. 4. Plug In The Framework 12
  13. 13. ©2015 Couchbase Inc. 5. Open The Project 13
  14. 14. ©2015 Couchbase Inc. Running Your First Android App Install Android Studio with Android SDK 19 & Build Tool 19 Check out Grocery Sync sample code repo Import Grocery Sync gradle file into Android Studio Press Debug or Run button 14
  15. 15. ©2015 Couchbase Inc. 2. Download Grocery Sync Source Code 15
  16. 16. ©2015 Couchbase Inc. 3. Import ‘build.gradle’ into Android Studio 16
  17. 17. Quick Demo
  18. 18. A Tour Of The Code And The API
  19. 19. 1. Initialization & Insertion
  20. 20. ©2015 Couchbase Inc. Initialization DemoAppDelegate.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
  21. 21. ©2015 Couchbase Inc. Initialization MainActivity.java:118 manager = new Manager(new AndroidContext(this), Manager.DEFAULT_OPTIONS); database = manager.getDatabase(DATABASE_NAME); 21
  22. 22. ©2015 Couchbase Inc. Manager Top-level object, usually a singleton A collection of named databases Locates databases in filesystem 22
  23. 23. ©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”
  24. 24. ©2015 Couchbase Inc. Database Namespace for documents Contains views and their indexes Contains validation functions Source and target of replication 24
  25. 25. ©2015 Couchbase Inc. Document “_id” is unique within database, immutable JSON allows nested data structures (arrays, maps) Schemaless — Documents needn’t have the same structure Different types of docs can coexist in a database “type” property is a common convention Documents are versioned Optimistic concurrency control (MVCC) 25
  26. 26. ©2015 Couchbase Inc. Adding New Items RootViewController.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
  27. 27. ©2015 Couchbase Inc. Adding New Items MainActivity.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
  28. 28. 2. Views & Queries
  29. 29. ©2015 Couchbase Inc. Creating A Database View RootViewController.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"]; 29
  30. 30. ©2015 Couchbase Inc. Map/Reduce Views Concept from functional programming, via Google App-defined map function operates on documents doc ⟼ { (key, value) …} Its output generates an index ordered by key Index rows can be aggregated by a reduce function Index is queried by key or key range 30
  31. 31. ©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” View “byDate” 31
  32. 32. ©2015 Couchbase Inc. Creating A Database View RootViewController.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"]; 32
  33. 33. ©2015 Couchbase Inc. Creating A Database View MainActivity.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"); 33
  34. 34. ©2015 Couchbase Inc. Driving the Table from a View Query RootViewController.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
  35. 35. ©2015 Couchbase Inc. Driving the Table from a View Query RootViewController.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
  36. 36. ©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” } Query QueryRow QueryRow QueryRow .limit = 3 .offset = … .reverse = … .startKey = … .endKey = …
  37. 37. ©2015 Couchbase Inc. LiveQuery Driving An iOS UITableView 37 LiveQuery Query CBLUITable- Source UITableView Your Controller
  38. 38. ©2015 Couchbase Inc. LiveQuery Driving An iOS UITableView 38
  39. 39. ©2015 Couchbase Inc. Displaying Table Cells DemoAppDelegate.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
  40. 40. ©2015 Couchbase Inc. Displaying Table Cells GrocerySyncArrayAdapter.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 box Object check = (Object) currentRevision.getProperty("check"); boolean isGroceryItemChecked = false; if (check != null && check instanceof Boolean) isGroceryItemChecked = ((Boolean)check).booleanValue(); // Text String groceryItemText = (String) currentRevision.getProperty("text"); label.setText(groceryItemText); 40
  41. 41. ©2015 Couchbase Inc. Responding To Taps DemoAppDelegate.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
  42. 42. ©2015 Couchbase Inc. Responding To Taps MainActivity.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
  43. 43. ©2015 Couchbase Inc. Change Notifications Three types: DatabaseChanged: Any document updated DocumentChanged: A specific document updated LiveQuery: Change in query result set Enables reactive programming Controller Model (Database) GUI View User event Update doc DocumentChangedRedraw 43 Replication (pull)
  44. 44. 3. Replication
  45. 45. ©2015 Couchbase Inc. Replication 46 Replication (push) Replication (pull) https://exam.pl/db local_db
  46. 46. ©2015 Couchbase Inc. Replication Replication is asynchronous Use database notifications to detect changes A Replication can be one-shot or continuous One-shot runs only until it “catches up” Continuous keeps going till stopped or app quits Continuous handles online/offline transitions gracefully Replications can be filtered 47
  47. 47. ©2015 Couchbase Inc. Creating Replications DemoAppDelegate.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
  48. 48. ©2015 Couchbase Inc. Creating Replications MainActivity.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
  49. 49. ©2015 Couchbase Inc. Monitoring Replications DemoAppDelegate.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
  50. 50. ©2015 Couchbase Inc. Monitoring Replications MainActivity.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
  51. 51. Next Steps
  52. 52. ©2015 Couchbase Inc. Getting Started: Next Steps Try connecting Grocery Sync to your own Sync Gateway Couchbase Mobile Blog: Blog.couchbase.com Visit our mobile developer forums 53

×