Skip to content

Commit 34bc524

Browse files
committed
Performance improvements
- functions getAllContacts & getContactsByName now run inside web worker - functions getAllContacts & getContactsByName now take argument contactFields to narrow down result set scope
1 parent 0023c85 commit 34bc524

11 files changed

+449
-325
lines changed

README.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,13 @@ contacts.getContact().then(function(args){
107107
var app = require( "application" );
108108
var contacts = require( "nativescript-contacts" );
109109

110-
contacts.getContactsByName("Hicks").then(function(args){
110+
/*
111+
contactFields contains the fields to retrieve from native backend to reduce processing time
112+
var contactFields = ['name','organization','nickname','notes','photo','urls','phoneNumbers','emailAddresses','postalAddresses']
113+
*/
114+
var contactFields = ['name','phoneNumbers']
115+
116+
contacts.getContactsByName("Hicks",contactFields).then(function(args){
111117
console.log("getContactsByName Complete");
112118
console.log(JSON.stringify(args));
113119
/// Returns args:
@@ -124,7 +130,13 @@ contacts.getContactsByName("Hicks").then(function(args){
124130
var app = require( "application" );
125131
var contacts = require( "nativescript-contacts" );
126132

127-
contacts.getAllContacts().then(function(args){
133+
/*
134+
contactFields contains the fields to retrieve from native backend to reduce processing time
135+
var contactFields = ['name','organization','nickname','notes','photo','urls','phoneNumbers','emailAddresses','postalAddresses']
136+
*/
137+
var contactFields = ['name','phoneNumbers']
138+
139+
contacts.getAllContacts(contactFields).then(function(args){
128140
console.log("getAllContacts Complete");
129141
console.log(JSON.stringify(args));
130142
/// Returns args:

contact-helper.android.js

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
var appModule = require("application");
32
var KnownLabel = require("./known-label");
43

@@ -8,10 +7,24 @@ var RAW_CONTACT_ID = "raw_contact_id"; // android.provider.ContactsContract.Data
87
var CONTACT_ID = "contact_id"; // android.provider.ContactsContract.Data.CONTACT_ID
98
var MIMETYPE = "mimetype"; // android.provider.ContactsContract.Data.MIMETYPE
109

10+
/*
11+
inside a web worker appModule.android.context does not work (function by Nathanael)
12+
*/
13+
exports.getContext = function() {
14+
if (appModule.android.context) {
15+
return (appModule.android.context);
16+
}
17+
var ctx = java.lang.Class.forName("android.app.AppGlobals").getMethod("getInitialApplication", null).invoke(null, null);
18+
if (ctx) return ctx;
19+
20+
ctx = java.lang.Class.forName("android.app.ActivityThread").getMethod("currentApplication", null).invoke(null, null);
21+
return ctx;
22+
}
23+
1124
//Query Sample:
1225
//query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
1326
exports.getBasicCursor = function(uri, id){
14-
var contentResolver = appModule.android.context.getContentResolver();
27+
var contentResolver = exports.getContext().getContentResolver();
1528
var cursor = contentResolver.query(uri,
1629
null,
1730
CONTACT_ID + "=" + id,
@@ -25,7 +38,7 @@ exports.getBasicCursor = function(uri, id){
2538
//projection: String[]
2639
//parameters: String[]
2740
exports.getComplexCursor = function(id, uri, projection, parameters){
28-
var contentResolver = appModule.android.context.getContentResolver();
41+
var contentResolver = exports.getContext().getContentResolver();
2942
var cursor = contentResolver.query(uri,
3043
projection,
3144
CONTACT_ID + "=? AND " + MIMETYPE + "=?",

contact-model-common.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ var Contact = (function () {
3333
this.postalAddresses = [];
3434
}
3535

36-
Contact.prototype.initializeFromNative = function(nativeData) {
36+
Contact.prototype.initializeFromNative = function(nativeData,contactFields) {
3737
// Abstract Method
3838
};
3939

contact-model.android.js

+176-153
Large diffs are not rendered by default.

contact-model.ios.js

+14-11
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ var Contact = (function (_super) {
99
_super.apply(this, arguments);
1010
}
1111

12-
Contact.prototype.initializeFromNative = function(contactData) {
12+
Contact.prototype.initializeFromNative = function(
13+
contactData,
14+
contactFields = ['name','organization','nickname','notes','photo','urls','phoneNumbers','emailAddresses','postalAddresses']
15+
) {
1316
this.id = helper.getiOSValue("identifier", contactData);
1417

1518
//NAME
@@ -31,11 +34,11 @@ var Contact = (function (_super) {
3134

3235
this.notes = helper.getiOSValue("notes", contactData);
3336

34-
if (contactData.imageDataAvailable) {
37+
if (contactFields.indexOf('photo') > -1 && contactData.imageDataAvailable) {
3538
this.photo = imageSource.fromData(contactData.imageData);
36-
}
39+
} else { delete this.photo; }
3740

38-
if(contactData.phoneNumbers.count > 0){
41+
if(contactFields.indexOf('phoneNumbers') > -1 && contactData.phoneNumbers.count > 0) {
3942
for(var i = 0; i < contactData.phoneNumbers.count; i++){
4043
var pdata = contactData.phoneNumbers[i];
4144
this.phoneNumbers.push(
@@ -45,9 +48,9 @@ var Contact = (function (_super) {
4548
value: pdata.value.stringValue
4649
});
4750
}
48-
}
51+
} else { delete this.phoneNumbers; }
4952

50-
if(contactData.emailAddresses.count > 0){
53+
if (contactFields.indexOf('emailAddresses') > -1 && contactData.emailAddresses.count > 0) {
5154
for(var i = 0; i < contactData.emailAddresses.count; i++){
5255
var edata = contactData.emailAddresses[i];
5356
this.emailAddresses.push(
@@ -57,9 +60,9 @@ var Contact = (function (_super) {
5760
value: edata.value
5861
});
5962
}
60-
}
63+
} else { delete this.emailAddresses; }
6164

62-
if(contactData.postalAddresses.count > 0){
65+
if (contactFields.indexOf('postalAddresses') > -1 && contactData.postalAddresses.count > 0) {
6366
for(var i = 0; i < contactData.postalAddresses.count; i++){
6467
var postaldata = contactData.postalAddresses[i];
6568
this.postalAddresses.push(
@@ -77,9 +80,9 @@ var Contact = (function (_super) {
7780
}
7881
});
7982
}
80-
}
83+
} else { delete this.postalAddresses; }
8184

82-
if(contactData.urlAddresses.count > 0){
85+
if (contactFields.indexOf('urlAddresses') > -1 && contactData.urlAddresses.count > 0) {
8386
for(var i = 0; i < contactData.urlAddresses.count; i++){
8487
var urldata = contactData.urlAddresses[i];
8588
this.urls.push(
@@ -88,7 +91,7 @@ var Contact = (function (_super) {
8891
value: urldata.value
8992
});
9093
}
91-
}
94+
} else { delete this.urlAddresses; }
9295
};
9396

9497
Contact.prototype.save = function () {

get-all-contacts-worker.android.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
require('globals'); // necessary to bootstrap tns modules on the new thread
2+
var Contact = require("./contact-model");
3+
var helper = require("./contact-helper");
4+
5+
/* pass debug messages to main thread since web workers do not have console access */
6+
function console_log(msg) { postMessage({ type: 'debug', message: msg }); }
7+
function console_dump(msg) { postMessage({ type: 'dump', message: msg }); }
8+
9+
self.onmessage = function (event) {
10+
// console_log('message received from main script');
11+
// console_dump(event.data);
12+
13+
var c = helper.getContext().getContentResolver().query(android.provider.ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
14+
15+
if(c.getCount() > 0){
16+
var cts = [];
17+
while(c.moveToNext()){
18+
var contactModel = new Contact();
19+
contactModel.initializeFromNative(c,event.data.contactFields);
20+
cts.push(contactModel);
21+
}
22+
c.close();
23+
postMessage({ type: 'result', message: { data: cts, response: "fetch" }});
24+
} else {
25+
c.close();
26+
postMessage({ type: 'result', message: { data: null, response: "fetch" }});
27+
}
28+
}

get-all-contacts-worker.ios.js

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
require('globals'); // necessary to bootstrap tns modules on the new thread
2+
var Contact = require("./contact-model");
3+
var helper = require("./contact-helper");
4+
5+
/* pass debug messages to main thread since web workers do not have console access */
6+
function console_log(msg) { postMessage({ type: 'debug', message: msg }); }
7+
function console_dump(msg) { postMessage({ type: 'dump', message: msg }); }
8+
9+
self.onmessage = function (event) {
10+
// console_log('message received from main script');
11+
// console_dump(event.data);
12+
contactFields = event.data.contactFields;
13+
14+
var keysToFetch = []; // All Properties that we are using in the Model
15+
if (contactFields.indexOf('name') > -1) {
16+
keysToFetch.push(
17+
"givenName", "familyName", "middleName", "namePrefix", "nameSuffix",
18+
"phoneticGivenName", "phoneticMiddleName", "phoneticFamilyName"
19+
);
20+
}
21+
22+
if (contactFields.indexOf('organization') > -1) { keysToFetch.push("jobTitle", "departmentName", "organizationName"); }
23+
if (contactFields.indexOf('nickname') > -1) { keysToFetch.push("nickname"); }
24+
if (contactFields.indexOf('notes') > -1) { keysToFetch.push("notes"); }
25+
if (contactFields.indexOf('photo') > -1) { keysToFetch.push("imageData", "imageDataAvailable"); }
26+
if (contactFields.indexOf('phoneNumbers') > -1) { keysToFetch.push("phoneNumbers"); }
27+
if (contactFields.indexOf('emailAddresses') > -1) { keysToFetch.push("emailAddresses"); }
28+
if (contactFields.indexOf('postalAddresses') > -1) { keysToFetch.push("postalAddresses"); }
29+
if (contactFields.indexOf('urlAddresses') > -1) { keysToFetch.push("urlAddresses"); }
30+
31+
var store = new CNContactStore(),
32+
error,
33+
fetch = CNContactFetchRequest.alloc().initWithKeysToFetch(keysToFetch),
34+
cts = [],
35+
nativeMutableArray = new NSMutableArray();
36+
37+
fetch.unifyResults = true;
38+
fetch.predicate = null;
39+
40+
store.enumerateContactsWithFetchRequestErrorUsingBlock(fetch, error, function(c,s){
41+
nativeMutableArray.addObject(c);
42+
var contactModel = new Contact();
43+
contactModel.initializeFromNative(c,contactFields);
44+
cts.push(contactModel);
45+
});
46+
47+
if(error) { postMessage({ type: 'error', message: error }); }
48+
if(cts.length > 0) { postMessage({ type: 'result', message: { data: cts, response: "fetch" }}); }
49+
else { postMessage({ type: 'result', message: { data: null, response: "fetch" }}); }
50+
}
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
require('globals'); // necessary to bootstrap tns modules on the new thread
2+
var Contact = require("./contact-model");
3+
var helper = require("./contact-helper");
4+
5+
/* pass debug messages to main thread since web workers do not have console access */
6+
function console_log(msg) { postMessage({ type: 'debug', message: msg }); }
7+
function console_dump(msg) { postMessage({ type: 'dump', message: msg }); }
8+
9+
self.onmessage = function (event) {
10+
// console_log('message received from main script');
11+
// console_dump(event.data);
12+
13+
var Contacts = android.provider.ContactsContract.Contacts,
14+
SELECTION = android.provider.ContactsContract.ContactNameColumns.DISPLAY_NAME_PRIMARY,
15+
c = helper.getContext().getContentResolver().query(
16+
Contacts.CONTENT_URI,
17+
null,
18+
SELECTION + " like ?",
19+
["%" + event.data.searchPredicate + "%"],
20+
null
21+
);
22+
23+
if(c.getCount() > 0){
24+
var cts = [];
25+
while(c.moveToNext()){
26+
var contactModel = new Contact();
27+
contactModel.initializeFromNative(c,event.data.contactFields);
28+
cts.push(contactModel);
29+
}
30+
c.close();
31+
postMessage({ type: 'result', message: { data: cts, response: "fetch" }});
32+
}
33+
else{
34+
c.close();
35+
postMessage({ type: 'result', message: { data: null, response: "fetch" }});
36+
}
37+
}

get-contacts-by-name-worker.ios.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
require('globals'); // necessary to bootstrap tns modules on the new thread
2+
var Contact = require("./contact-model");
3+
var helper = require("./contact-helper");
4+
5+
/* pass debug messages to main thread since web workers do not have console access */
6+
function console_log(msg) { postMessage({ type: 'debug', message: msg }); }
7+
function console_dump(msg) { postMessage({ type: 'dump', message: msg }); }
8+
9+
self.onmessage = function (event) {
10+
// console_log('message received from main script');
11+
// console_dump(event.data);
12+
contactFields = event.data.contactFields;
13+
14+
var keysToFetch = []; // All Properties that we are using in the Model
15+
if (contactFields.indexOf('name') > -1) {
16+
keysToFetch.push(
17+
"givenName", "familyName", "middleName", "namePrefix", "nameSuffix",
18+
"phoneticGivenName", "phoneticMiddleName", "phoneticFamilyName"
19+
);
20+
}
21+
22+
if (contactFields.indexOf('organization') > -1) { keysToFetch.push("jobTitle", "departmentName", "organizationName"); }
23+
if (contactFields.indexOf('nickname') > -1) { keysToFetch.push("nickname"); }
24+
if (contactFields.indexOf('notes') > -1) { keysToFetch.push("notes"); }
25+
if (contactFields.indexOf('photo') > -1) { keysToFetch.push("imageData", "imageDataAvailable"); }
26+
if (contactFields.indexOf('phoneNumbers') > -1) { keysToFetch.push("phoneNumbers"); }
27+
if (contactFields.indexOf('emailAddresses') > -1) { keysToFetch.push("emailAddresses"); }
28+
if (contactFields.indexOf('postalAddresses') > -1) { keysToFetch.push("postalAddresses"); }
29+
if (contactFields.indexOf('urlAddresses') > -1) { keysToFetch.push("urlAddresses"); }
30+
31+
var store = new CNContactStore(),
32+
error,
33+
foundContacts = store.unifiedContactsMatchingPredicateKeysToFetchError(
34+
CNContact.predicateForContactsMatchingName(event.data.searchPredicate),
35+
keysToFetch,
36+
error
37+
);
38+
39+
if(error) { postMessage({ type: 'error', message: error }); }
40+
41+
42+
if (foundContacts.count > 0) {
43+
var cts = [];
44+
for(var i=0; i<foundContacts.count; i++){
45+
var contactModel = new Contact();
46+
contactModel.initializeFromNative(foundContacts[i],contactFields);
47+
cts.push(contactModel);
48+
}
49+
postMessage({ type: 'result', message: { data: cts, response: "fetch" }});
50+
}
51+
else { postMessage({ type: 'result', message: { data: null, response: "fetch" }}); }
52+
}

0 commit comments

Comments
 (0)