Android Room –待办事项列表应用程序

时间:2020-02-23 14:29:14  来源:igfitidea点击:

在本教程中,我们将讨论和实现Google引入的Room库。
我们将使用它来开发Todo List Android应用程序。

安卓机房

Room是Google引入的库,可作为SQLite上的抽象层,使数据库查询更加容易。

为什么要使用房间?

它确实对SQL查询进行编译时验证。
从而防止运行时崩溃。

它减少了样板代码。
代替使用SQLiteHelper和编写冗长的查询,我们可以使用注释为我们完成工作。

以下是Room库的结构:Google文档

通常,Room由以下三个主要部分组成:

  • 实体:这是一个模型类,其中定义了充当列字段的属性。
    我们也可以使用注解@ColumnInfo设置列名。
    我们也需要设置表名。
    要忽略表中的属性,请在其上使用注解@@ Ignore。
    至少一个属性必须具有@ PrimaryKey
    要设置与字段名称不同的列名称,请使用" @Embedded"
  • "数据库":这是一个抽象类,必须扩展" RoomDatabase"。
    我们必须在这里设置实体。
    另外,每次更改架构时,我们都需要更新版本号。
    exportSchema设置为true/false
  • 道:数据访问对象。
    这是我们设置SQL查询的接口。
    @ Insert,@ Query,@ Update,@ Delete。

@Insert无法返回int。

@Update和@Delete可以返回一个整数,该整数表示已更改/删除的行数。

房间查询不能也不应在主线程上执行。
会导致崩溃。

让我们在Todo List Android应用程序中使用Room库。

Android TODO App项目结构

我们的应用程序包括插入,更新,删除待办事项。
我们首先需要在build.gradle中导入以下Room依赖项:

implementation 'android.arch.persistence.room:runtime:1.0.0'
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'

让我们使用Todo.java类为数据库创建表,如下所示:

package com.theitroad.androidroomtodolist;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.PrimaryKey;

import java.io.Serializable;

@Entity(tableName = MyDatabase.TABLE_NAME_TODO)
public class Todo implements Serializable {

  @PrimaryKey(autoGenerate = true)
  public int todo_id;

  public String name;

  public String description;

  public String category;

  @Ignore
  public String priority;

}

MyDatabase.java

package com.theitroad.androidroomtodolist;

import android.arch.persistence.room.Database;
import android.arch.persistence.room.RoomDatabase;

@Database(entities = {Todo.class}, version = 1, exportSchema = false)
public abstract class MyDatabase extends RoomDatabase {

  public static final String DB_NAME = "app_db";
  public static final String TABLE_NAME_TODO = "todo";

  public abstract DaoAccess daoAccess();

}

这是一个抽象类,其中包含DaoAccess()接口的定义。

DaoAccess.java

package com.theitroad.androidroomtodolist;

import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Update;

import java.util.List;

@Dao
public interface DaoAccess {

  @Insert
  long insertTodo(Todo todo);

  @Insert
  void insertTodoList(List<Todo> todoList);

  @Query("SELECT * FROM " + MyDatabase.TABLE_NAME_TODO)
  List<Todo> fetchAllTodos();

  @Query("SELECT * FROM " + MyDatabase.TABLE_NAME_TODO + " WHERE category = :category")
  List<Todo> fetchTodoListByCategory(String category);

  @Query("SELECT * FROM " + MyDatabase.TABLE_NAME_TODO + " WHERE todo_id = :todoId")
  Todo fetchTodoListById(int todoId);

  @Update
  int updateTodo(Todo todo);

  @Delete
  int deleteTodo(Todo todo);
}

添加注释和一些sql查询。
并且所有SQLite功能都可以在我们的Activity中实现。

下面给出了activity_main.xml布局的代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity">
  
  <Spinner
      android:id="@+id/spinner"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_alignParentTop="true" 

  <android.support.v7.widget.RecyclerView
      android:id="@+id/recyclerView"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_below="@+id/spinner"
      android:layout_marginTop="16dp" 

  <android.support.design.widget.FloatingActionButton
      android:id="@+id/fab"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_alignParentRight="true"
      android:layout_marginBottom="16dp"
      android:src="@android:drawable/ic_input_add"
      android:layout_marginEnd="16dp"
      android:layout_marginRight="16dp" 

</RelativeLayout>

下面给出了recyclerview_item_layout.xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="wrap_content">

  <android.support.v7.widget.CardView
      android:id="@+id/cardView"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_gravity="center"
      android:layout_margin="16dp">

      <RelativeLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:padding="8dp">

          <TextView
              android:id="@+id/txtNo"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_alignParentLeft="true"
              android:layout_centerVertical="true" 

          <LinearLayout
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_toRightOf="@+id/txtNo"
              android:orientation="vertical">

              <TextView
                  android:id="@+id/txtName"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_marginLeft="8dp"
                  android:layout_marginRight="8dp"
                  android:layout_marginTop="8dp"
                  android:textAllCaps="true"
                  android:textColor="@android:color/black" 

              <TextView
                  android:id="@+id/txtDesc"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_marginLeft="8dp"
                  android:layout_marginRight="8dp"
                  android:layout_marginStart="8dp"
                  android:layout_marginTop="8dp"
                  android:ellipsize="end"
                  android:maxLines="1" 

              <TextView
                  android:id="@+id/txtCategory"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_marginLeft="8dp"
                  android:layout_marginStart="8dp"
                  android:layout_marginTop="8dp"
                  android:textColor="@android:color/holo_red_dark" 

          </LinearLayout>

      </RelativeLayout>
  </android.support.v7.widget.CardView>
</LinearLayout>

MainActivity.java类的代码如下:

package com.theitroad.androidroomtodolist;

import android.annotation.SuppressLint;
import android.arch.persistence.room.Room;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MainActivity extends AppCompatActivity implements RecyclerViewAdapter.ClickListener, AdapterView.OnItemSelectedListener {

  MyDatabase myDatabase;
  RecyclerView recyclerView;
  Spinner spinner;
  RecyclerViewAdapter recyclerViewAdapter;
  FloatingActionButton floatingActionButton;
  private String[] categories = {
          "All",
          "Android",
          "iOS",
          "Kotlin",
          "Swift"
  };

  ArrayList<Todo> todoArrayList = new ArrayList<>();
  ArrayList<String> spinnerList = new ArrayList<>(Arrays.asList(categories));

  public static final int NEW_TODO_REQUEST_CODE = 200;
  public static final int UPDATE_TODO_REQUEST_CODE = 300;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      initViews();
      myDatabase = Room.databaseBuilder(getApplicationContext(), MyDatabase.class, MyDatabase.DB_NAME).fallbackToDestructiveMigration().build();
      checkIfAppLaunchedFirstTime();

      spinner.setOnItemSelectedListener(this);
      spinner.setSelection(0);

      floatingActionButton.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              startActivityForResult(new Intent(MainActivity.this, TodoNoteActivity.class), NEW_TODO_REQUEST_CODE);
          }
      });

  }

  private void initViews() {
      floatingActionButton = findViewById(R.id.fab);
      spinner = findViewById(R.id.spinner);
      ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, spinnerList);
      adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      spinner.setAdapter(adapter);

      recyclerView = findViewById(R.id.recyclerView);
      recyclerView.setLayoutManager(new LinearLayoutManager(this));
      recyclerViewAdapter = new RecyclerViewAdapter(this);
      recyclerView.setAdapter(recyclerViewAdapter);
  }

  @Override
  public void launchIntent(int id) {
      startActivityForResult(new Intent(MainActivity.this, TodoNoteActivity.class).putExtra("id", id), UPDATE_TODO_REQUEST_CODE);
  }

  @Override
  public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

      if (position == 0) {
          loadAllTodos();
      } else {
          String string = parent.getItemAtPosition(position).toString();
          loadFilteredTodos(string);
      }
  }

  @Override
  public void onNothingSelected(AdapterView<?> parent) {

  }

  @SuppressLint("StaticFieldLeak")
  private void loadFilteredTodos(String category) {
      new AsyncTask<String, Void, List<Todo>>() {
          @Override
          protected List<Todo> doInBackground(String... params) {
              return myDatabase.daoAccess().fetchTodoListByCategory(params[0]);

          }

          @Override
          protected void onPostExecute(List<Todo> todoList) {
              recyclerViewAdapter.updateTodoList(todoList);
          }
      }.execute(category);

  }

  @SuppressLint("StaticFieldLeak")
  private void fetchTodoByIdAndInsert(int id) {
      new AsyncTask<Integer, Void, Todo>() {
          @Override
          protected Todo doInBackground(Integer... params) {
              return myDatabase.daoAccess().fetchTodoListById(params[0]);

          }

          @Override
          protected void onPostExecute(Todo todoList) {
              recyclerViewAdapter.addRow(todoList);
          }
      }.execute(id);

  }

  @SuppressLint("StaticFieldLeak")
  private void loadAllTodos() {
      new AsyncTask<String, Void, List<Todo>>() {
          @Override
          protected List<Todo> doInBackground(String... params) {
              return myDatabase.daoAccess().fetchAllTodos();
          }

          @Override
          protected void onPostExecute(List<Todo> todoList) {
              recyclerViewAdapter.updateTodoList(todoList);
          }
      }.execute();
  }

  private void buildDummyTodos() {
      Todo todo = new Todo();
      todo.name = "Android Retrofit Tutorial";
      todo.description = "Cover a tutorial on the Retrofit networking library using a RecyclerView to show the data.";
      todo.category = "Android";

      todoArrayList.add(todo);

      todo = new Todo();
      todo.name = "iOS TableView Tutorial";
      todo.description = "Covers the basics of TableViews in iOS using delegates.";
      todo.category = "iOS";

      todoArrayList.add(todo);

      todo = new Todo();
      todo.name = "Kotlin Arrays";
      todo.description = "Cover the concepts of Arrays in Kotlin and how they differ from the Java ones.";
      todo.category = "Kotlin";

      todoArrayList.add(todo);

      todo = new Todo();
      todo.name = "Swift Arrays";
      todo.description = "Cover the concepts of Arrays in Swift and how they differ from the Java and Kotlin ones.";
      todo.category = "Swift";

      todoArrayList.add(todo);
      insertList(todoArrayList);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      if (resultCode == RESULT_OK) {

          //reset spinners
          spinner.setSelection(0);

          if (requestCode == NEW_TODO_REQUEST_CODE) {
              long id = data.getLongExtra("id", -1);
              Toast.makeText(getApplicationContext(), "Row inserted", Toast.LENGTH_SHORT).show();
              fetchTodoByIdAndInsert((int) id);

          } else if (requestCode == UPDATE_TODO_REQUEST_CODE) {

              boolean isDeleted = data.getBooleanExtra("isDeleted", false);
              int number = data.getIntExtra("number", -1);
              if (isDeleted) {
                  Toast.makeText(getApplicationContext(), number + " rows deleted", Toast.LENGTH_SHORT).show();
              } else {
                  Toast.makeText(getApplicationContext(), number + " rows updated", Toast.LENGTH_SHORT).show();
              }

              loadAllTodos();

          }

      } else {
          Toast.makeText(getApplicationContext(), "No action done by user", Toast.LENGTH_SHORT).show();
      }
  }

  @SuppressLint("StaticFieldLeak")
  private void insertList(List<Todo> todoList) {
      new AsyncTask<List<Todo>, Void, Void>() {
          @Override
          protected Void doInBackground(List<Todo>... params) {
              myDatabase.daoAccess().insertTodoList(params[0]);

              return null;

          }

          @Override
          protected void onPostExecute(Void voids) {
              super.onPostExecute(voids);
          }
      }.execute(todoList);

  }

  private void checkIfAppLaunchedFirstTime() {
      final String PREFS_NAME = "SharedPrefs";

      SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);

      if (settings.getBoolean("firstTime", true)) {
          settings.edit().putBoolean("firstTime", false).apply();
          buildDummyTodos();
      }
  }
}
  • myDatabase = Room.databaseBuilder(getApplicationContext(),MyDatabase.class,MyDatabase.DB_NAME).fallbackToDestructiveMigration()。
    build();)用于初始化数据库。

  • fallbackToDestructiveMigration()提供跨数据库版本的无缝迁移而不会崩溃。

  • 我们会检查应用程序是首次启动还是不使用共享首选项。

  • 然后,我们创建一个虚拟ArrayList来填充我们的RecyclerView。

  • 我们需要使用异步任务来运行查询。
    因此,请使用AsyncTask或者使用RxJava。
    在本教程中,我们使用了AsyncTasks。

  • 我们的应用程序中将执行以下操作:从列表中更新待办事项

  • 将新的待办事项添加到列表中。

  • 对于这两种情况,我们都使用" startActivityForResult"从下一个活动中获取数据,并相应地更新RecyclerView。

  • 我们的微调器用于根据查询数据库的类别过滤RecyclerView。

RecyclerViewAdapter.java

package com.theitroad.androidroomtodolist;

import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

  private List<Todo> todoList;
  private RecyclerViewAdapter.ClickListener clickListener;

  public RecyclerViewAdapter(ClickListener clickListener) {
      this.clickListener = clickListener;
      todoList = new ArrayList<>();
  }

  @Override
  public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                           int viewType) {
      View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item_layout, parent, false);
      RecyclerViewAdapter.ViewHolder viewHolder = new RecyclerViewAdapter.ViewHolder(view);
      return viewHolder;
  }

  @Override
  public void onBindViewHolder(RecyclerViewAdapter.ViewHolder holder, int position) {
      Todo todo = todoList.get(position);
      holder.txtName.setText(todo.name);
      holder.txtNo.setText("#" + String.valueOf(todo.todo_id));
      holder.txtDesc.setText(todo.description);
      holder.txtCategory.setText(todo.category);

  }

  @Override
  public int getItemCount() {
      return todoList.size();
  }

  public void updateTodoList(List<Todo> data) {
      todoList.clear();
      todoList.addAll(data);
      notifyDataSetChanged();
  }

  public void addRow(Todo data) {
      todoList.add(data);
      notifyDataSetChanged();
  }

  public class ViewHolder extends RecyclerView.ViewHolder {

      public TextView txtName;
      public TextView txtNo;
      public TextView txtDesc;
      public TextView txtCategory;
      public CardView cardView;

      public ViewHolder(View view) {
          super(view);

          txtNo = view.findViewById(R.id.txtNo);
          txtName = view.findViewById(R.id.txtName);
          txtDesc = view.findViewById(R.id.txtDesc);
          txtCategory = view.findViewById(R.id.txtCategory);
          cardView = view.findViewById(R.id.cardView);
          cardView.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  clickListener.launchIntent(todoList.get(getAdapterPosition()).todo_id);
              }
          });
      }
  }

  public interface ClickListener {
      void launchIntent(int id);
  }
}

下面给出了activity_todo_note.xml布局的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".TodoNoteActivity">

  <android.support.design.widget.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/AppTheme.AppBarOverlay">

      <android.support.v7.widget.Toolbar
          android:id="@+id/toolbar"
          android:layout_width="match_parent"
          android:layout_height="?attr/actionBarSize"
          android:background="?attr/colorPrimary"
          app:popupTheme="@style/AppTheme.PopupOverlay" 

  </android.support.design.widget.AppBarLayout>

  <include layout="@layout/content_todo_note" 

</android.support.design.widget.CoordinatorLayout>

content_todo_note.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:layout_behavior="@string/appbar_scrolling_view_behavior"
  tools:context=".TodoNoteActivity"
  tools:showIn="@layout/activity_todo_note">

  <EditText
      android:id="@+id/inTitle"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginEnd="8dp"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="16dp"
      android:ems="10"
      android:hint="Title"
      android:text="Sample Title"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" 

  <EditText
      android:id="@+id/inDescription"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginEnd="8dp"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:ems="10"
      android:hint="Description"
      android:minLines="3"
      android:text="Sample Description"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.0"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/inTitle" 

  <Spinner
      android:id="@+id/spinner"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginEnd="8dp"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="8dp"
      android:padding="16dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/inDescription" 

  <Button
      android:id="@+id/btnDone"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginEnd="8dp"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="16dp"
      android:text="DONE"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/spinner" 

  <Button
      android:id="@+id/btnDelete"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginTop="8dp"
      android:text="DELETE"
      android:visibility="gone"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/btnDone" 

</android.support.constraint.ConstraintLayout>

下面给出了TodoNoteActivity.java类的代码

package com.theitroad.androidroomtodolist;

import android.annotation.SuppressLint;
import android.arch.persistence.room.Room;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;

import java.util.ArrayList;
import java.util.Arrays;

public class TodoNoteActivity extends AppCompatActivity {

  Spinner spinner;
  EditText inTitle, inDesc;
  Button btnDone, btnDelete;
  boolean isNewTodo = false;

  private String[] categories = {
          "Android",
          "iOS",
          "Kotlin",
          "Swift"
  };

  public ArrayList<String> spinnerList = new ArrayList<>(Arrays.asList(categories));
  MyDatabase myDatabase;

  Todo updateTodo;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_todo_note);
      Toolbar toolbar = findViewById(R.id.toolbar);
      setSupportActionBar(toolbar);

      spinner = findViewById(R.id.spinner);
      inTitle = findViewById(R.id.inTitle);
      inDesc = findViewById(R.id.inDescription);
      btnDone = findViewById(R.id.btnDone);
      btnDelete = findViewById(R.id.btnDelete);
      ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, spinnerList);
      adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      spinner.setAdapter(adapter);

      myDatabase = Room.databaseBuilder(getApplicationContext(), MyDatabase.class, MyDatabase.DB_NAME).build();

      int todo_id = getIntent().getIntExtra("id", -100);

      if (todo_id == -100)
          isNewTodo = true;

      if (!isNewTodo) {
          fetchTodoById(todo_id);
          btnDelete.setVisibility(View.VISIBLE);
      }

      btnDone.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              if (isNewTodo) {
                  Todo todo = new Todo();
                  todo.name = inTitle.getText().toString();
                  todo.description = inDesc.getText().toString();
                  todo.category = spinner.getSelectedItem().toString();

                  insertRow(todo);
              } else {

                  updateTodo.name = inTitle.getText().toString();
                  updateTodo.description = inDesc.getText().toString();
                  updateTodo.category = spinner.getSelectedItem().toString();

                  updateRow(updateTodo);
              }
          }
      });

      btnDelete.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              deleteRow(updateTodo);
          }
      });
  }

  @SuppressLint("StaticFieldLeak")
  private void fetchTodoById(final int todo_id) {
      new AsyncTask<Integer, Void, Todo>() {
          @Override
          protected Todo doInBackground(Integer... params) {

              return myDatabase.daoAccess().fetchTodoListById(params[0]);

          }

          @Override
          protected void onPostExecute(Todo todo) {
              super.onPostExecute(todo);
              inTitle.setText(todo.name);
              inDesc.setText(todo.description);
              spinner.setSelection(spinnerList.indexOf(todo.category));

              updateTodo = todo;
          }
      }.execute(todo_id);

  }

  @SuppressLint("StaticFieldLeak")
  private void insertRow(Todo todo) {
      new AsyncTask<Todo, Void, Long>() {
          @Override
          protected Long doInBackground(Todo... params) {
              return myDatabase.daoAccess().insertTodo(params[0]);
          }

          @Override
          protected void onPostExecute(Long id) {
              super.onPostExecute(id);

              Intent intent = getIntent();
              intent.putExtra("isNew", true).putExtra("id", id);
              setResult(RESULT_OK, intent);
              finish();
          }
      }.execute(todo);

  }

  @SuppressLint("StaticFieldLeak")
  private void deleteRow(Todo todo) {
      new AsyncTask<Todo, Void, Integer>() {
          @Override
          protected Integer doInBackground(Todo... params) {
              return myDatabase.daoAccess().deleteTodo(params[0]);
          }

          @Override
          protected void onPostExecute(Integer number) {
              super.onPostExecute(number);

              Intent intent = getIntent();
              intent.putExtra("isDeleted", true).putExtra("number", number);
              setResult(RESULT_OK, intent);
              finish();
          }
      }.execute(todo);

  }

  @SuppressLint("StaticFieldLeak")
  private void updateRow(Todo todo) {
      new AsyncTask<Todo, Void, Integer>() {
          @Override
          protected Integer doInBackground(Todo... params) {
              return myDatabase.daoAccess().updateTodo(params[0]);
          }

          @Override
          protected void onPostExecute(Integer number) {
              super.onPostExecute(number);

              Intent intent = getIntent();
              intent.putExtra("isNew", false).putExtra("number", number);
              setResult(RESULT_OK, intent);
              finish();
          }
      }.execute(todo);

  }

}

setResult(RESULT_OK,intent);用于将结果传递回MainActivity。
我们或者传递新的待办任务的ID,或者传递删除/更新的行数,并相应地更新RecyclerView。