学习开源项目MyDiary第二天---实现通讯录功能
继续学习GitHub的开源项目MyDiary,它的地址是https://github.com/DaxiaK/MyDiary。
截止目前为止我的代码是https://github.com/BILY5354/OurDiaryGit
还参考了b站教程https://www.bilibili.com/video/BV1ct411K7tp?from=search&seid=9028382545153013472
(注意现在的通讯录功能是有bug的在git上又说明)
上面三幅图是MyDiary的功能,长按可以修改,短按可以拔出电话。MyDiary的数据库操作是用SQLHelper的,但现在2021年有了Room来操作数据库(感觉用Kotlin写更好,不过学校安卓课程一定要用Java),用Room的好处就是,当有新的通讯录新增时,不需要写加载数据库文件的代码而是设置一个观察者,Room就会帮我们把新的数据显示到RecyclerView中。因此,具体需要自己实现的功能有
- 用Room保存通讯录数据,基本的增删改
- 实现搜索功能
首先是通讯录表的设定,分别有通讯录id、通讯录名称、通讯录电话号码和参考的主页Recyclerview_id,最后一个Recyclerview_id的功能是,因为主页的RecyclerView有不同的通讯录的,如初中通讯录、高中通讯录和大学通讯录等等,但是这些通讯录其实都是保存到同一张数据表中,然后根据它们在主页RecyclerView的ID找到对应的通讯录。也就是当我点击了高中通讯录时,在通讯录的Activity中用条件语句查找通许录表中RecyclerView为高中通讯录的id就可以了。
新建Contacts文件夹,专门用来实现通讯录的功能,实现通讯录所需要的有CallDialogFragment.java是当按下时弹出对话框用的(),Adapter则是RecyclerView所需要的文件,LatterSortLayout是用于实现侧边字母栏。
- CallDialogFragment.java 短按item时,会弹出用于打电话的对话框。
- ContactsActivity.java 本通讯录界面的Activity。
- ContactsAdapter.java 显示本界面的RecyclerView。
- ContactsDetailDialogFragment.java 用于修改或新增通讯录的对话行弹框,会与ContactsActivity进行通讯数据的交互,因为当点击新增通讯录按钮时,弹出此框,点击保存后,需要获取此对话弹框中的EditText中通讯录名字与电话号码并插入发到到数据库中进行保存,所有的与数据库有关的操作将都会在Activity中进行。
- ContactsEntity.java 和数据库中的通讯录表一一对应,主要用于每次创建一个ArrayList放入通讯录表中(对应topic id号)的全部通讯录数据,为什么已经有了数据库的表,显示时候直接用数据表中的数据显示,还需要放入到一个新的List中。因为,想要实现通讯录按照字母排序的话,只能先将数据取出来,再进行排序,到时候显示就用这个list进行显示,每次数据修改时(新增或删除)都需要将List清空再重新赋值。
- LatterSortLayout.java 显示侧边栏字母排序的类。
使用Room需要创建的文件有,
- Contact.java 用于创建通讯录表的信息,这里创建的表是在SQLite Expert是这样的(rowid不是)
- ContactDao.java 用于
- ContactRepository.java
- ContactRoomDatabase.java
- ContactViewModel
这部分要创建的文件好多,不过可以直接看谷歌的教程https://developer.android.com/codelabs/android-room-with-a-view#0,就能大致知道为什么需要创建这些文件了。
Fragment与宿主Activity间传递数据,可以在官方文档中看到它的描述是这样的,它的地址是https://developer.android.com/guide/fragments/communicate#receive-host-activity,所以获取对话弹框中通讯录的信息,并在Activity中对其进行数据库的操作,并且为了代码的复用,所以新增日记和更新日记(原有日记上修改)都是用此对话弹框,那么就需要判断为什么现在是新增情况还是修改情况。
在ContactsActivity的onCreate中添加这些代码
1 //add one 2 getSupportFragmentManager().setFragmentResultListener("contacts_detail_fg_add", 3 this, new FragmentResultListener() { 4 @Override 5 public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle bundle) { 6 String result_name, result_phone_number; 7 result_name = bundle.getString("contacts_detail_fg_add_name"); 8 result_phone_number = bundle.getString("contacts_detail_fg_add_phone_number"); 9 Contact contact = new Contact(result_name, result_phone_number, 1); 10 mContactViewModel.insert(contact); 11 } 12 }); 13 //update one 14 getSupportFragmentManager().setFragmentResultListener("contacts_detail_fg_update", 15 this, new FragmentResultListener() { 16 @Override 17 public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle bundle) { 18 int result_id = bundle.getInt("contacts_detail_fg_update_id"); 19 String result_name, result_phone_number; 20 result_name = bundle.getString("contacts_detail_fg_update_name"); 21 result_phone_number = bundle.getString("contacts_detail_fg_update_phone_number"); 22 Contact contact = new Contact(result_name, result_phone_number, 1); 23 contact.setId(result_id); 24 mContactViewModel.update(contact); 25 } 26 });
在ContactsDetailDialogFragment的onCreateDialog中添加以下代码,顺便加入了判断是新增还是更新模式,isEditMode这个boolean值是怎么来的呢,在创建此ContactsDetailDialogFragment的NEWINSTANCE会填入构造参数
1 /**if is added button clicked, the ContactsDetailDialog will not show the delete fab*/ 2 if (isEditMode) { 3 fab_delete_one.setVisibility(view.VISIBLE); 4 5 } else { 6 fab_delete_one.setVisibility(view.GONE); 7 } 8 9 /**below are three FAB button for update back delete one function*/ 10 fab_update.setOnClickListener(update -> { 11 Bundle result = new Bundle(); 12 if (isEditMode) //if is edit mode, update it, else, add the new one 13 { 14 15 result.putInt("contacts_detail_fg_update_id", contactsId); 16 result.putString("contacts_detail_fg_update_name", et_contacts_detail_name.getText().toString()); 17 result.putString("contacts_detail_fg_update_phone_number",et_contacts_detail_phone_number.getText().toString()); 18 getParentFragmentManager().setFragmentResult("contacts_detail_fg_update", result); 19 Toast.makeText(getContext(), "更新成功^-^", Toast.LENGTH_SHORT).show(); 20 } else { 21 22 result.putString("contacts_detail_fg_add_name", et_contacts_detail_name.getText().toString()); 23 result.putString("contacts_detail_fg_add_phone_number",et_contacts_detail_phone_number.getText().toString()); 24 getParentFragmentManager().setFragmentResult("contacts_detail_fg_add", result); 25 Toast.makeText(getContext(), "添加成功^-^", Toast.LENGTH_SHORT).show(); 26 } 27 dismiss(); 28 });
前面提到了需要每次都将数据塞入到List中,所以在Activity中添加一个loadContacts()方法,该方法会设置一个观察者观察通讯录表的数据是否发生变化,如果有变化,则重新塞入。想要确定for循环的次数,只需要用
contacts.size()方法就可以,因为本来它也是一个list(只不过不能在这个List中排序,所以需要塞入一个List中)。
1 private void loadContacts() { 2 3 mContactViewModel.getSpecificContacts(topicId).observe(this, new Observer<List<Contact>>() { 4 @Override 5 public void onChanged(List<Contact> contacts) { 6 7 contactsNamesList.clear(); 8 9 for (int i = 0; i < contacts.size(); i++) { 10 contactsNamesList.add(new ContactsEntity( 11 contacts.get(i).getId(), 12 contacts.get(i).getContacts_name(), 13 contacts.get(i).getContacts_phone_number(), 14 contacts.get(i).getStrId()));//photo先塞入数据库数据 后期是要放图片的 15 } 16 17 contactsNamesList = sortContacts(contactsNamesList); 18 19 } 20 }); 21 22 23 }