您好,欢迎来到源码搜藏网!分享精神,快乐你我!
[加入VIP] 设为首页 | 收藏本站 | 网站地图 | Sitemap | TAG标签
  • 特码历史记录
  • 在线工具
  • jquery手册
  • 2018 香港开奖记录结果:如何使用Room和Recyclerview以及ViewModel在Android中使用数据库

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

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

    特码历史记录 www.lm47u.com 本文解决了典型的任务:

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

    背景

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

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

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

    使用代码

    开始吧!在Android studio中创建一个新项目(我使用的是版本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="//schemas.android.com/apk/res/android"
    
        xmlns:app="//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="//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="//schemas.android.com/apk/res/android"
    
        xmlns:app="//schemas.android.com/apk/res-auto"
    
        xmlns:tools="//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中使用数据库

    让我们转到数据库。这个应用程序侧重于成分即的一个子集LiveData,ViewModelRoom。此图显示了此体系结构的基本形式。你可以在这里阅读更多相关信息。

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

    添加一些build.gradleapp??椋?/font>

    // 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并从便捷注释生成查询以查找常见查询,例如@Insert, @Delete,@Query。DAO必须是一个interfaceabstract类。默认情况下,所有查询都必须在单独的线程上执行。好的,做我们自己的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类处理数据的操作。它为应用程序数据的应用程序的其余部分提供了一个干净的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类分开可以让您更好地遵循单一责任原则:您的活动和片段负责将数据绘制到屏幕,同时您ViewModel可以负责保存和处理UI所需的所有数据。

    ViewModel,LiveData用于UI将使用或显示的可变数据。使用LiveData有几个好处:

    • 您可以将观察者放在数据上(而不是轮询更改),只在数据实际更改时更新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。当活动被销毁时,例如,通过配置更改,ViewModel持续存在。重新创建活动时,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(如果需要,请阅读此内容)。这可以防止内存泄漏,并以一种能够在配置更改后幸存的方式使用生命周期。

    如何使用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");
            }
        }
    }

    我希望这篇简单的文章可以帮到你。您可以轻松改进此应用程序。我喜欢开发应用程序,所以你可以在这里尝试其中的一些。

    如何使用Room和Recyclerview以及ViewModel在Android中使用数据库转载//www.lm47u.com/appboke/39579.html
    629| 144| 262| 951| 972| 122| 140| 750| 736| 623|