更改目录结构,增加拖动排序并更新数据库

This commit is contained in:
2025-10-22 11:36:35 +08:00
parent 80f7e47511
commit 70fd325c00
11 changed files with 199 additions and 49 deletions

View File

@@ -7,7 +7,6 @@ import androidx.lifecycle.Observer;
import com.ttstd.dialer.R;
import com.ttstd.dialer.base.mvvm.BaseMvvmActivity;
import com.ttstd.dialer.contact.Contact;
import com.ttstd.dialer.databinding.ActivityContactAddBinding;
import com.ttstd.dialer.filter.NoSpaceInputFilter;
@@ -58,8 +57,7 @@ public class ContactAddActivity extends BaseMvvmActivity<ContactAddViewModel, Ac
public void save(View view) {
String name = mViewDataBinding.etName.getText().toString();
String phone = mViewDataBinding.etPhone.getText().toString();
Contact contact = new Contact(name, phone);
mViewModel.insert(contact);
mViewModel.saveContact(name, phone);
}
}
}

View File

@@ -5,13 +5,21 @@ import android.util.Log;
import androidx.lifecycle.MutableLiveData;
import com.trello.rxlifecycle4.RxLifecycle;
import com.trello.rxlifecycle4.android.ActivityEvent;
import com.ttstd.dialer.base.mvvm.BaseViewModel;
import com.ttstd.dialer.contact.Contact;
import com.ttstd.dialer.contact.ContactRepository;
import com.ttstd.dialer.databinding.ActivityContactAddBinding;
import com.ttstd.dialer.db.contact.Contact;
import com.ttstd.dialer.db.contact.ContactRepository;
import java.util.List;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class ContactAddViewModel extends BaseViewModel<ActivityContactAddBinding, ActivityEvent> {
private static final String TAG = "ContactAddViewModel";
@@ -25,9 +33,41 @@ public class ContactAddViewModel extends BaseViewModel<ActivityContactAddBinding
public MutableLiveData<Long> mIntegerMutableLiveData = new MutableLiveData<>();
public void insert(Contact contact) {
Log.e(TAG, "insert: " );
mIntegerMutableLiveData.setValue(mRepository.insert(contact));
public void saveContact(String name, String phone) {
Observable.create(new ObservableOnSubscribe<Long>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Long> emitter) throws Throwable {
int count = mRepository.getTotalCount() + 1;
Contact contact = new Contact(name, phone, count);
Log.e(TAG, "saveContact: " + contact);
emitter.onNext(mRepository.insert(contact));
emitter.onComplete();
}
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.e("saveContact", "onSubscribe: ");
}
@Override
public void onNext(@NonNull Long aLong) {
Log.e("saveContact", "onNext: " + aLong);
mIntegerMutableLiveData.setValue(aLong);
}
@Override
public void onError(@NonNull Throwable e) {
Log.e("saveContact", "onError: " + e.getMessage());
}
@Override
public void onComplete() {
Log.e("saveContact", "onComplete: ");
}
});
}
}

View File

@@ -7,14 +7,13 @@ import android.view.View;
import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.ttstd.dialer.R;
import com.ttstd.dialer.activity.contact.add.ContactAddActivity;
import com.ttstd.dialer.adapter.ContactInfoAdapter;
import com.ttstd.dialer.base.mvvm.BaseMvvmActivity;
import com.ttstd.dialer.contact.Contact;
import com.ttstd.dialer.databinding.ActivityContactListBinding;
import com.ttstd.dialer.db.contact.Contact;
import com.ttstd.dialer.view.ItemTouchHelperCallback;
import java.util.List;
@@ -25,6 +24,8 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
private ContactInfoAdapter mContactInfoAdapter;
private List<Contact> mContacts;
@Override
public boolean setNightMode() {
return true;
@@ -54,12 +55,21 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
mContactInfoAdapter.setItemMoveCallback(new ContactInfoAdapter.ItemMoveCallback() {
@Override
public void onItemMove(int fromPosition, int toPosition) {
Log.e(TAG, "onItemMove: " );
Log.e(TAG, "onItemMove: ");
Contact fromContact = mContacts.get(fromPosition);
int fromContactPosition = fromContact.getPosition();
Contact toContact = mContacts.get(toPosition);
int toContactPosition = toContact.getPosition();
fromContact.setPosition(toContactPosition);
mViewModel.updateItemPosition(fromContact);
toContact.setPosition(fromContactPosition);
mViewModel.updateItemPosition(toContact);
}
@Override
public void onItemRemoved(int position) {
Log.e(TAG, "onItemRemoved: " );
Log.e(TAG, "onItemRemoved: ");
}
});
// 设置ItemTouchHelper实现拖动和滑动删除
@@ -78,8 +88,9 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
mViewModel.mContactListData.observe(this, new Observer<List<Contact>>() {
@Override
public void onChanged(List<Contact> contacts) {
Log.e(TAG, "onChanged: " + contacts);
mContactInfoAdapter.setContacts(contacts);
Log.e(TAG, "mContactListData: " + contacts);
mContacts = contacts;
mContactInfoAdapter.setContacts(mContacts);
}
});
}

View File

@@ -1,18 +1,27 @@
package com.ttstd.dialer.activity.contact.list;
import android.content.Context;
import android.util.Log;
import androidx.lifecycle.MutableLiveData;
import com.trello.rxlifecycle4.RxLifecycle;
import com.trello.rxlifecycle4.android.ActivityEvent;
import com.ttstd.dialer.base.mvvm.BaseViewModel;
import com.ttstd.dialer.contact.Contact;
import com.ttstd.dialer.contact.ContactRepository;
import com.ttstd.dialer.databinding.ActivityContactListBinding;
import com.ttstd.dialer.db.contact.Contact;
import com.ttstd.dialer.db.contact.ContactRepository;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class ContactListViewModel extends BaseViewModel<ActivityContactListBinding, ActivityEvent> {
private static final String TAG = "ContactListViewModel";
@@ -27,19 +36,81 @@ public class ContactListViewModel extends BaseViewModel<ActivityContactListBindi
public MutableLiveData<List<Contact>> mContactListData = new MutableLiveData<>();
public void getAllContacts() {
List<Contact> contacts = mRepository.getAllContacts();
List<Contact> sorted = contacts.stream().sorted(new Comparator<Contact>() {
Observable.create(new ObservableOnSubscribe<List<Contact>>() {
@Override
public int compare(Contact o1, Contact o2) {
return Integer.compare(o1.getSort(), o2.getSort());
public void subscribe(@NonNull ObservableEmitter<List<Contact>> emitter) throws Throwable {
List<Contact> contacts = mRepository.getAllContacts();
emitter.onNext(contacts);
emitter.onComplete();
}
}).collect(Collectors.toList());
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<Contact>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.e("getAllContacts", "onSubscribe: ");
}
mContactListData.setValue(sorted);
@Override
public void onNext(@NonNull List<Contact> contacts) {
Log.e("getAllContacts", "onNext: ");
mContactListData.setValue(contacts);
// List<Contact> sorted = contacts.stream().sorted(new Comparator<Contact>() {
// @Override
// public int compare(Contact o1, Contact o2) {
// return Integer.compare(o1.getSort(), o2.getSort());
// }
// }).collect(Collectors.toList());
// mContactListData.setValue(sorted);
}
@Override
public void onError(@NonNull Throwable e) {
Log.e("getAllContacts", "onError: " + e.getMessage());
}
@Override
public void onComplete() {
Log.e("getAllContacts", "onComplete: ");
}
});
}
public List<Contact> searchContacts(String query) {
return mRepository.searchContacts(query);
public void updateItemPosition(Contact contact) {
Log.e(TAG, "updateItemPosition: " + contact);
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
int id = mRepository.update(contact);
emitter.onNext(id);
emitter.onComplete();
}
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.e("updateItemPosition", "onComplete: ");
}
@Override
public void onNext(@NonNull Integer integer) {
Log.e("updateItemPosition", "onNext: " + integer);
}
@Override
public void onError(@NonNull Throwable e) {
Log.e("updateItemPosition", "onError: " + e.getMessage());
}
@Override
public void onComplete() {
Log.e("updateItemPosition", "onComplete: ");
}
});
}
}

View File

@@ -12,7 +12,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.shehuan.niv.NiceImageView;
import com.ttstd.dialer.R;
import com.ttstd.dialer.contact.Contact;
import com.ttstd.dialer.db.contact.Contact;
import java.util.Collections;
import java.util.List;
@@ -81,6 +81,9 @@ public class ContactInfoAdapter extends RecyclerView.Adapter<ContactInfoAdapter.
}
}
notifyItemMoved(fromPosition, toPosition);
if (mItemMoveCallback != null) {
mItemMoveCallback.onItemMove(fromPosition, toPosition);
}
}
// 处理滑动删除

View File

@@ -1,9 +1,10 @@
package com.ttstd.dialer.contact;
package com.ttstd.dialer.db.contact;
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import android.content.Context;
import java.io.File;
@@ -19,8 +20,8 @@ public abstract class AppDatabase extends RoomDatabase {
synchronized (AppDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
AppDatabase.class, context.getExternalCacheDir() + File.separator +"contact_database")
.allowMainThreadQueries() // 为了简化示例允许主线程查询
AppDatabase.class, context.getExternalFilesDir("db") + File.separator + "contact_database")
// .allowMainThreadQueries() // 为了简化示例允许主线程查询
.build();
}
}

View File

@@ -1,4 +1,4 @@
package com.ttstd.dialer.contact;
package com.ttstd.dialer.db.contact;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -19,12 +19,13 @@ public class Contact implements Serializable {
private String name;
private String phoneNumber;
private String avatar;
private int sort;
private String wxid;
private int position;
public Contact(String name, String phoneNumber) {
public Contact(String name, String phoneNumber, int position) {
this.name = name;
this.phoneNumber = phoneNumber;
this.sort = 0;
this.position = position;
}
public int getId() {
@@ -59,12 +60,20 @@ public class Contact implements Serializable {
this.avatar = avatar;
}
public int getSort() {
return sort;
public String getWxid() {
return wxid;
}
public void setSort(int sort) {
this.sort = sort;
public void setWxid(String wxid) {
this.wxid = wxid;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
@Override

View File

@@ -1,4 +1,4 @@
package com.ttstd.dialer.contact;
package com.ttstd.dialer.db.contact;
import androidx.room.Dao;
import androidx.room.Delete;
@@ -10,6 +10,14 @@ import java.util.List;
@Dao
public interface ContactDao {
// 基本查询获取总行数
@Query("SELECT COUNT(*) FROM contacts")
int getTotalCount();
// 查询根据特定列的非空值计数
@Query("SELECT COUNT(id) FROM contacts")
int getCountById();
@Insert
long insert(Contact contact);
@@ -25,7 +33,7 @@ public interface ContactDao {
@Query("DELETE FROM contacts")
int deleteAll();
@Query("SELECT * FROM contacts ORDER BY name ASC")
@Query("SELECT * FROM contacts ORDER BY position ASC")
List<Contact> getAllContacts();
@Query("SELECT * FROM contacts WHERE id = :id")

View File

@@ -1,17 +1,24 @@
package com.ttstd.dialer.contact;
package com.ttstd.dialer.db.contact;
import android.content.Context;
import java.util.List;
public class ContactRepository {
private ContactDao mContactDao;
private List<Contact> mAllContacts;
// 构造函数获取数据库访问对象
public ContactRepository(Context context) {
AppDatabase db = AppDatabase.getDatabase(context);
mContactDao = db.contactDao();
mAllContacts = mContactDao.getAllContacts();
}
public int getTotalCount() {
return mContactDao.getTotalCount();
}
public int getCountById() {
return mContactDao.getCountById();
}
// 获取所有联系人

View File

@@ -1,7 +1,9 @@
package com.ttstd.dialer.contact;
package com.ttstd.dialer.db.contact;
import android.app.Application;
import androidx.lifecycle.AndroidViewModel;
import java.util.List;
public class ContactViewModel extends AndroidViewModel {

View File

@@ -29,7 +29,7 @@ public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
// 通知适配器项已移动
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
mAdapter.onItemMove(viewHolder.getBindingAdapterPosition(), target.getBindingAdapterPosition());
return true;
}
@@ -37,7 +37,7 @@ public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// 通知适配器项已删除
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
mAdapter.onItemDismiss(viewHolder.getBindingAdapterPosition());
}
// 当长按item时启用拖动
@@ -49,6 +49,6 @@ public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
// 启用滑动删除
@Override
public boolean isItemViewSwipeEnabled() {
return true;
return false;
}
}