NativeScript — это платформа для создания кроссплатформенных собственных мобильных приложений с использованием XML, CSS и JavaScript. В этой серии мы попробуем некоторые интересные вещи, которые вы можете сделать с помощью приложения NativeScript: геолокация и интеграция с Google Maps, база данных SQLite, интеграция с Firebase и push-уведомления. Попутно мы создаем фитнес-приложение с возможностями реального времени, которое будет использовать каждую из этих функций.
В этом руководстве вы узнаете, как интегрировать базу данных SQLite в приложение для локального хранения данных. В частности, мы будем хранить данные о сессиях ходьбы, которые мы собрали в предыдущем уроке .
Что вы будете создавать
Продолжая предыдущий урок, вы добавите представление вкладок для отображения различных частей приложения. Ранее в нашем приложении была страница отслеживания , поэтому нам не нужны вкладки. В этом посте мы добавим страницу » Прогулки» . На этой странице будут отображаться сеансы ходьбы пользователя. Новая точка данных будет добавляться здесь каждый раз, когда пользователь отслеживает ход их прогулки. Также будет функция очистки данных.
Вот как будет выглядеть окончательный результат:
Настройка проекта
Если вы следовали предыдущему учебнику по геолокации , вы можете просто использовать тот же проект и создать функции, которые мы добавим в этом учебнике. В противном случае вы можете создать новый проект и скопировать начальные файлы в папку приложения вашего проекта.
1
|
tns create fitApp —appid «com.yourname.fitApp»
|
После этого вам также необходимо установить плагины геолокации и Google Maps:
1
2
|
tns plugin add nativescript-geolocation
tns plugin add nativescript-google-maps-sdk
|
После установки вам необходимо настроить плагин Google Maps. Вы можете прочитать подробные инструкции о том, как это сделать, прочитав раздел « Установка плагина Google Maps» в предыдущем руководстве .
Как только все это будет сделано, вы должны быть готовы следовать этому уроку.
Запуск проекта
Вы можете запустить проект, выполнив tns run android
. Но так как это приложение будет основано на функциональности геолокации, я рекомендую вам использовать эмулятор GPS для быстрой настройки и изменения вашего местоположения. Вы можете прочитать о том, как это сделать, в разделе « Запуск приложения» в предыдущем руководстве .
Установка плагина SQLite
Первое, что вам нужно сделать, чтобы начать работать с SQLite, это установить плагин :
1
|
tns plugin add nativescript-sqlite
|
Это позволяет вам выполнять такие вещи, как подключение к базе данных и выполнение операций CRUD (создание, чтение, обновление, удаление) над ней.
Подключение к базе данных
Откройте файл main-page.js и импортируйте плагин SQLite:
1
|
var Sqlite = require(«nativescript-sqlite»);
|
Теперь вы можете подключиться к базе данных:
1
2
3
4
5
6
7
|
var db_name = «walks.db»;
new Sqlite(db_name).then(db => {
// next: create table for storing walks data
}, error => {
});
|
Файл walks.db был создан из терминала с помощью touch
команды, поэтому это просто пустой файл. Скопируйте его в папку приложения .
Если он успешно подключен, функция разрешения обещания будет выполнена. Внутри этого мы запускаем оператор SQL для создания таблицы walks
. Для простоты все, что нам нужно сохранить, это общее пройденное расстояние (в метрах) и общее количество шагов, а также метки времени начала и окончания.
1
2
3
4
5
|
db.execSQL(«CREATE TABLE IF NOT EXISTS walks (id INTEGER PRIMARY KEY AUTOINCREMENT, total_distance INTEGER, total_steps INTEGER, start_datetime DATETIME, end_datetime DATETIME)»).then(id => {
page.bindingContext = createViewModel(db);
}, error => {
console.log(«CREATE TABLE ERROR», error);
});
|
После успешного выполнения запроса мы передаем экземпляр базы данных ( db
) в контекст страницы. Это позволит нам использовать его из файла main-view-model.js позже.
Получение данных
Теперь мы готовы работать с данными. Но так как мы будем работать с датами, нам сначала нужно установить библиотеку с именем fecha . Это позволяет нам легко разбирать и форматировать даты:
1
|
npm install —save fecha
|
После установки откройте файл main-view-model.js и включите библиотеку:
1
|
var fecha = require(‘fecha’);
|
Далее идет код для проверки, включена ли геолокация. Сначала создайте переменную ( walk_id
) для хранения идентификатора прогулочной записи. Нам это нужно, потому что приложение сразу вставит новую запись ходьбы в таблицу walks
когда пользователь начнет отслеживать местоположение. walk_id
будет хранить идентификатор, автоматически сгенерированный SQLite, так что мы сможем обновить запись, как только пользователь прекратит отслеживать.
1
|
var walk_id;
|
Далее получаем текущий месяц и год. Мы будем использовать его для запроса к таблице, чтобы он возвращал только записи, относящиеся к одному и тому же месяцу и году. Это позволяет нам ограничивать количество записей, отображаемых в пользовательском интерфейсе.
1
2
|
var month = fecha.format(new Date(), ‘MM’);
var year = fecha.format(new Date(), ‘YYYY’);
|
Нам также нужна переменная для хранения начальной отметки времени. Мы будем использовать его позже для обновления пользовательского интерфейса. Это потому, что мы запрашиваем таблицу только один раз при загрузке приложения, поэтому нам нужно вручную обновлять пользовательский интерфейс любых новых данных, которые становятся доступными. И поскольку начальная временная метка будет иметь значение только тогда, когда пользователь начнет отслеживать, нам нужно инициализировать ее вне области действия, чтобы мы могли обновить или получить доступ к ее значению позже.
1
|
var st_datetime;
|
Инициализируйте данные прогулок, которые будут отображаться в пользовательском интерфейсе:
1
2
3
|
var walks = [];
viewModel.walks = [];
viewModel.has_walks = false;
|
Получите данные из таблицы walks
используя метод all()
. Здесь мы предоставляем месяц и год в качестве параметров запроса. Функция strftime()
используется для извлечения части месяца и года из start_datetime
.
1
2
3
4
5
6
7
8
9
|
db.all(
«SELECT * FROM walks WHERE strftime(‘%m’, start_datetime) == ? AND strftime(‘%Y’, start_datetime) == ? ORDER BY start_datetime DESC»,
[month, year]
).then((err, rs) => {
if(!err){
// next: update the UI with the walks data
}
});
|
Как только возвращается ответ об успешном выполнении, мы перебираем набор результатов, чтобы правильно отформатировать данные. Обратите внимание, что индексы, в которых мы получаем доступ к отдельным значениям, зависят от структуры таблицы, которая была описана ранее в файле main-page.js . Первый столбец — ID, второй — общее расстояние и так далее.
Отформатированные данные затем передаются в массив walks
и используются для обновления пользовательского интерфейса. has_walks
используется в качестве переключателя для пользовательского интерфейса, так что мы можем показать или скрыть вещи, основываясь на его значении.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
rs.forEach((w) => {
let start_datetime = new Date(w[3]);
let end_datetime = new Date(w[4]);
walks.push({
start: fecha.format(start_datetime, ‘MMM D, h:mm’), // eg Jun 5, 5:30
end: fecha.format(end_datetime, ‘h:mm a’), // eg 6:30 pm
distance: commafy(w[1]) + ‘m’, // eg 2,000m
steps: commafy(w[2]) // eg 2,300
});
});
if(walks.length){
viewModel.set(‘has_walks’, true);
}
viewModel.set(‘walks’, walks);
|
Это предоставит данные для ListView
в файле main-page.xml :
1
2
3
4
5
6
7
8
9
|
<ListView items=»{{ walks }}»>
<ListView.itemTemplate>
<GridLayout columns=»2*,*,*» rows=»auto» class=»item item-row»>
<Label text=»{{ start + ‘ — ‘ + end }}» textWrap=»true» row=»0″ col=»0″/>
<Label text=»{{ distance }}» textWrap=»true» row=»0″ col=»1″ />
<Label text=»{{ steps }}» textWrap=»true» row=»0″ col=»2″ />
</GridLayout>
</ListView.itemTemplate>
</ListView>
|
Сохранение данных
Как только пользователь начнет отслеживать, установите текущую дату и время как start_datetime
и вставьте начальные значения в таблицу, используя execSQL()
. Как и функция all()
, она ожидает SQL-запрос в качестве первого аргумента и массив параметров в качестве второго.
Если запрос выполнен успешно, он должен вернуть автоматически сгенерированный идентификатор для вставленной записи. Затем мы присваиваем его как значение для walk_id
чтобы его можно было использовать позже для обновления этой конкретной записи.
01
02
03
04
05
06
07
08
09
10
11
|
st_datetime = new Date();
var start_datetime = fecha.format(st_datetime, ‘YYYY-MM-DD HH:mm:ss’);
db.execSQL(
«INSERT INTO walks (total_distance, total_steps, start_datetime) VALUES (?, ?, ?)»,
[0, 0, start_datetime]
).then((id) => {
walk_id = id;
}, (e) => {
dialogs.alert(e.message);
});
|
Когда пользователь прекращает отслеживание, мы снова получаем текущую временную метку и форматируем ее соответственно для хранения:
1
2
|
var ed_datetime = new Date();
var end_datetime = fecha.format(ed_datetime, ‘YYYY-MM-DD HH:mm:ss’);
|
Поскольку мы упорядочили результаты от самых последних до самых последних, мы используем unshift()
(вместо push()
), чтобы добавить новый элемент в верхнюю часть массива walks
.
01
02
03
04
05
06
07
08
09
10
11
|
walks.unshift({
start: fecha.format(st_datetime, ‘MMM D, h:mm’),
end: fecha.format(ed_datetime, ‘h:mm a’),
distance: commafy(total_distance) + ‘m’,
steps: commafy(total_steps)
});
viewModel.set(‘walks’, walks);
if(walks.length > 0){
viewModel.set(‘has_walks’, true);
}
|
После этого мы снова используем execSQL()
для обновления записи, которую мы вставили ранее:
01
02
03
04
05
06
07
08
09
10
|
db.execSQL(
«UPDATE walks SET end_datetime = ?, total_steps = ?, total_distance = ? WHERE id = ?»,
[end_datetime, total_steps, total_distance, walk_id]
).then(
(err, id) => {
if(!err){
// todo: add code for resetting the tracking UI here
}
}
);
|
Обязательно переместите код для сброса пользовательского интерфейса отслеживания (для сброса общего расстояния и шагов) в функцию разрешения обещания, чтобы вы могли легко проверить, успешно ли выполнен запрос на обновление.
Очистка данных
Удаление данных выполняется нажатием на кнопку « Очистить данные» под списком данных об обходе:
1
2
3
4
|
<ListView items=»{{ walks }}»>
…
</ListView>
<Button text=»Clear Data» tap=»{{ clearData }}» class=»bg-danger» />
|
В файле main-view-model.js добавьте код для удаления всех данных из таблицы walks
. Если вы привыкли к MySQL, вам может быть интересно, почему мы используем запрос DELETE
вместо TRUNCATE
для очистки таблицы. Ну, это потому, что SQLite не имеет функции TRUNCATE
. Вот почему мы должны использовать запрос DELETE
без указания условия, чтобы он удалял все записи, которые в данный момент находятся в таблице.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
viewModel.clearData = function() {
dialogs.confirm(«Are you sure you want to clear your data?»).then((agree) => {
if(agree){
db.execSQL(«DELETE FROM walks», []).then(
(err) => {
if(!err){
dialogs.alert(«Data has been cleared!»);
walks = [];
viewModel.set(‘walks’, []);
viewModel.set(‘has_walks’, false);
}
}
);
}
});
}
|
Вывод
Из этого руководства вы узнали, как локально хранить данные в своих приложениях NativeScript с помощью плагина SQLite. Как вы уже видели, SQLite позволяет вам повторно использовать имеющиеся у вас навыки SQL в управлении локальной базой данных. Важно отметить, что не все функции, к которым вы привыкли в MySQL, поддерживаются в SQLite. Поэтому всегда полезно обратиться к документации, если вы не уверены, поддерживается ли определенная функция или нет.
Если вы хотите узнать о других возможностях хранения данных в приложениях NativeScript, я рекомендую вам прочитать эту статью в статье « Переход в автономный режим с помощью NativeScript» .
В последнем посте этой серии мы добавим push-уведомления в наше приложение.
А пока посмотрите другие наши посты о NativeScript и кроссплатформенном мобильном кодировании.
-
Мобильное приложениеСоздайте приложение погоды с TypeScript и NativeScript
-
Мобильная разработкаПредставляем Vue и Weex для собственных мобильных приложений
-
ионныйНачните с Ionic Services: Auth
Для всестороннего знакомства с NativeScript попробуйте наш видеокурс « Код мобильного приложения с NativeScript» . В этом курсе Keyvan Kasaei шаг за шагом покажет вам, как создать простое приложение. Попутно вы узнаете, как реализовать простой рабочий процесс приложения с сетевыми запросами, архитектурой MVVM и некоторыми из наиболее важных компонентов пользовательского интерфейса NativeScript. В конце вы поймете, почему вы должны рассмотреть NativeScript для вашего следующего проекта мобильного приложения.