Erste Schritte mit AWS
Erstellen einer Android-Anwendung
Erstellen einer einfachen Android-Anwendung mit AWS Amplify

Android-App erstellen
Modul 1: Erstellen und Bereitstellen einer Android-App
In diesem Modul erstellen Sie eine Android-Anwendung und stellen sie mit dem Webhosting-Service von AWS Amplify in der Cloud bereit.
Einführung
AWS Amplify bietet einen Git-basierten Workflow zur Erstellung, Verwaltung, Integration und Bereitstellung von serverlosen Backends für Web- und mobile Anwendungen. Die Amplify CLI bietet eine einfache textbasierte Benutzeroberfläche zur Bereitstellung und Verwaltung von Backend Services, wie z. B. Benutzerauthentifizierung oder eine REST- oder GraphQL-API für Ihre Anwendungen. Die Amplify-Bibliotheken ermöglichen die einfache Integration dieser Amplify Backend Services mit nur wenigen Zeilen Code in Ihre Anwendungen.
In diesem Modul beginnen wir mit der Erstellung einer neuen Android-Anwendung zur Aufnahme von Reisenotizen. Es werden ein Titel, eine Beschreibung und ein Bild notiert. Wir werden diese Anwendung in den folgenden Modulen erweitern.
Lerninhalte
- Erstellen einer Android-Anwendung
- Aktualisieren der Hauptansicht, um eine Liste von Elementen anzuzeigen
- Erstellen und Testen Ihrer Anwendung
Wichtige Konzepte
Kotlin: Kotlin wurde als Programmiersprache für dieses Tutorial gewählt, weil es Ihnen erlaubt, einen Großteil des Boilerplate-Codes zu reduzieren, und weil es mit Blick auf die Typsicherheit entwickelt wurde.
Jetpack: Dieses Tutorial verwendet das Jetpack von Android, eine Sammlung von Android-Bibliotheken, die bewährte Methoden enthalten und Abwärtskompatibilität in Ihren Android-Apps bieten.
Veranschlagte Zeit
10 Minuten
Verwendete Services
Implementierung
-
Ein Android-Projekt erstellen
Starten Sie Android Studio, und wählen Sie im Startbildschirm die Option Start eines neuen Android Studio-Projekts:
Wählen Sie unter Telefon und Tablet die Option Grundlegende Aktivität und klicken Sie auf Weiter:
Geben Sie einen Namen für Ihr Projekt ein, zum Beispiel Android Erste Schritte. Stellen Sie sicher, dass Sprache Kotlin und Minimum SDK API 26: Android 8.0 (oreo) ist, und klicken Sie dann auf Fertig stellen:
Nun, da das Gerüst des Projekts existiert, benötigen wir 4 Schritte, um unsere grundlegende Anwendung zum Laufen zu bringen:
- Löschen unerwünschter Klassen und Dateien und Hinzufügen von Plugins
- Erstellen von Klassen zur Aufnahme unserer Datenstrukturen
- Eine Ansicht erstellen, um einzelne Notizen in der Liste zu halten
- Ändern der MainActivity, um eine Liste der Notizen anzuzeigen
-
Löschen nicht benötigter Dateien und Hinzufügen von Plugins
Unter res/layout und java/com.example.androidgettingstarted löschen Sie die vier Fragment-Dateien (markieren Sie die 4 Dateien, klicken Sie mit der rechten Maustaste und wählen Sie Löschen aus dem Kontextmenü):
Öffnen Sie unter Gradle Scripts build.gradle (Modul:app) und fügen Sie das Kotlin Extension Plugin hinzu.
plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-android-extensions' // <== add this line }
-
Erstellen einer UserData-Datenklasse
Die Klasse UserData enthält den Benutzerstatus: ein isSignedIn-Flag und eine Liste von Notizwerten.
Um eine neue Klasse zu erstellen, klicken Sie mit der rechten Maustaste auf java/com.example/androidgettingstarted und wählen Sie Neu -> Kotlin-Datei/Klasse. Geben Sie UserData als Namen ein.
Fügen Sie den unten stehenden Code in die soeben erstellte neue Datei (UserData.kt)
package com.example.androidgettingstarted import android.graphics.Bitmap import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData // a singleton to hold user data (this is a ViewModel pattern, without inheriting from ViewModel) object UserData { private const val TAG = "UserData" // // observable properties // // signed in status private val _isSignedIn = MutableLiveData<Boolean>(false) var isSignedIn: LiveData<Boolean> = _isSignedIn fun setSignedIn(newValue : Boolean) { // use postvalue() to make the assignation on the main (UI) thread _isSignedIn.postValue(newValue) } // the notes private val _notes = MutableLiveData<MutableList<Note>>(mutableListOf()) // please check https://stackoverflow.com/questions/47941537/notify-observer-when-item-is-added-to-list-of-livedata private fun <T> MutableLiveData<T>.notifyObserver() { this.postValue(this.value) } fun notifyObserver() { this._notes.notifyObserver() } fun notes() : LiveData<MutableList<Note>> = _notes fun addNote(n : Note) { val notes = _notes.value if (notes != null) { notes.add(n) _notes.notifyObserver() } else { Log.e(TAG, "addNote : note collection is null !!") } } fun deleteNote(at: Int) : Note? { val note = _notes.value?.removeAt(at) _notes.notifyObserver() return note } fun resetNotes() { this._notes.value?.clear() //used when signing out _notes.notifyObserver() } // a note data class data class Note(val id: String, val name: String, val description: String, var imageName: String? = null) { override fun toString(): String = name // bitmap image var image : Bitmap? = null } }
Was haben wir gerade hinzugefügt?
- Die Klasse UserData ist dafür verantwortlich, Benutzerdaten zu halten, nämlich ein isSignedIn-Flag zur Verfolgung des aktuellen Authentifizierungsstatus und eine Liste von Notizobjekten.
- Diese beiden Eigenschaften sind entsprechend dem LiveData Publish/Abonnement Framework implementiert. Sie ermöglicht es der Graphischen Benutzeroberfläche (GUI), Änderungen zu abonnieren und entsprechend zu reagieren. Um mehr über LiveData zu erfahren, können Sie dieses Dokument lesen oder diesem kurzen Video-Tutorial folgen. Um der bewährten Methode zu befolgen, halten Sie die MutableLiveData-Eigenschaft privat und legen Sie nur die schreibgeschützte LiveData-Eigenschaft offen. Wenn es sich bei den zu veröffentlichenden Daten um eine Liste handelt, ist ein zusätzlicher Boilerplate-Code erforderlich, um sicherzustellen, dass die Beobachter benachrichtigt werden, wenn einzelne Komponenten in der Liste geändert werden.
- Wir haben auch eine Notizdatenklasse hinzugefügt, um die Daten einzelner Notizen zu speichern. Für ImageName und Image werden zwei unterschiedliche Eigenschaften verwendet. Das Bild wird in einem späteren Modul behandelt.
- Das Singleton-Entwurfsmuster für das UserData-Objekt wurde implementiert, da es den Verweis darauf von überall in der Anwendung nur mit UserData erlaubt.
-
GUI für einzelne Zellen in der Liste hinzufügen
Einzelne Zellen in einer Bildlaufliste werden als RecyclerView bezeichnet, da die Ansicht recycelt werden kann, wenn der Benutzer nach oben und unten blättert, wenn die Ansicht auf dem Bildschirm nicht mehr sichtbar ist.
Genau wie bei einer normalen Ansicht erstellen wir Layout-XML-Dateien und eine Kotlin-Klasse. Eine einzelne Zelle sieht wie folgt aus:
Um die Layout-Datei zu erzeugen, klicken Sie mit der rechten Maustaste auf res/layout und wählen Sie Neu -> Layout-Ressourcen-Datei. Geben Sie content_note als Namen ein und lassen Sie alle anderen Werte stehen, da wir die XML-Datei direkt bearbeiten werden.
Öffnen Sie die Code-Ansicht für die neu erstellte Datei.
Ersetzen Sie in der Code-Ansicht der soeben erstellten neuen Datei (content_note.xml) den generierten Code durch Einfügen des unten stehenden Codes:
<?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="wrap_content" android:orientation="horizontal" android:paddingVertical="16dp"> <ImageView android:id="@+id/image" android:layout_width="100dp" android:layout_height="match_parent" android:padding="8dp" android:scaleType="centerCrop" android:src="@drawable/ic_launcher_background" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="5dp" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Title" android:textSize="20sp" android:textStyle="bold" /> <TextView android:id="@+id/description" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Title" android:textSize="15sp" /> </LinearLayout> </LinearLayout>
Erstellen Sie schließlich die Kotlin-Klasse: Klicken Sie mit der rechten Maustaste auf java/com.example/androidgettingstarted und wählen Sie Neu -> Kotlin-Datei/Klasse. Geben Sie NoteRecyclerViewAdapter als Namen ein.
Fügen Sie den folgenden Code in die soeben erstellte neue Datei ein (NoteRecyclerViewAdapter.kt)
package com.example.androidgettingstarted import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView // this is a single cell (row) in the list of Notes class NoteRecyclerViewAdapter( private val values: MutableList<UserData.Note>?) : RecyclerView.Adapter<NoteRecyclerViewAdapter.ViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.content_note, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = values?.get(position) holder.nameView.text = item?.name holder.descriptionView.text = item?.description if (item?.image != null) { holder.imageView.setImageBitmap(item.image) } } override fun getItemCount() = values?.size ?: 0 inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val imageView: ImageView = view.findViewById(R.id.image) val nameView: TextView = view.findViewById(R.id.name) val descriptionView: TextView = view.findViewById(R.id.description) } }
Was haben wir gerade hinzugefügt?
Der obige Code besteht aus:- einer Layout-xml-Datei, die das Layout der Komponente auf einer Zelle beschreibt, die eine Notiz darstellt. Sie zeigt das Bild, den Titel der Notiz und die Beschreibung der Notiz an.
- einer unterstützenden Kotlin-Klasse. Sie erhält bei der Erstellung ein Notizen-Datenobjekt und ordnet den entsprechenden Ansichten (Bild, Titel und Beschreibung) individuelle Werte zu.
-
Aktualisieren der Hauptaktivität
Nachdem wir nun die Datenklassen (UserData und Note) und die Ansicht der einzelnen Notizen (NoteRecyclerViewAdapter) haben, erstellen wir die Notizliste zur Hauptaktivität.
Öffnen Sie in der Dateiliste auf der linken Seite von Android Studio die Datei res/layout/content_main.xml und ersetzen Sie den Code durch diesen Inhalt:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/frameLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <androidx.recyclerview.widget.RecyclerView android:id="@+id/item_list" android:name="com.example.myapplication.ItemListFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="60dp" android:paddingHorizontal="8dp" android:paddingVertical="8dp" app:layoutManager="LinearLayoutManager" tools:context=".MainActivity" tools:listitem="@layout/content_note" /> </FrameLayout>
Öffnen Sie in der Dateiliste auf der linken Seite von Android Studio die Datei java/com.example/androidgettingstarted/MainActivity.kt und ersetzen Sie den Code durch diesen Inhalt:
package com.example.androidgettingstarted import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.content_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) // prepare our List view and RecyclerView (cells) setupRecyclerView(item_list) } // recycler view is the list of cells private fun setupRecyclerView(recyclerView: RecyclerView) { // update individual cell when the Note data are modified UserData.notes().observe(this, Observer<MutableList<UserData.Note>> { notes -> Log.d(TAG, "Note observer received ${notes.size} notes") // let's create a RecyclerViewAdapter that manages the individual cells recyclerView.adapter = NoteRecyclerViewAdapter(notes) }) } companion object { private const val TAG = "MainActivity" } }
Was haben wir gerade hinzugefügt?
- Das Hauptlayout ist eine RecyclerView, die die Liste der einzelnen Zellen verwaltet, die wir zuvor erstellt haben.
- Die Hauptaktivitätsklasse beobachtet Änderungen an der Liste der Notizen und erstellt einen NoteRecyclerViewAdapter, um einzelne Zellen zu erstellen.
-
Überprüfen der Build-Abhängigkeiten
Öffnen Sie unter Gradle Scripts die Datei build.gradle (Modul:app) und überprüfen Sie, ob die generierten Abhängigkeiten korrekt sind. Die `Bibliotheksversionen` müssen überprüft werden.
```gradle dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.2' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1' implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' }
-
Erstellen und testen
Erstellen und starten Sie nun die Anwendung im Simulator. Klicken Sie auf das Symbol Ausführen ▶️ in der Symbolleiste oder geben Sie ^ R ein.
Nach einer Weile startet die Anwendung im Android-Simulator mit einem leeren Anfangsbildschirm.
In diesem Stadium gibt es keine Daten, die zur Laufzeit gerendert werden müssen. Wir werden das Mail-Symbol in einem späteren Schritt abschaffen.