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.