• <code id="58gs9"></code>

      <mark id="58gs9"></mark>
      1. 当前位置£º首页 > 安卓源码 > 技术博客 >

        如何使用Room和Recyclerview以及ViewModel在Android中使用数据库

        时间£º2019-02-28 22:44 来源£º互联网 作者£º源码搜藏 浏览£º 收藏 挑错 推荐 打印

        本文解决了典型的任务£º 在应用程序中存储数据 - 使用Room 向用户显示数据 - 使用片段和recyclerview 存储并使用自动更新数据 ViewModel 背景 Room提供了一个覆盖SQLite的抽象层£¬以便在利用SQLite的全部功能的同时进行流畅的数据库访问¡£ 该应用程序使用 Ro

        本文解决了典型的任务£º

        • 在应用程序中存储数据 - 使用Room
        • 向用户显示数据 - 使用片段和recyclerview
        • 存储并使用自动更新数据 ViewModel

        背景

        Room提供了一个覆盖SQLite的抽象层£¬以便在利用SQLite的全部功能的同时进行流畅的数据库访问¡£该应用程序使用Room数据库来获取与该数据库关联的数据访问对象或DAO¡£然后£¬应用程序使用每个DAO从数据库中获取实体£¬并将对这些实体的任何更改保存回数据库¡£最后£¬应用程序使用实体来获取和设置与数据库中的表列对应的值¡£

        RecyclerView窗口小部件中£¬几个不同的组件一起工作以显示您的数据£¨对象列表£©¡£用户界面的整个容器是RecyclerView您添加到布局对象¡£RecyclerView由您提供的布局管理器提供的意见罢了本身¡£您可以使用我们的标准布局管理器£¨例如LinearLayoutManagerGridLayoutManager£©£¬或实现您自己的¡£

        ViewModel是一个负责准备和管理活动或片段数据的类¡£它还处理Activity / Fragment与应用程序其余部分的通信¡£换句话说£¬这意味着ViewModel如果其所有者因配置更?#27169;?#20363;如旋转£©而被销毁£¬则不会销毁该文件¡£所有者的新实例将重新连接到现有实例ViewModel¡£

        使用代码

        开?#21450;É£?/font>在Android studio中创建一个新项目£¨我使用的?#21069;?#26412;3.2.1£©£¬或者您可以下载源文件并选择£ºFile-New-Import项目¡£我们将构建一个这样的应用程序£º

        如何使用Room和Recyclerview以及ViewModel在Android中使用数据库

        您可以根据需要在数据库中添加和删除数据并将其显示在屏幕上¡£

        我们需要数据类DataItem£º

        public class DataItem {
            private long id;
            private String name;
            private String content;
            private String details;
            private String section;
        }

        它是类 - 我们存储在数据库中的数据¡£为了显示这些数据£¬我们使用RecyclerView小部件¡£创建新片段£ºFile-New-Fragment-Fragment£¨列表£©¡£RecyclerView使用两个XML文件£º一个文件表示列表项£¬第二个文件表示项的完整列表¡£进行一些更改fragment_item£º添加CardView小部件并制作自定义Textview元素¡£也增加了build.gradleCardview小部件£º

        //for recyclerview items
        implementation 'com.android.support:cardview-v7:28.0.0'

        Fragment_item.xml£º

        <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        
            xmlns:app="http://schemas.android.com/apk/res-auto"
        
            android:layout_width="match_parent"
        
            android:layout_height="wrap_content"
        
            android:orientation="vertical">
        
            <android.support.v7.widget.CardView
        
                android:id="@+id/card_view"
        
                android:layout_width="match_parent"
        
                android:layout_height="wrap_content"
        
        
        
                android:layout_margin="2dp"
        
                app:cardCornerRadius="2dp"
        
                app:cardElevation="3dp"
        
                app:cardUseCompatPadding="true">
        
                <LinearLayout
        
                    android:layout_width="match_parent"
        
                    android:layout_height="wrap_content"
        
                    android:layout_gravity="center"
        
                    android:orientation="horizontal">
        
                    <TextView
        
                        android:id="@+id/item_number"
        
                        android:layout_width="wrap_content"
        
                        android:layout_height="wrap_content"
        
                        android:layout_margin="@dimen/text_margin"
        
                        android:background="@drawable/round_shape"
        
                        android:gravity="center"
        
                        android:text="1"
        
                        android:textAppearance="?attr/textAppearanceListItem"
        
                        android:textColor="@color/colorWhite" />
        
                    <TextView
        
                        android:id="@+id/item_name"
        
                        android:layout_width="wrap_content"
        
                        android:layout_height="wrap_content"
        
                        android:layout_margin="@dimen/text_margin"
        
                        android:text="text"
        
                        android:textAppearance="?attr/textAppearanceListItem" />
        
                    <LinearLayout
        
                        android:layout_width="match_parent"
        
                        android:layout_height="wrap_content"
        
                        android:layout_gravity="center"
        
                        android:gravity="end"
        
                        android:orientation="horizontal">
        
                        <TextView
        
                            android:id="@+id/item_section"
        
                            android:layout_width="wrap_content"
        
                            android:layout_height="wrap_content"
        
                            android:layout_gravity="center"
        
                            android:layout_margin="@dimen/text_margin"
        
                            android:text="section"
        
                            android:textAppearance="?attr/textAppearanceListItem" />
        
                        <ImageView
        
                            android:id="@+id/image_delete"
        
                            android:layout_width="40dp"
        
                            android:layout_height="40dp"
        
                            android:padding="8dp"
        
                            android:src="@drawable/ic_delete2" />
                    </LinearLayout>
        
                </LinearLayout>
            </android.support.v7.widget.CardView>
        </LinearLayout>

        如何使用Room和Recyclerview以及ViewModel在Android中使用数据库

        Textview使用数字进行红色循环£¬我们需要round_shape.xml£º

        <?xml version="1.0" encoding="utf-8"?>
        <shape xmlns:android="http://schemas.android.com/apk/res/android"
        
            android:shape="oval">
            <solid android:color="#FF0000" />
            <size
        
                android:width="30dp"
        
                android:height="30dp" />
        </shape>

        并将background我们的值设置TextViewround_shape.xml£º

        android:background="@drawable/round_shape"

        添加按钮到fragment_list.xml£º

        <?xml version="1.0" encoding="utf-8"?>
        
        <LinearLayout 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:layout_width="match_parent"
        
            android:layout_height="match_parent"
        
            android:orientation="vertical">
        
            <LinearLayout
        
                android:layout_width="match_parent"
        
                android:layout_height="wrap_content"
        
                android:orientation="vertical">
        
                <Button
        
                    android:id="@+id/add_button"
        
                    android:layout_width="wrap_content"
        
                    android:layout_height="wrap_content"
        
                    android:layout_gravity="end"
        
                    android:layout_margin="@dimen/list_margin"
        
                    android:text="Add" />
            </LinearLayout>
        
            <LinearLayout
        
                android:layout_width="match_parent"
        
                android:layout_height="wrap_content"
        
                android:orientation="vertical">
        
                <android.support.v7.widget.RecyclerView
        
                    android:id="@+id/list"
        
                    android:layout_width="match_parent"
        
                    android:layout_height="wrap_content"
        
                    android:layout_marginLeft="@dimen/list_margin"
        
                    android:layout_marginRight="@dimen/list_margin"
        
                    app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        
                    tools:context=".fragment.ListFragment"
        
                    tools:listitem="@layout/fragment_item" />
            </LinearLayout>
        </LinearLayout>

        如何使用Room和Recyclerview以及ViewModel在Android中使用数据库

        ?#26790;?#20204;转到数据库¡£这个应用程序侧重于成分即的一个子集LiveData£¬ViewModelRoom¡£此图显示了此体系结构的基本?#38382;½¡?/font>你可以在这里阅读更多相关信息¡£

        如何使用Room和Recyclerview以及ViewModel在Android中使用数据库

        添加一些build.gradleapp模块£º

        // Room components
            implementation "android.arch.persistence.room:runtime:1.1.1"
            annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
            androidTestImplementation "android.arch.persistence.room:testing:1.1.1"
        
        // Lifecycle components
            implementation "android.arch.lifecycle:extensions:1.1.1"
            annotationProcessor "android.arch.lifecycle:compiler:1.1.1"

        要使DataItem该类对Room数据库有意义£¬您需要对其进行注释¡£注释标识此类的每个部分如何与数据库中的条目相关¡£Room使用此信息生成代码¡£

        • @Entity(tableName = "data_item_table")
          每个@Entity类代表一个表中的实体¡£注释您的类声明以指示它是一个实体¡£如果希望它与类的名称不同£¬请指定表的名称¡£
        • @PrimaryKey
          每个实体都需要一个主键¡£为了简单起见£¬每个单词都作为自己的主键¡£
        • @NonNull
          表示参数£¬字段或方法返回值永远不会null¡£
        • @ColumnInfo(name = "name")
          如果希望它与成员变量的名称不同£¬请在表中指定列的名称¡£
        • 存储在数据库中的每个字段都必须是public或具有“ getter”方法¡£此示例提供了一种geName()方法¡£

        将我们的课程改为£º

        @Entity
        public class DataItem {
            @PrimaryKey(autoGenerate = true)
            @NonNull
            private long id;
            private String name;
            private String content;
            private String details;
            private String section;
        
            @Ignore
            public DataItem(String name, String content, String details, String section) {
                this.name = name;
                this.content = content;
                this.details = details;
                this.section = section;
            }
        
            public void setId(long id) {
                this.id = id;
            }
        
            public long getId() {
                return id;
            }
        
            public String getName() {
                return name;
            }
        
            public String getContent() {
                return content;
            }
        
            public String getDetails() {
                return details;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public void setContent(String content) {
                this.content = content;
            }
        
            public void setDetails(String details) {
                this.details = details;
            }
        
            public String getSection() {
                return section;
            }
        
            public void setSection(String section) {
                this.section = section;
            }
        
            public DataItem() {
                this.name = "name";
                this.content = "content";
                this.details = "details";
                this.section = "section";
            }
        }

        DAO£¨数据访问对象£©中£¬指定SQL查询并将它们与方法调用相关联¡£编译器检查SQL并从便捷注释生成查询以查?#39029;?#35265;查询£¬例如@Insert, @Delete,@Query¡£DAO必须是一个interfaceabstract类¡£默认情况下£¬所有查询都必须在单独的线程?#29616;?#34892;¡£好的£¬做我们自己的DAO interface¡£

        @Dao
        public interface DataDAO {
        
            //Insert one item
            @Insert(onConflict = IGNORE)
            void insertItem(DataItem item);
        
            // Delete one item
            @Delete
            void deleteItem(DataItem person);
        
            //Delete one item by id
            @Query("DELETE FROM dataitem WHERE id = :itemId")
            void deleteByItemId(long itemId);
        
            //Get all items
            @Query("SELECT * FROM DataItem")
            LiveData<List<DataItem>> getAllData();
        
            //Delete All
            @Query("DELETE FROM DataItem")
            void deleteAll();
        }

        数据更改时£¬通常需要执行某些操作£¬例如在UI中显示更新的数据¡£这意味着您必须观察数据£¬以便在更改时£¬您可以做出反应¡£LiveData£¬一个用于数据观察的生命周期库类£¬解决了这个问题¡£LiveData在方法描述中使用type的返回值£¬并Room生成所有必需的代码以更新LiveData数据库的更新时间¡£

        接下来£¬根据创建数据库类RoomDatabase£º

        @Database(entities = {DataItem.class}, version = 1, exportSchema = false)
        public abstract class DataRoomDbase extends RoomDatabase {
        
            private static DataRoomDbase INSTANCE;
        
            public abstract DataDAO dataDAO();
        
            public static DataRoomDbase getDatabase(Context context) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(), 
                               DataRoomDbase.class, DataRoomDbase.class.getName())
                            //if you want create db only in memory, not in file
                            //Room.inMemoryDatabaseBuilder
                            //(context.getApplicationContext(), DataRoomDbase.class)
                            .build();
                }
                return INSTANCE;
            }
        
            public static void destroyInstance() {
                INSTANCE = null;
            }
        }

        接下来£¬创建存储库¡£Repository是抽象访问多个数据源的类¡£Repository不是体系结构组件库的一部分£¬但对于代码的分离和架构的建议最佳实践¡£Repository类处理数据的操作¡£它为应用程序数据的应用程序的其余部分提供了一个?#21024;?#30340;API¡£像这样£º

        public class DataRepository {
            private DataDAO mDataDao;
            private LiveData<List<DataItem>> mAllData;
        
            public DataRepository(Application application) {
                DataRoomDbase dataRoombase = DataRoomDbase.getDatabase(application);
                this.mDataDao = dataRoombase.dataDAO();
                this.mAllData = mDataDao.getAllData();
            }
        
            LiveData<List<DataItem>> getAllData() {
                return mAllData;
            }
        
        // You must call this on a non-UI thread or your app will crash
        
            public void insert(DataItem dataItem) {
                new insertAsyncTask(mDataDao).execute(dataItem);
            }
        
            private static class insertAsyncTask extends AsyncTask<DataItem, Void, Void> {
                private DataDAO mAsyncTaskDao;
                insertAsyncTask(DataDAO dao) {
                    mAsyncTaskDao = dao;
                }
        
                @Override
                protected Void doInBackground(final DataItem... params) {
                    mAsyncTaskDao.insertItem(params[0]);
                    return null;
                }
            }
        
            public void deleteItem(DataItem dataItem) {
                new deleteAsyncTask(mDataDao).execute(dataItem);
            }
        
            private static class deleteAsyncTask extends AsyncTask<DataItem, Void, Void> {
                private DataDAO mAsyncTaskDao;
                deleteAsyncTask(DataDAO dao) {
                    mAsyncTaskDao = dao;
                }
        
                @Override
                protected Void doInBackground(final DataItem... params) {
                    mAsyncTaskDao.deleteItem(params[0]);
                    return null;
                }
            }
        
            public void deleteItemById(Long idItem) {
                new deleteByIdAsyncTask(mDataDao).execute(idItem);
            }
        
            private static class deleteByIdAsyncTask extends AsyncTask<Long, Void, Void> {
                private DataDAO mAsyncTaskDao;
                deleteByIdAsyncTask(DataDAO dao) {
                    mAsyncTaskDao = dao;
                }
        
                @Override
                protected Void doInBackground(final Long... params) {
                    mAsyncTaskDao.deleteByItemId(params[0]);
                    return null;
                }
            }
        }

        根据ViewModel创建新类£º

        public class DataViewModel extends AndroidViewModel {
        
            private DataRepository mDataRepository;
            private LiveData<List<DataItem>> mListLiveData;
        
            public DataViewModel(@NonNull Application application) {
                super(application);
                mDataRepository = new DataRepository((application));
                mListLiveData = mDataRepository.getAllData();
            }
        
            public LiveData<List<DataItem>> getAllData() {
                return mListLiveData;
            }
        
            public void insertItem(DataItem dataItem) {
                mDataRepository.insert(dataItem);
            }
        
            public void deleteItem(DataItem dataItem) {
                mDataRepository.deleteItem(dataItem);
            }
        
            public void deleteItemById(Long idItem) {
                mDataRepository.deleteItemById(idItem);
            }
        }

        ViewModel以生命周期方式保存应用程序的UI数据£¬以便在配置更改后继续存在¡£将应用程序的UI数据与您的ActivityFragment类分开可以让您更好地遵循单一责任原则£º您的活动和片段负责将数据绘?#39057;?#23631;幕£¬同时您ViewModel可以负责保存和处理UI所需的所有数据¡£

        ViewModel£¬LiveData用于UI将使用或显示的可变数据¡£使用LiveData有几个好处£º

        • 您可以将观察者放在数据上£¨而不是轮询更?#27169;©£?#21482;在数据实际更改时更新UI¡£
        • Repository和UI完全被分离ViewModel¡£没有数据库调用ViewModel£¬使代码更易于测试¡£
        public class MainActivity extends AppCompatActivity 
                 implements ListFragment.OnListFragmentInteractionListener,
                AlertDialogFragment.AlertDialogListener {
        
            private DataViewModel mDataViewModel;
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        
                mDataViewModel = ViewModelProviders.of(this).get(DataViewModel.class);
                getSupportFragmentManager()
                        .beginTransaction()
                        .replace(R.id.main_layout, new ListFragment())
                        .addToBackStack("list")
                        .commit();
            }
        
            @Override
            public void onListClickItem(DataItem dataItem) {
                Toast.makeText(this, dataItem.getDetails(), Toast.LENGTH_SHORT).show();
            }
        
            @Override
            public void onListFragmentDeleteItemById(long idItem) {
                Bundle bundle = new Bundle();
                bundle.putLong(ID_LONG, idItem);
        
                AlertDialogFragment alertDialogFragment = new AlertDialogFragment();
                alertDialogFragment.setArguments(bundle);
                alertDialogFragment.show(getSupportFragmentManager(), "Allert");
            }
        
            @Override
            public void onDialogPositiveClick(DialogFragment dialog, long idItem) {
                mDataViewModel.deleteItemById(idItem);
                Toast.makeText(this, getString(R.string.message_delete), Toast.LENGTH_SHORT).show();
            }
        
            @Override
            public void onDialogNegativeClick(DialogFragment dialog) {
                Toast.makeText(this, getString(R.string.message_cancel), Toast.LENGTH_SHORT).show();
        
            }
        }

        用于ViewModelProviders将您ViewModel与UI控制器关联¡£当您的应用首次启动时£¬ViewModelProviders将创建ViewModel¡£当活动被销毁时£¬例如£¬通过配置更?#27169;?/font>ViewModel?#20013;?#23384;在¡£重新创建活动时£¬ViewModelProviders返回现有的活动ViewModel¡£

        public class ListFragment extends Fragment {
        
            private DataViewModel viewModel;
            private List<DataItem> mDataItemList;
            private ListRecyclerViewAdapter mListAdapter;
            private OnListFragmentInteractionListener mListener;
        
            public void setListData(List<DataItem> dataItemList) {
                //if data changed, set new list to adapter of recyclerview
        
                if (mDataItemList == null) {
                    mDataItemList = new ArrayList<>();
                }
                mDataItemList.clear();
                mDataItemList.addAll(dataItemList);
        
                if (mListAdapter != null) {
                    mListAdapter.setListData(dataItemList);
                }
            }
        
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                     Bundle savedInstanceState) {
                View view = inflater.inflate(R.layout.fragment_list, container, false);
                Context context = view.getContext();
                //set recyclerview
                RecyclerView recyclerView = view.findViewById(R.id.list);
                recyclerView.setLayoutManager(new LinearLayoutManager(context));
                mListAdapter = new ListRecyclerViewAdapter(mListener);
        
                if (mDataItemList != null) {
                    mListAdapter.setListData(mDataItemList);
                }
                recyclerView.setAdapter(mListAdapter);
        
                //Add new item to db
                Button addButton = (Button) view.findViewById(R.id.add_button);
                addButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
        
                        viewModel.insertItem(new DataItem());
        
                    }
                });
        
                return view;
            }
        
            @Override
            public void onActivityCreated(@Nullable Bundle savedInstanceState) {
                super.onActivityCreated(savedInstanceState);
                //get viewmodel
                viewModel = ViewModelProviders.of(this).get(DataViewModel.class);
                //bind to Livedata
                viewModel.getAllData().observe(this, new Observer<List<DataItem>>() {
                    @Override
                    public void onChanged(@Nullable List<DataItem> dataItems) {
                        if (dataItems != null) {
                            setListData(dataItems);
                        }
                    }
                });
            }
        
            @Override
            public void onAttach(Context context) {
                super.onAttach(context);
                if (context instanceof OnListFragmentInteractionListener) {
                    mListener = (OnListFragmentInteractionListener) context;
                } else {
                    throw new RuntimeException(context.toString()
                            + " must implement OnListFragmentInteractionListener");
                }
            }
        
            @Override
            public void onDetach() {
                super.onDetach();
                mListener = null;
            }
            
            public interface OnListFragmentInteractionListener {
                //onClick items of list
                void onListClickItem(DataItem dataItem);
        
                //onClick delete item from list
                void onListFragmentDeleteItemById(long idItem);
            }
        }

        另外£¬要显示警告对话框£¬当您想要从数据库中删除数据时£¬我创建了一个新类 - AlertDialogFragment£¨如果需要£¬请阅读此内容£©¡£这可以?#20048;?#20869;存泄漏£¬并以一种能够在配置更改后幸存的方式使用生命周期¡£

        如何使用Room和Recyclerview以及ViewModel在Android中使用数据库

        如何使用Room和Recyclerview以及ViewModel在Android中使用数据库

        public class AlertDialogFragment extends DialogFragment {
        
            AlertDialogListener mListener;
            public static String ID_LONG = "ID_LONG";
            long id_data;
        
            public interface AlertDialogListener {
                void onDialogPositiveClick(DialogFragment dialog, long idItem);
        
                void onDialogNegativeClick(DialogFragment dialog);
            }
        
            @Override
            @NonNull
            public Dialog onCreateDialog(Bundle savedInstanceState) {
        
                Activity activity = getActivity();
                Bundle bundle = getArguments();
        
                if (bundle != null && activity != null) {
                    //get data from bundle
                    id_data = bundle.getLong(ID_LONG);
                    // Use the Builder class for convenient dialog construction
                    AlertDialog.Builder builder = new AlertDialog.Builder(activity);
                    builder.setMessage(R.string.message_dialog)
                            .setPositiveButton(R.string.message_yes, new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    // set listener for yes button
                                    mListener.onDialogPositiveClick(AlertDialogFragment.this, id_data);
                                }
                            })
                            .setNegativeButton(R.string.message_no, new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    // User cancelled the dialog
                                    mListener.onDialogNegativeClick(AlertDialogFragment.this);
                                }
                            });
                    // Create the AlertDialog object and return it
                    return builder.create();
                }
                //if no bundle - show error
                AlertDialog.Builder builder = new AlertDialog.Builder(activity)
                        .setNegativeButton(R.string.message_error, new DialogInterface.OnClickListener() {
        
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
        
                            }
                        });
                return builder.create();
            }
        
            // Override the Fragment.onAttach() method to instantiate the DialogListener
        
            @Override
            public void onAttach(Context context) {
                super.onAttach(context);
                // Verify that the host activity implements the callback interface
                try {
                    // Instantiate the DialogListener so we can send events to the host
                    mListener = (AlertDialogListener) context;
                } catch (ClassCastException e) {
                    // The activity doesn't implement the interface, throw exception
                    throw new ClassCastException(context.toString()
                            + " must implement AlertDialogListener");
                }
            }
        }

        我希望这篇简单的文章可以帮到你¡£您可以轻松改进此应用程序¡£我?#19981;?#24320;发应用程序£¬所以你可以在这里尝试其中的一些¡£

        如何使用Room和Recyclerview以及ViewModel在Android中使用数据库转载<\/script>');
        ´ó¸»ÎÌÆåÅÆÓéÀÖ¹ÙÍø

      2. <code id="58gs9"></code>

          <mark id="58gs9"></mark>

          1. <code id="58gs9"></code>

              <mark id="58gs9"></mark>