Next you'll use the generated model to read and write data. In this section you'll initialize DataStore, and create and query for Todo items.
## Configure Amplify and DataStore
First, you'll add the DataStore plugin and configure Amplify.
Right-click on your namespace (`com.example.Todo`), click **New**, and click **Java Class** or **Kotlin Class/File** depending on which language you chose.
Configure the new class in **New Java Class**:
- Enter *MyAmplifyApp* in the **Name** field
- Press **OK**
- Extend *MyAmplifyApp* from *android.app.Application* by adding `extends Application` to your class
Add the following import statements at the top of the file:
```java
import android.app.Application;
import android.util.Log;
import com.amplifyframework.AmplifyException;
import com.amplifyframework.core.Amplify;
import com.amplifyframework.datastore.AWSDataStorePlugin;
```
Initialize Amplify by adding an `onCreate` method with the following code:
```java
public void onCreate() {
super.onCreate();
try {
Amplify.addPlugin(new AWSDataStorePlugin());
Amplify.configure(getApplicationContext());
Log.i("Tutorial", "Initialized Amplify");
} catch (AmplifyException error) {
Log.e("Tutorial", "Could not initialize Amplify", error);
}
}
```
Configure the new class in **New Kotlin Class/File**:
- Enter *MyAmplifyApp* in the **Name** field
- Press enter
- Extend *MyAmplifyApp* from *android.app.Application* by adding `: Application()` to your class
Add the following import statements at the top of the file:
```kotlin
import android.app.Application
import android.util.Log
import com.amplifyframework.AmplifyException
import com.amplifyframework.core.Amplify
import com.amplifyframework.datastore.AWSDataStorePlugin
```
Initialize Amplify by adding an `onCreate` method with the following code:
```kotlin
override fun onCreate() {
super.onCreate()
try {
Amplify.addPlugin(AWSDataStorePlugin())
Amplify.configure(applicationContext)
Log.i("Tutorial", "Initialized Amplify")
} catch (error: AmplifyException) {
Log.e("Tutorial", "Could not initialize Amplify", error)
}
}
```
This overrides the `onCreate()` to initialize Amplify when your application is launched.
Next, configure your application to use your new custom `Application` class. Open **manifests** > **AndroidManifest.xml**, and add an `android:name` attribute with the value of your new class name:
```xml
```
**Build and run** the application. In logcat, you'll see a log line indicating success:
```console
com.example.MyAmplifyApp I/MyAmplifyApp: Initialized Amplify
```
To make this easier to find, enter the string **MyAmplifyApp** into the search field
## Manipulating data
### Create a Todo
Next, you'll create a Todo and save it to DataStore.
1. Open `MainActivity` and **add the following** import statements at the top of the file:
```java
import android.util.Log;
import com.amplifyframework.AmplifyException;
import com.amplifyframework.core.Amplify;
import com.amplifyframework.core.model.temporal.Temporal;
import com.amplifyframework.datastore.AWSDataStorePlugin;
import com.amplifyframework.datastore.generated.model.Priority;
import com.amplifyframework.datastore.generated.model.Todo;
import java.util.*;
import java.util.concurrent.TimeUnit;
```
```kotlin
import android.util.Log
import com.amplifyframework.AmplifyException
import com.amplifyframework.core.Amplify
import com.amplifyframework.core.model.temporal.Temporal
import com.amplifyframework.datastore.AWSDataStorePlugin
import com.amplifyframework.datastore.generated.model.Priority
import com.amplifyframework.datastore.generated.model.Todo
import java.util.*
import java.util.concurrent.TimeUnit
```
2. In the same file ( MainActivity
), add the following code to the bottom of the onCreate()
method:
```java
Todo item = Todo.builder()
.name("Build Android application")
.priority(Priority.NORMAL)
.build();
Amplify.DataStore.save(item,
success -> Log.i("Tutorial", "Saved item: " + success.item().getName()),
error -> Log.e("Tutorial", "Could not save item to DataStore", error)
);
```
```kotlin
val item = Todo.builder()
.name("Build Android application")
.priority(Priority.NORMAL)
.build()
Amplify.DataStore.save(item,
{ Log.i("Tutorial", "Saved item: ${item.name}") },
{ Log.e("Tutorial", "Could not save item to DataStore", it) }
)
```
This code creates a Todo item with two properties: a name, and a priority, and then calls Amplify.DataStore.save()
in order to store it on DataStore.
3. After making the preceding updates to the MainActivity
file, your code should look like the following:
```java
package com.example.todo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.amplifyframework.core.Amplify;
import com.amplifyframework.core.model.query.Where;
import com.amplifyframework.core.model.temporal.Temporal;
import com.amplifyframework.datastore.AWSDataStorePlugin;
import com.amplifyframework.datastore.generated.model.Priority;
import com.amplifyframework.datastore.generated.model.Todo;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Todo item = Todo.builder()
.name("Build Android application")
.priority(Priority.NORMAL)
.build();
Amplify.DataStore.save(item,
success -> Log.i("Tutorial", "Saved item: " + success.item().getName()),
error -> Log.e("Tutorial", "Could not save item to DataStore", error)
);
}
}
```
```kotlin
package com.example.todo
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.amplifyframework.core.Amplify
import com.amplifyframework.core.model.query.Where
import com.amplifyframework.core.model.temporal.Temporal
import com.amplifyframework.datastore.AWSDataStorePlugin
import com.amplifyframework.datastore.generated.model.Priority
import com.amplifyframework.datastore.generated.model.Todo
import java.util.*
import java.util.concurrent.TimeUnit
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val item = Todo.builder()
.name("Build Android application")
.priority(Priority.NORMAL)
.build()
Amplify.DataStore.save(item,
{ Log.i("Tutorial", "Saved item: ${item.name}") },
{ Log.e("Tutorial", "Could not save item to DataStore", it) }
)
}
}
```
4. **Build and run** the application. In logcat, you'll see an indication that the item was saved successfully:
```console
com.example.todo I/Tutorial: Initialized Amplify
com.example.todo I/Tutorial: Saved item: Build Android application
```
1. **Replace the item** with a new Todo to save an additional item. Let's change the name and priority, and add a completedAt:
```java
Date date = new Date();
int offsetMillis = TimeZone.getDefault().getOffset(date.getTime());
int offsetSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(offsetMillis);
Temporal.DateTime temporalDateTime = new Temporal.DateTime(date, offsetSeconds);
Todo item = Todo.builder()
.name("Finish quarterly taxes")
.priority(Priority.HIGH)
.completedAt(temporalDateTime)
.build();
```
```kotlin
val date = Date()
val offsetMillis = TimeZone.getDefault().getOffset(date.time).toLong()
val offsetSeconds = TimeUnit.MILLISECONDS.toSeconds(offsetMillis).toInt()
val temporalDateTime = Temporal.DateTime(date, offsetSeconds)
val item = Todo.builder()
.name("Finish quarterly taxes")
.priority(Priority.HIGH)
.completedAt(temporalDateTime)
.build()
```
5. **Build and run** the application. In logcat, you'll see an indication that the item was saved successfully:
```console
com.example.todo I/Tutorial: Initialized Amplify
com.example.todo I/Tutorial: Saved item: Finish quarterly taxes
```
### Query Todos
Now that you have some data in DataStore, you can run queries to retrieve those records.
1. Edit your `onCreate` method to remove anything related to DataStore and replace it with the following code:
```java
Amplify.DataStore.query(Todo.class,
todos -> {
while (todos.hasNext()) {
Todo todo = todos.next();
Log.i("Tutorial", "==== Todo ====");
Log.i("Tutorial", "Name: " + todo.getName());
if (todo.getPriority() != null) {
Log.i("Tutorial", "Priority: " + todo.getPriority().toString());
}
if (todo.getCompletedAt() != null) {
Log.i("Tutorial", "CompletedAt: " + todo.getCompletedAt().toString());
}
}
},
failure -> Log.e("Tutorial", "Could not query DataStore", failure)
);
```
```kotlin
Amplify.DataStore.query(Todo::class.java,
{ todos ->
while (todos.hasNext()) {
val todo: Todo = todos.next()
Log.i("Tutorial", "==== Todo ====")
Log.i("Tutorial", "Name: ${todo.name}")
todo.priority?.let { todoPriority -> Log.i("Tutorial", "Priority: $todoPriority") }
todo.completedAt?.let { todoCompletedAt -> Log.i("Tutorial", "CompletedAt: $todoCompletedAt") }
}
},
{ Log.e("Tutorial", "Could not query DataStore", it) }
)
```
1. Run the application. In logcat, you'll see both items returned:
```console
com.example.todo I/Tutorial: Initialized Amplify
com.example.todo I/Tutorial: ==== Todo ====
com.example.todo I/Tutorial: Name: Build Android application
com.example.todo I/Tutorial: Priority: NORMAL
com.example.todo I/Tutorial: ==== Todo ====
com.example.todo I/Tutorial: Name: Finish quarterly taxes
com.example.todo I/Tutorial: Priority: HIGH
com.example.todo I/Tutorial: CompletedAt:
```
1. Queries can also contain predicate filters. These will query for specific objects matching a certain condition.
The following predicates are supported:
**Strings**
`eq` `ne` `le` `lt` `ge` `gt` `contains` `notContains` `beginsWith` `between`
**Numbers**
`eq` `ne` `le` `lt` `ge` `gt` `between`
**Lists**
`contains` `notContains`
To use a predicate, pass an additional argument into your query. For example, the following code queries for all high priority items:
```java
Amplify.DataStore.query(Todo.class,
Where.matches(Todo.PRIORITY.eq(Priority.HIGH)),
todos -> {
while (todos.hasNext()) {
Todo todo = todos.next();
Log.i("Tutorial", "==== Todo ====");
Log.i("Tutorial", "Name: " + todo.getName());
if (todo.getPriority() != null) {
Log.i("Tutorial", "Priority: " + todo.getPriority().toString());
}
if (todo.getCompletedAt() != null) {
Log.i("Tutorial", "Description: " + todo.getCompletedAt().toString());
}
}
},
failure -> Log.e("Tutorial", "Could not query DataStore", failure)
);
```
```kotlin
Amplify.DataStore.query(
Todo::class.java, Where.matches(Todo.PRIORITY.eq(Priority.HIGH)),
{ todos ->
while (todos.hasNext()) {
val todo: Todo = todos.next()
Log.i("Tutorial", "==== Todo ====")
Log.i("Tutorial", "Name: ${todo.name}")
todo.priority?.let { todoPriority -> Log.i("Tutorial", "Priority: $todoPriority") }
todo.completedAt?.let { todoCompletedAt -> Log.i("Tutorial", "CompletedAt: $todoCompletedAt") }
}
},
{ failure -> Log.e("Tutorial", "Could not query DataStore", failure) }
)
```
In the above code, notice the addition of the predicate parameter as the second argument.
1. Run the application. In logcat, you'll see only the high priority item returned:
```console
com.example.todo I/Tutorial: Initialized Amplify
com.example.todo I/Tutorial: ==== Todo ====
com.example.todo I/Tutorial: Name: Finish quarterly taxes
com.example.todo I/Tutorial: Priority: HIGH
com.example.todo I/Tutorial: CompletedAt:
```
### Update a Todo
You may want to change the contents of a record. Below, we'll query for a record, create a copy of it, modify it, and save it back to DataStore.
1. Edit your `onCreate` method to remove anything related to DataStore and replace it with the following code:
```java
Amplify.DataStore.query(Todo.class, Where.matches(Todo.NAME.eq("Finish quarterly taxes")),
matches -> {
if (matches.hasNext()) {
Todo todo = matches.next();
Todo updatedTodo = todo.copyOfBuilder()
.name("File quarterly taxes")
.build();
Amplify.DataStore.save(updatedTodo,
updated -> Log.i("Tutorial", "Updated item: " + updatedTodo.getName()),
failure -> Log.e("Tutorial", "Update failed.", failure)
);
}
},
failure -> Log.e("Tutorial", "Query failed.", failure)
);
```
```kotlin
Amplify.DataStore.query(Todo::class.java, Where.matches(Todo.NAME.eq("Finish quarterly taxes")),
{ matches ->
if (matches.hasNext()) {
val todo = matches.next()
val updatedTodo = todo.copyOfBuilder()
.name("File quarterly taxes")
.build()
Amplify.DataStore.save(updatedTodo,
{ Log.i("Tutorial", "Updated item: ${updatedTodo.name}") },
{ Log.e("Tutorial", "Update failed.", it) }
)
}
},
{ Log.e("Tutorial", "Query failed", it) }
)
```
1. **Build and run** the application. In your logcat, you'll see an indication that the item was updated successfully:
```console
Initialized Amplify
Updated item: File quarterly taxes
```
### Delete a Todo
To round out CRUD operations, we'll query for a record and then delete it from DataStore.
1. Edit your `onCreate()` method to remove anything related to DataStore and replace it with the following code:
```java
Amplify.DataStore.query(Todo.class, Where.matches(Todo.NAME.eq("File quarterly taxes")),
matches -> {
if (matches.hasNext()) {
Todo toDeleteTodo = matches.next();
Amplify.DataStore.delete(toDeleteTodo,
deleted -> Log.i("Tutorial", "Deleted item: " + toDeleteTodo.getName()),
failure -> Log.e("Tutorial", "Delete failed.", failure)
);
}
},
failure -> Log.e("Tutorial", "Query failed.", failure)
);
```
```kotlin
Amplify.DataStore.query(Todo::class.java, Where.matches(Todo.NAME.eq("File quarterly taxes")),
{ matches ->
if (matches.hasNext()) {
val toDeleteTodo = matches.next()
Amplify.DataStore.delete(toDeleteTodo,
{ Log.i("Tutorial", "Deleted item: ${toDeleteTodo.name}") },
{ Log.e("Tutorial", "Delete failed.", it) }
)
}
},
{ Log.e("Tutorial", "Query failed.", it) }
)
```
1. **Build and run** the application. In the console output, you'll see an indication that the item was deleted successfully:
```console
Initialized Amplify
Deleted item: File quarterly taxes
```
## Almost done
We just reached a *very cool* checkpoint. We have a fully featured CRUD application that saves and retrieves data in the local device, which means the app **works without an AWS account and even without internet connection**.
Next, let's connect it to AWS and make sure the data available in the cloud.