Статьи

Создание облачного бэкенда для вашего Android-приложения с помощью Parse

Ранее мы опубликовали статью об использовании Parse для предоставления бэкенда для приложений для iOS и решили, что нам следует написать статью для разработчиков Android, которые хотят знать, как интегрировать Parse SDK в свое приложение.

Если вы читали предыдущую статью, вы можете пропустить введение. Мы хотели, чтобы статьи были самостоятельными учебниками, поэтому вам не нужно читать предыдущую, чтобы следовать этой.

Вступление

С ростом использования мобильных устройств приложения обычно предлагают такие функции, как резервное хранилище, синхронизация данных, обмен данными и т. Д. Создание автономных приложений, которые работают и сохраняют свои данные только на том устройстве, на котором они установлены, иногда не возможно. Обычно требуется серверная часть, где данные можно сохранять и манипулировать ими, чтобы приложение предоставило услугу, для которой оно предназначалось.

Создание этого требует времени, другого набора навыков и других ресурсов (например, серверов, служб push-уведомлений и т. Д.). К счастью, есть несколько платформ, которые предоставляют готовые настраиваемые бэкэнды, которые вы можете интегрировать со своими приложениями. Они известны как «Backend as a Service», или, вкратце, BaaS.

Плюсы и минусы использования BaaS

Pros

  • Экономит время и ресурсы.
  • Предоставляет разные услуги в одном пакете. Большинство доступных поставщиков BaaS предоставляют не только облачное хранилище для ваших данных, но и такие услуги, как push-уведомления, аналитика, интеграция с социальными сетями и т. Д.
  • Обслуживает масштабирование. Платформы BaaS созданы для масштабирования, и, как разработчик, вам не нужно будет выполнять дополнительную работу, если вы хотите привлечь большое количество пользователей. Это будет стоить вам больше, хотя, как вы можете двигаться вверх по тарифному плану.
  • Легко вносить изменения. Вы можете легко вносить изменения в функциональность вашего приложения, не требуя много переписывать его бэкэнд. Модели базы данных легко изменить с помощью панели инструментов платформы. Это пригодится всем, кто следует итеративной методике «бережного стартапа» доставки и улучшения приложения на основе данных об использовании.

Cons

  • Использование BaaS может быть дорогим. Хотя большинство из этих сервисов предлагают бесплатный пакет для определенного количества запросов в месяц, оно может стоить дорого, если ваше приложение взлетело и набрало много пользователей.
  • Вы можете столкнуться с блокировкой поставщика, когда переход на другую платформу затруднен Но это становится меньшей проблемой, так как большинство сервисов созданы для облегчения миграции. Возможно, вам придется отказаться от некоторых услуг, поскольку не все платформы BaaS предлагают одинаковые услуги.
  • Огромным недостатком, который следует учитывать перед использованием BaaS, является зависимость вашего приложения от стороннего сервиса. Поставщик может внести изменения в свою услугу, которые вам придется либо терпеть, либо искать другое решение. Существует также возможность закрытия службы, что будет очень неудобно, так как вы будете вынуждены перенести свои данные другому провайдеру или на свой сервер. Примером этого является недавнее отключение StackMob, которое вынудило разработчиков переносить свои данные.

Введите Parse

В этом уроке мы рассмотрим использование Parse для предоставления серверной части для приложения Android. Мы кратко рассмотрим, что он предлагает, прежде чем создавать приложение, которое будет использовать его для регистрации пользователей, аутентификации и хранения пользовательских данных.

Parse — одна из самых популярных платформ Backend as a Service. Сервис предлагает три продукта в одном пакете: Parse Core, Parse Push и Parse Analytics.

Parse Core, как правило, обеспечивает сохранение данных и интеграцию с социальными сетями.

Parse Push используется для отправки push-уведомлений. Это позволяет разработчику настраивать, планировать и отправлять push-уведомления всем зарегистрированным пользователям или избранной группе пользователей.

Parse Analytics позволяет отслеживать данные вашего приложения. Вы можете отслеживать данные об использовании, такие как установки, активные пользователи, сохранение пользователей, скорость открытия push-уведомлений и т. Д.

Сборка приложения

Вы можете найти код для приложения, которое мы создаем здесь . Если у вас есть какие-либо проблемы с кодом или зависимостями, здесь есть несколько дополнительных рекомендаций .

Мы создадим простое приложение для создания заметок, которое позволит пользователю сохранять и извлекать заметки в облако, поддерживая тем самым одинаковые данные на разных устройствах. Мы также рассмотрим, как заставить приложение работать в автономном режиме, используя функцию Parse Local Datastore, которая является новой функцией, добавленной в Parse Android SDK.

Для начала вы должны сначала создать учетную запись на parse.com, если у вас ее еще нет. После входа в систему откройте панель инструментов, где вы сможете создать новое приложение, а также увидеть список всех создаваемых вами приложений.

Создайте приложение под названием NoteApp .

parse_android_01

После создания приложения вы увидите окно, содержащее идентификаторы и ключи вашего приложения. Они будут использованы позже в приложении для Android.

parse_android_02

Загрузите Parse SDK здесь . Распакуйте его содержимое в папку libs вашего проекта.

Создайте новый проект Android. Я назвал свой NoteApp и установил минимально необходимый SDK для API версии 11. В окне « Создать действие» выберите « Пустое действие» .

Далее мы создадим собственный класс Application . Класс Application — это то, что сначала загружается при запуске приложения. По умолчанию Android использует общий класс Application , но мы создадим наш собственный, чтобы выполнить некоторые начальные настройки.

Создайте новый класс с именем NoteAppApplication и установите android.app.Application качестве его суперкласса.

В файле AndroidManifest.xml задайте имя атрибута application с именем класса, которое вы только что создали.

 <application android:name="com.echessa.noteapp.NoteAppApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > 

Скопируйте файл Parse-xxxjar из извлеченной загрузки в папку libs . Если вы используете Android Studio, не забудьте добавить зависимость в файл build.gradle .

В файле манифеста добавьте следующие разрешения перед тегом application .

 <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 

В классе Application добавьте метод onCreate() со следующим кодом.

 @Override public void onCreate() { super.onCreate(); Parse.initialize(this, APPLICATION_ID, CLIENT_KEY); ParseObject testObject = new ParseObject("TestObject"); testObject.put("foo", "bar"); testObject.saveInBackground(); } 

Замените заполнители, указанные выше, на идентификатор приложения и ключ клиента, их можно найти на панели инструментов Parse. Код, который мы поместили после инициализации Parse, предназначен только для тестирования. Мы удалим его, как только установим, что приложение сохранило данные в Parse.

Организуйте импорт в файл с помощью Ctrl+Shift+O (Вы можете настроить Eclipse и Android Studio, чтобы сделать это автоматически, чтобы сэкономить время при наборе текста. Импортировать вам придется только тогда, когда есть конфликтующая библиотека). В этой статье я не буду указывать необходимый импорт, если нет потенциальных конфликтов.

Запустите приложение и перейдите на панель анализа Parse в своем браузере. Выберите ваше приложение и нажмите на вкладку Браузер данных. Вы должны увидеть данные таблицы объекта, который был создан выше.

parse_android_03

На панели инструментов вы найдете элементы управления для добавления / удаления строк и столбцов, установки разрешений, экспорта класса и даже удаления всего класса. TestObject класс TestObject как он нам не понадобится для нашего приложения. Удалите его, нажав кнопку « Дополнительно» и выбрав « Удалить класс» . Также удалите код, который создает TestObject при запуске приложения.

Вы можете не только создавать объекты программно, как мы делали выше, но вы также можете делать это с помощью панели инструментов. Мы собираемся создать класс Post и несколько тестовых записей, которые будут загружены в наше приложение.

Нажмите на кнопку New Class и назовите класс Post . Оставьте тип как пользовательский . Добавьте два строковых столбца: title и content . Добавьте несколько строк данных, просто заполните поля заголовка и содержимого.

Помимо столбцов title и content также генерируются другие столбцы — objectId, creationAt, updatedAt и ACL. ACL расшифровывается как списки контроля доступа. Они используются для указания контроля доступа, который пользователи и / или роли имеют в определенных объектах.

Вернувшись в наше приложение, мы собираемся загрузить данные в виде списка. В представлении списка будут отображаться заголовки поста, а при нажатии содержимое выбранного поста будет отображаться в другом действии. Для простоты мы будем использовать один и тот же вид для просмотра и редактирования текста.

Обратите внимание, что мы будем создавать простое приложение с дизайном, не очень подходящим для нескольких экранов . Для разработки нескольких экранов используйте фрагменты для реализации правильного потока основных деталей.

Удалите код в onCreate() выше, который создает ParseObject и сохраняет его.

Откройте файл activity_main.xml и удалите TextView представление Hello World. Поместите представление списка в действие. Измените его атрибут id на @android:id/list . Это необходимо, так как мы будем использовать ListActivity с пользовательским макетом для нашего представления. Удалите отступы, которые были установлены в макете, и установите ширину и высоту представления match_parent wrap_content match_parent и wrap_content соответственно. Настройки показаны ниже.

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" > </ListView> </RelativeLayout> 

Измените класс MainActivity так, чтобы он ListActivity . Это действие, которое отображает список элементов путем привязки к источнику данных. Он имеет макет по умолчанию с одним полноэкранным списком в центре экрана, но мы будем использовать пользовательский макет, и поэтому мы устанавливаем android:id="@android:id/list" в элементе ListView. в деятельности выше.

Мы будем стилизовать элементы списка в нашем представлении списка, чтобы отобразить заголовок сообщения и значок. Создайте файл res/layout папке res/layout именем list_item_layout.xml . Поместите в него TextView со следующими настройками

 <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:padding="5dp" android:singleLine="true" android:textSize="20sp" android:ellipsize="end" android:drawableRight="@drawable/ic_action_edit"> </TextView> 

Значок ic_action_edit находится в ic_action_edit значков ic_action_edit действий на веб-сайте разработчика Android. Я использовал голографическую версию. Вы также можете использовать этот инструмент для создания иконок.

Создайте класс, который будет содержать наши данные Post. Назовите это Note.java . Это простое приложение с полями id заметки, content и title их получателями и установщиками.

 package com.echessa.noteapp; public class Note { private String id; private String title; private String content; Note(String noteId, String noteTitle, String noteContent) { id = noteId; title = noteTitle; content = noteContent; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } 

В MainActivity.java объявите переменную класса, которая будет содержать список заметок.

 private List<Note> posts; 

Затем отредактируйте метод onCreate() в том же файле, как показано ниже.

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); posts = new ArrayList<Note>(); ArrayAdapter<Note> adapter = new ArrayAdapter<Note>(this, R.layout.list_item_layout, posts); setListAdapter(adapter); refreshPostList(); } 

Здесь мы создаем адаптер, который управляет моделью данных и адаптирует ее к отдельным строкам в представлении списка. Для этого мы используем ArrayAdapter . Это сопоставляет метод toString() объекта с TextView в макете строки. Чтобы поддерживать другие представления или иметь данные, отличные от объекта toString() , вы должны создать собственный адаптер. Мы будем использовать данный адаптер и переопределить метод toString() нашего объекта, чтобы он давал название заметки.

В Note.java добавьте следующий метод.

 @Override public String toString() { return this.getTitle(); } 

Затем добавьте метод refreshPostList() в класс. Когда это вызывается, он будет извлекать данные из Parse и назначать их в список posts .

 private void refreshPostList() { ParseQuery<ParseObject> query = ParseQuery.getQuery("Post"); query.findInBackground(new FindCallback<ParseObject>() { @Override public void done(List<ParseObject> postList, ParseException e) { if (e == null) { // If there are results, update the list of posts // and notify the adapter posts.clear(); for (ParseObject post : postList) { Note note = new Note(post.getObjectId(), post.getString("title"), post.getString("content")); posts.add(note); } ((ArrayAdapter<Note>) getListAdapter()).notifyDataSetChanged(); } else { Log.d(getClass().getSimpleName(), "Error: " + e.getMessage()); } } }); } 

Запустите приложение, и представление списка будет заполнено заметками, которые вы добавили ранее в Parse.

parse_android_04

Во время загрузки данных происходит небольшая пауза. Мы дадим пользователю указание на это, включая загрузочный счетчик.

Добавьте следующее после super.onCreate(savedInstanceState); оператор в onCreate() .

 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 

В refreshPostList() добавьте следующее перед вызовом findInBackground()

 setProgressBarIndeterminateVisibility(true); 

Это покажет управление счетчиком прогресса. После загрузки данных нам нужно это скрыть. Поместите следующее как первый оператор в done методе.

 setProgressBarIndeterminateVisibility(false); 

Далее мы добавим два действия панели действий, чтобы обновить список и добавить новую заметку. В res/menu/main.xml добавьте следующее.

 <item android:id="@+id/action_refresh" android:icon="@drawable/ic_action_refresh" android:showAsAction="always|withText" android:title="@string/action_refresh"> </item> <item android:id="@+id/action_new" android:showAsAction="always|withText" android:title="@string/action_new" android:icon="@drawable/ic_action_new"/> 

Затем добавьте следующие значения в файл res/values/strings.xml .

 <string name="action_new">New Note</string> <string name="action_refresh">Refresh</string> 

Я использовал иконки из ранее упомянутого набора иконок из папки темы holo-dark.

parse_android_05

Далее мы создадим новое действие для добавления и редактирования заметок. Вы можете иметь отдельные действия для просмотра и редактирования заметок, но для простоты мы будем использовать один вид для этого.

Щелкните правой кнопкой мыши по вашему проекту и выберите New -> Other, чтобы открыть мастер создания нового файла. В раскрывающемся меню Android выберите Android Activity . На следующей странице выберите Пустое действие . Назовите действие EditNoteActivity и измените заголовок на « Добавить / изменить» . Нажмите Готово, чтобы добавить файлы в ваш проект. Это добавит код и файлы макета для действия, а также изменит файлы strings.xml и AndroidManifest.xml с необходимыми данными для действия.

В MainActivity.java добавьте следующий код для обработки щелчков элементов панели действий.

 @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); switch (id) { case R.id.action_refresh: { refreshPostList(); break; } case R.id.action_new: { Intent intent = new Intent(this, EditNoteActivity.class); startActivity(intent); break; } case R.id.action_settings: { // Do something when user selects Settings from Action Bar overlay break; } } return super.onOptionsItemSelected(item); } 

Запустите приложение, и вы сможете обновить список сообщений и перейти к новому действию, используя действия на панели действий.

Отредактируйте файл res/layout/activity_edit_note.xml как показано ниже. Мы изменили макет с RelativeLayout на LinearLayout и добавили два поля EditText и кнопку.

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="16dp" android:paddingRight="16dp" android:orientation="vertical" > <EditText android:id="@+id/noteTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:hint="@string/note_title_hint" /> <EditText android:id="@+id/noteContent" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="top" android:hint="@string/note_content_hint" android:ems="10" /> <Button android:id="@+id/saveNote" android:layout_width="100dp" android:layout_height="wrap_content" android:layout_gravity="right" android:text="@string/save_button" /> </LinearLayout> 

Добавьте следующее в файл strings.xml .

 <string name="note_title_hint">Title</string> <string name="note_content_hint">Content</string> <string name="save_button">Save</string> 

Когда мы запускаем приложение и переходим к представлению «Добавить / редактировать», мы должны использовать кнопку «Назад», чтобы вернуться к нашему представлению списка. Мы добавим курсор вверх на панель действий, чтобы мы могли вернуться к нашему родительскому виду. В файле манифеста измените EditNoteActivity активности EditNoteActivity как показано.

 <activity android:name=".EditNoteActivity" android:label="@string/title_activity_edit_note" > <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.echessa.noteapp.MainActivity" /> </activity> 

Добавьте следующее в метод onCreate() файла EditNoteActivity.java сразу после вызова super.onCreate(savedInstanceState); ,

 getActionBar().setDisplayHomeAsUpEnabled(true); 

При запуске приложения вы должны увидеть левую каретку рядом со значком приложения, который при нажатии перемещается вверх по иерархии.

parse_android_05

parse_android_06

В MainActivity.java мы MainActivity.java пользователю возможность выбрать элемент списка и увидеть его детали в представлении «Добавить / изменить». Добавьте следующий метод в файл.

 @Override protected void onListItemClick(ListView l, View v, int position, long id) { Note note = posts.get(position); Intent intent = new Intent(this, EditNoteActivity.class); intent.putExtra("noteId", note.getId()); intent.putExtra("noteTitle", note.getTitle()); intent.putExtra("noteContent", note.getContent()); startActivity(intent); } 

При касании элемента представления списка мы извлекаем примечание, которое выбрал пользователь, и прикрепляем его данные к объекту намерения. Мы EditNoteActivity эти данные обратно в класс EditNoteActivity . Это один из способов передачи данных между действиями.

В файле EditNoteActivity.java добавьте следующие поля.

 private Note note; private EditText titleEditText; private EditText contentEditText; private String postTitle; private String postContent; private Button saveNoteButton; 

Измените метод onCreate() как показано.

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActionBar().setDisplayHomeAsUpEnabled(true); setContentView(R.layout.activity_edit_note); Intent intent = this.getIntent(); titleEditText = (EditText) findViewById(R.id.noteTitle); contentEditText = (EditText) findViewById(R.id.noteContent); if (intent.getExtras() != null) { note = new Note(intent.getStringExtra("noteId"), intent.getStringExtra("noteTitle"), intent.getStringExtra("noteContent")); titleEditText.setText(note.getTitle()); contentEditText.setText(note.getContent()); } saveNoteButton = (Button)findViewById(R.id.saveNote); saveNoteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { saveNote(); } }); } 

Он проверяет, были ли какие-либо данные переданы с помощью Intent, и загружает текстовые поля вместе с ним, если это так.

Добавьте метод saveNote() .

 private void saveNote() { postTitle = titleEditText.getText().toString(); postContent = contentEditText.getText().toString(); postTitle = postTitle.trim(); postContent = postContent.trim(); // If user doesn't enter a title or content, do nothing // If user enters title, but no content, save // If user enters content with no title, give warning // If user enters both title and content, save if (!postTitle.isEmpty()) { // Check if post is being created or edited if (note == null) { // create new post ParseObject post = new ParseObject("Post"); post.put("title", postTitle); post.put("content", postContent); post.saveInBackground(new SaveCallback() { public void done(ParseException e) { if (e == null) { // Saved successfully. Toast.makeText(getApplicationContext(), "Saved", Toast.LENGTH_SHORT).show(); } else { // The save failed. Toast.makeText(getApplicationContext(), "Failed to Save", Toast.LENGTH_SHORT).show(); Log.d(getClass().getSimpleName(), "User update error: " + e); } } }); } else { // update post ParseQuery<ParseObject> query = ParseQuery.getQuery("Post"); // Retrieve the object by id query.getInBackground(note.getId(), new GetCallback<ParseObject>() { public void done(ParseObject post, ParseException e) { if (e == null) { // Now let's update it with some new data. post.put("title", postTitle); post.put("content", postContent); post.saveInBackground(new SaveCallback() { public void done(ParseException e) { if (e == null) { // Saved successfully. Toast.makeText(getApplicationContext(), "Saved", Toast.LENGTH_SHORT).show(); } else { // The save failed. Toast.makeText(getApplicationContext(), "Failed to Save", Toast.LENGTH_SHORT).show(); Log.d(getClass().getSimpleName(), "User update error: " + e); } } }); } } }); } } else if (postTitle.isEmpty() &amp;&amp; !postContent.isEmpty()) { AlertDialog.Builder builder = new AlertDialog.Builder(EditNoteActivity.this); builder.setMessage(R.string.edit_error_message) .setTitle(R.string.edit_error_title) .setPositiveButton(android.R.string.ok, null); AlertDialog dialog = builder.create(); dialog.show(); } } 

Приведенный выше код проверяет, создает ли пользователь новую заметку или редактирует существующую, и создает ParseObject или получает его соответственно. Данные сохраняются с помощью saveInBackground() который сохраняет данные асинхронно, поэтому ваше приложение не будет заблокировано до завершения сохранения. Если сеть работает медленно, вы можете вернуться к списку заметок, и данные все равно будут сохранены.

Добавьте следующее в файл strings.xml .

 <string name="edit_error_title">Error!</string> <string name="edit_error_message">You cannot save a note without a title</string> 

Как и в нашем представлении списка, мы покажем индикатор загрузки. Добавьте следующее после super.onCreate(savedInstanceState) в onCreate() .

 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 

Затем поместите следующее перед вызовом post.saveInBackground() для блоков create-new и update-post.

 setProgressBarIndeterminateVisibility(true); 

После сохранения скройте индикатор загрузки с помощью следующего. Поместите это как первое утверждение в done методе.

 setProgressBarIndeterminateVisibility(false); 

Вы можете запустить и протестировать приложение, чтобы увидеть все, что мы добавили до сих пор. Вы заметите, что после сохранения заметки, когда пользователь снова нажмет кнопку Сохранить, будет создана другая заметка. Мы предотвратим это, создав объект заметки при сохранении заметки, чтобы при повторном нажатии кнопки «Сохранить» note не была null .

В блок, который создает новую заметку, добавьте следующую после того, как заметка была успешно сохранена.

 note = new Note(post.getObjectId(), postTitle, postContent); 

Добавьте final модификатор к объекту post чтобы он мог быть доступен во внутреннем классе.

 final ParseObject post = new ParseObject("Post"); 

Ниже приводится результирующий код для блока if .

 if (note == null) { // create new post final ParseObject post = new ParseObject("Post"); post.put("title", postTitle); post.put("content", postContent); setProgressBarIndeterminateVisibility(true); post.saveInBackground(new SaveCallback() { public void done(ParseException e) { setProgressBarIndeterminateVisibility(false); if (e == null) { // Saved successfully. note = new Note(post.getObjectId(), postTitle, postContent); Toast.makeText(getApplicationContext(), "Saved", Toast.LENGTH_SHORT).show(); } else { // The save failed. Toast.makeText(getApplicationContext(), "Failed to Save", Toast.LENGTH_SHORT).show(); Log.d(getClass().getSimpleName(), "User update error: " + e); } } }); } 

Теперь повторные записи не будут создаваться при повторном сохранении той же заметки.

Приложение сохраняет и извлекает сообщения, но любой может использовать их и просмотреть все заметки, сохраненные в серверной части. Мы ограничим использование приложения зарегистрированными пользователями, а также сделаем так, чтобы пользователь мог получать доступ только к своим заметкам.

Сначала мы создадим активность входа. Создайте пустое действие, как вы делали ранее. Назовите его LoginActivity и установите его название на Login.

Измените файл res/layout/activity_login.xml как показано.

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".LoginActivity" > <EditText android:id="@+id/usernameField" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:ems="10" android:hint="@string/username_hint" > <requestFocus /> </EditText> <EditText android:id="@+id/passwordField" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/usernameField" android:layout_below="@+id/usernameField" android:ems="10" android:hint="@string/password_hint" android:inputType="textPassword" /> <Button android:id="@+id/loginButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/passwordField" android:layout_below="@+id/passwordField" android:text="@string/login_button_label" /> <TextView android:id="@+id/signUpText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/loginButton" android:layout_centerHorizontal="true" android:layout_marginTop="69dp" android:text="@string/sign_up_text" /> </RelativeLayout> 

Добавьте следующее в файл strings.xml . Некоторые из атрибутов будут использованы позже.

 <string name="username_hint">Username</string> <string name="password_hint">Password</string> <string name="email_hint">Email</string> <string name="sign_up_button_label">Sign Up</string> <string name="signup_error_message">Please make sure you enter a username, password, and email address!</string> <string name="signup_error_title">Error!</string> <string name="login_error_message">Please make sure you enter a username and password!</string> <string name="login_error_title">Error!</string> <string name="login_button_label">Login</string> <string name="sign_up_text">Sign Up!</string> <string name="logout_label">Logout</string> 

Создайте еще одно пустое действие и назовите его SignUpActivity . Дайте ему название Зарегистрироваться .

Измените файл res/layout/activity_sign_up.xml как показано.

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".SignUpActivity" > <EditText android:id="@+id/usernameField" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:ems="10" android:hint="@string/username_hint" > <requestFocus /> </EditText> <EditText android:id="@+id/passwordField" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/usernameField" android:layout_below="@+id/usernameField" android:ems="10" android:inputType="textPassword" android:hint="@string/password_hint" /> <EditText android:id="@+id/emailField" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/passwordField" android:layout_below="@+id/passwordField" android:ems="10" android:inputType="textEmailAddress" android:hint="@string/email_hint" /> <Button android:id="@+id/signupButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/emailField" android:layout_below="@+id/emailField" android:text="@string/sign_up_button_label" /> </RelativeLayout> 

Ниже приведены полученные логин и регистрация.

parse_android_07

Когда приложение запустится, мы проверим, вошел ли пользователь в систему, и если нет, приложение перенаправит его в представление «Вход».

Поскольку создание учетных записей пользователей является распространенным требованием в приложениях, Parse предоставляет класс ParseUser который автоматически обрабатывает большую часть функций, необходимых для управления учетными записями пользователей. ParseUser имеет свойства, которые используются при типичном назначении и управлении пользователями, например, имя пользователя, пароль и адрес электронной почты.

В классе MainActivity добавьте проверку для вошедшего в систему пользователя в onCreate() после вызова setContentView(R.layout.activity_main) .

 ParseUser currentUser = ParseUser.getCurrentUser(); if (currentUser == null) { loadLoginView(); } 

Добавьте метод loadLoginView() в файл.

 private void loadLoginView() { Intent intent = new Intent(this, LoginActivity.class); startActivity(intent); } 

Запустите приложение, и вы будете перенаправлены на страницу входа в систему. Однако, когда вы используете кнопку «Назад», вы будете перенаправлены на основной вид деятельности. Это связано с тем, что в стеке истории MainActivity предшествует LoginActivity . Таким образом, нажимается «назад», приложение переходит к предыдущему действию. Нам нужно очистить историю стека и установить LoginActivity в качестве начала стека истории. Измените loadLoginView() как показано.

 private void loadLoginView() { Intent intent = new Intent(this, LoginActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); } 

Теперь, когда вы нажмете кнопку «Назад», приложение закроется.

Измените класс LoginActivity как показано.

 public class LoginActivity extends ActionBarActivity { protected EditText usernameEditText; protected EditText passwordEditText; protected Button loginButton; protected TextView signUpTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.activity_login); signUpTextView = (TextView)findViewById(R.id.signUpText); usernameEditText = (EditText)findViewById(R.id.usernameField); passwordEditText = (EditText)findViewById(R.id.passwordField); loginButton = (Button)findViewById(R.id.loginButton); signUpTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(LoginActivity.this, SignUpActivity.class); startActivity(intent); } }); loginButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String username = usernameEditText.getText().toString(); String password = passwordEditText.getText().toString(); username = username.trim(); password = password.trim(); if (username.isEmpty() || password.isEmpty()) { AlertDialog.Builder builder = new AlertDialog.Builder(LoginActivity.this); builder.setMessage(R.string.login_error_message) .setTitle(R.string.login_error_title) .setPositiveButton(android.R.string.ok, null); AlertDialog dialog = builder.create(); dialog.show(); } else { setProgressBarIndeterminateVisibility(true); ParseUser.logInInBackground(username, password, new LogInCallback() { @Override public void done(ParseUser user, ParseException e) { setProgressBarIndeterminateVisibility(false); if (e == null) { // Success! Intent intent = new Intent(LoginActivity.this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); } else { // Fail AlertDialog.Builder builder = new AlertDialog.Builder(LoginActivity.this); builder.setMessage(e.getMessage()) .setTitle(R.string.login_error_title) .setPositiveButton(android.R.string.ok, null); AlertDialog dialog = builder.create(); dialog.show(); } } }); } } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.login, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } } 

В приведенном выше коде мы направляем пользователя к представлению регистрации, если они касаются TextView . Когда они пытаются войти в систему, мы сначала проверяем поля, чтобы убедиться, что данные были введены, прежде чем пытаться войти в них с помощью Parse. Если вход не пройден, они будут уведомлены. Если это удастся, то они будут направлены на представление списка с примечаниями. Обратите внимание, что мы MainActivity и устанавливаем стек истории перед MainActivity . Это гарантирует, что пользователь не сможет вернуться к представлению входа в систему, нажав кнопку «Назад».

Измените класс SignUpActivity как показано.

 public class SignUpActivity extends ActionBarActivity { protected EditText usernameEditText; protected EditText passwordEditText; protected EditText emailEditText; protected Button signUpButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); getActionBar().setDisplayHomeAsUpEnabled(true); setContentView(R.layout.activity_sign_up); usernameEditText = (EditText)findViewById(R.id.usernameField); passwordEditText = (EditText)findViewById(R.id.passwordField); emailEditText = (EditText)findViewById(R.id.emailField); signUpButton = (Button)findViewById(R.id.signupButton); signUpButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String username = usernameEditText.getText().toString(); String password = passwordEditText.getText().toString(); String email = emailEditText.getText().toString(); username = username.trim(); password = password.trim(); email = email.trim(); if (username.isEmpty() || password.isEmpty() || email.isEmpty()) { AlertDialog.Builder builder = new AlertDialog.Builder(SignUpActivity.this); builder.setMessage(R.string.signup_error_message) .setTitle(R.string.signup_error_title) .setPositiveButton(android.R.string.ok, null); AlertDialog dialog = builder.create(); dialog.show(); } else { setProgressBarIndeterminateVisibility(true); ParseUser newUser = new ParseUser(); newUser.setUsername(username); newUser.setPassword(password); newUser.setEmail(email); newUser.signUpInBackground(new SignUpCallback() { @Override public void done(ParseException e) { setProgressBarIndeterminateVisibility(false); if (e == null) { // Success! Intent intent = new Intent(SignUpActivity.this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); } else { AlertDialog.Builder builder = new AlertDialog.Builder(SignUpActivity.this); builder.setMessage(e.getMessage()) .setTitle(R.string.signup_error_title) .setPositiveButton(android.R.string.ok, null); AlertDialog dialog = builder.create(); dialog.show(); } } }); } } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.sign_up, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } } 

В файле манифеста установите родительское действие для SignUpActivity равным LoginActivity чтобы мы могли перейти к представлению входа в систему из представления регистрации.

 <activity android:name=".SignUpActivity" android:label="@string/title_activity_sign_up" > <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.echessa.noteapp.LoginActivity" /> </activity> 

Теперь вы можете создать учетную запись и получить доступ к заметкам на сервере Parse. Сеанс пользователя кэшируется, поэтому вам не нужно будет входить в систему каждый раз, когда вы используете приложение. Нам нужно создать связь между заметками и пользователем, чтобы пользователь загружал только свои заметки. Перед этим давайте добавим функцию выхода из системы.

В res/menu/main.xml добавьте элемент панели действий.

 <item android:id="@+id/action_logout" android:title="@string/logout_label"> </item> 

В MainActivity.java добавьте следующий случай к оператору switch в onOptionsItemSelected(MenuItem item) .

 case R.id.action_logout: ParseUser.logOut(); loadLoginView(); break; 

Теперь вы можете выйти из системы, используя действие панели действий. Если вы не видите его на панели действий, доступ к нему можно получить в меню наложения панели действий.

parse_android_08

Добавьте следующее в EditNoteActivity в saveNote() . Добавьте его в блок if который создает новую заметку, после этого оператора post.put("content", postContent); ,

 post.put("author", ParseUser.getCurrentUser()); 

При добавлении новой заметки зарегистрированный пользователь будет сохранен как его автор. При первом запуске колонка автора будет автоматически создана в Parse перед сохранением данных, поэтому вам не нужно создавать ее с помощью панели мониторинга, прежде чем вы сможете ее использовать.

В MainActivity добавьте следующее в метод refreshPostList() после этого оператора ParseQuery query = ParseQuery.getQuery("Post"); ,

 query.whereEqualTo("author", ParseUser.getCurrentUser()); 

Запустив приложение, вы сможете создавать заметки и просматривать только созданные вами заметки.

Примечания

Мы рассмотрели, как интегрировать Parse SDK в приложение для Android. Мы увидели, как сохранять и извлекать данные в бэкэнд и как управлять учетными записями пользователей. Есть и другие функции, которые вы можете включить, о которых я упомяну здесь.

Удаление объектов

Вы должны включить способ удаления заметок для пользователей. Как вы этого достигнете, зависит только от вас. Обычные шаблоны проектирования в Android для удаления включают в себя пролистывание элемента списка для удаления, длительное нажатие на элемент, чтобы вызвать диалоговое окно подтверждения удаления, а также можно добавить кнопку удаления в подробном представлении «Добавить / изменить».

Чтобы удалить заметку, используйте следующую

 post.deleteInBackground(); 

Сброс пароля

Если вы ожидаете, что пользователи будут использовать пароли для использования вашего приложения, вы должны включить способ сброса паролей, если они их забудут. Parse уже имеет эту функцию, поэтому вам нужно вызывать только следующее, когда пользователь запрашивает сброс пароля.

 ParseUser.requestPasswordResetInBackground(userEmail, new RequestPasswordResetCallback() { public void done(ParseException e) { if (e == null) { // An email was successfully sent with reset instructions. } else { // Something went wrong. Look at the ParseException to see what's up. } } }); 

Использование в автономном режиме

Приложение, которое мы создали, нуждается в интернет-соединении для работы по мере необходимости. Для получения и сохранения заметок требуется подключение к интернету.

Parse теперь предлагает Parse Local Datastore, который позволяет вам сохранять данные локально и запрашивать данные с помощью обычного ParseQuery . Это можно сделать, закрепив данные в локальном хранилище данных и открепив данные, чтобы удалить их.

Когда приложение находится в автономном режиме, оно по-прежнему сможет извлекать и сохранять данные, а когда подключение к Интернету устанавливается снова, оно синхронизирует данные в облаке с локальным хранилищем данных. Для получения информации о том, как это сделать, проверьте руководства ,

Вывод

Мы рассмотрели использование Parse в качестве системы BaaS для ваших приложений. Использование таких готовых серверных сервисов имеет множество преимуществ, но оно также сопряжено с некоторыми подводными камнями, которые следует сравнивать с преимуществами при принятии решения о том, собирать ли его с нуля или использовать решение BaaS. Даже если вы планируете создать свой собственный бэкэнд, возможно, стоит начать с BaaS, чтобы сократить время выхода приложения на рынок, а также протестировать приложение на рынке и быстро проверить функциональность на основе данные об использовании.

Помимо Parse, есть несколько других решений / сервисов, например Apigee , Backendless , Kii , built.io , Firebase и другие. Они предоставляют разные услуги по разным ценам, и стоит посмотреть и сравнить разные продукты, чтобы решить, что лучше всего соответствует вашим потребностям.