refactor(mvvm): 重构闹钟与应用列表ViewModel为AndroidViewModel
将ViewModel改为继承BaseAndroidViewModel,通过构造器注入Application,使用addDisposable管理RxJava订阅,LiveData改为私有并提供getter,移除RxLifecycle依赖。
This commit is contained in:
@@ -45,8 +45,8 @@ public class AlarmAddActivity extends BaseMvvmActivity<AlarmAddViewModel, Activi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.mSaveResult.observe(this, success -> {
|
||||
protected void observeViewModel() {
|
||||
mViewModel.getSaveResult().observe(this, success -> {
|
||||
if (success) {
|
||||
TipDialog.show("添加成功", WaitDialog.TYPE.SUCCESS);
|
||||
finish();
|
||||
|
||||
@@ -1,40 +1,38 @@
|
||||
package com.ttstd.dialer.activity.alarm.add;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.trello.rxlifecycle4.RxLifecycle;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.alarmclock.AlarmManagerHelper;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.ActivityAlarmAddBinding;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.db.alarm.AlarmInfo;
|
||||
import com.ttstd.dialer.db.alarm.AlarmRepository;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Completable;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.core.SingleObserver;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class AlarmAddViewModel extends BaseViewModel<ActivityAlarmAddBinding, ActivityEvent> {
|
||||
public class AlarmAddViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "AlarmAddViewModel";
|
||||
private AlarmRepository mRepository;
|
||||
private final AlarmRepository mRepository;
|
||||
|
||||
private int mVolume = 80;
|
||||
private int mSnoozeInterval = 5;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = new AlarmRepository(context);
|
||||
private final MutableLiveData<Boolean> mSaveResult = new MutableLiveData<>();
|
||||
|
||||
public AlarmAddViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = new AlarmRepository(application);
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> mSaveResult = new MutableLiveData<>();
|
||||
public LiveData<Boolean> getSaveResult() {
|
||||
return mSaveResult;
|
||||
}
|
||||
|
||||
public void saveAlarm(int hour, int minute, String label, boolean vibration, int repeatType) {
|
||||
AlarmInfo alarmInfo = new AlarmInfo();
|
||||
@@ -47,43 +45,31 @@ public class AlarmAddViewModel extends BaseViewModel<ActivityAlarmAddBinding, Ac
|
||||
alarmInfo.setVolume(mVolume);
|
||||
alarmInfo.setSnoozeInterval(mSnoozeInterval);
|
||||
|
||||
Single.fromCallable(() -> mRepository.insertAlarm(alarmInfo))
|
||||
addDisposable(Single.fromCallable(() -> mRepository.insertAlarm(alarmInfo))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new SingleObserver<Long>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.d(TAG, "开始保存闹钟");
|
||||
}
|
||||
.subscribe(aLong -> {
|
||||
Logger.d(TAG, "闹钟保存成功,ID: " + aLong);
|
||||
alarmInfo.setId(aLong.intValue());
|
||||
|
||||
@Override
|
||||
public void onSuccess(Long aLong) {
|
||||
Logger.d(TAG, "闹钟保存成功,ID: " + aLong);
|
||||
alarmInfo.setId(aLong.intValue());
|
||||
// 计算并设置系统闹钟
|
||||
long nextTime = AlarmManagerHelper.calculateNextTime(alarmInfo);
|
||||
alarmInfo.setNextTriggerTime(nextTime);
|
||||
|
||||
// 计算并设置系统闹钟
|
||||
long nextTime = AlarmManagerHelper.calculateNextTime(alarmInfo);
|
||||
alarmInfo.setNextTriggerTime(nextTime);
|
||||
|
||||
// 更新数据库中的下次触发时间
|
||||
Completable.fromAction(() -> mRepository.updateNextTriggerTime(alarmInfo.getId(), nextTime))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(() -> {
|
||||
AlarmManagerHelper.setExactAlarm(getSafeContext(), alarmInfo.getId(), nextTime);
|
||||
mSaveResult.postValue(true);
|
||||
}, throwable -> {
|
||||
Logger.e(TAG, "更新下次触发时间失败: " + throwable.getMessage());
|
||||
mSaveResult.postValue(true); // 依然认为保存成功,只是系统闹钟可能没设好
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e(TAG, "闹钟保存失败: " + e.getMessage());
|
||||
mSaveResult.setValue(false);
|
||||
}
|
||||
|
||||
});
|
||||
// 更新数据库中的下次触发时间
|
||||
addDisposable(Completable.fromAction(() -> mRepository.updateNextTriggerTime(alarmInfo.getId(), nextTime))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(() -> {
|
||||
AlarmManagerHelper.setExactAlarm(getAppContext(), alarmInfo.getId(), nextTime);
|
||||
mSaveResult.postValue(true);
|
||||
}, throwable -> {
|
||||
Logger.e(TAG, "更新下次触发时间失败: " + throwable.getMessage());
|
||||
mSaveResult.postValue(true); // 依然认为保存成功,只是系统闹钟可能没设好
|
||||
}));
|
||||
},
|
||||
throwable -> {
|
||||
Logger.e(TAG, "闹钟保存失败: " + throwable.getMessage());
|
||||
mSaveResult.setValue(false);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ public class AlarmEditActivity extends BaseMvvmActivity<AlarmEditViewModel, Acti
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.mUpdateResult.observe(this, success -> {
|
||||
protected void observeViewModel() {
|
||||
mViewModel.getUpdateResult().observe(this, success -> {
|
||||
if (success) {
|
||||
TipDialog.show("保存成功", WaitDialog.TYPE.SUCCESS);
|
||||
finish();
|
||||
@@ -61,7 +61,7 @@ public class AlarmEditActivity extends BaseMvvmActivity<AlarmEditViewModel, Acti
|
||||
}
|
||||
});
|
||||
|
||||
mViewModel.mDeleteResult.observe(this, success -> {
|
||||
mViewModel.getDeleteResult().observe(this, success -> {
|
||||
if (success) {
|
||||
TipDialog.show("删除成功", WaitDialog.TYPE.SUCCESS);
|
||||
finish();
|
||||
|
||||
@@ -1,40 +1,42 @@
|
||||
package com.ttstd.dialer.activity.alarm.edit;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.trello.rxlifecycle4.RxLifecycle;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.alarmclock.AlarmManagerHelper;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.ActivityAlarmEditBinding;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.db.alarm.AlarmInfo;
|
||||
import com.ttstd.dialer.db.alarm.AlarmRepository;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Completable;
|
||||
import io.reactivex.rxjava3.core.CompletableObserver;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class AlarmEditViewModel extends BaseViewModel<ActivityAlarmEditBinding, ActivityEvent> {
|
||||
public class AlarmEditViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "AlarmEditViewModel";
|
||||
private AlarmRepository mRepository;
|
||||
private final AlarmRepository mRepository;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = new AlarmRepository(context);
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> mUpdateResult = new MutableLiveData<>();
|
||||
public MutableLiveData<Boolean> mDeleteResult = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> mUpdateResult = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> mDeleteResult = new MutableLiveData<>();
|
||||
|
||||
private AlarmInfo mOriginalAlarm;
|
||||
|
||||
public AlarmEditViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = new AlarmRepository(application);
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getUpdateResult() {
|
||||
return mUpdateResult;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getDeleteResult() {
|
||||
return mDeleteResult;
|
||||
}
|
||||
|
||||
public void loadAlarmInfo(AlarmInfo alarmInfo) {
|
||||
this.mOriginalAlarm = alarmInfo;
|
||||
}
|
||||
@@ -57,58 +59,36 @@ public class AlarmEditViewModel extends BaseViewModel<ActivityAlarmEditBinding,
|
||||
alarmInfo.setNextTriggerTime(nextTime);
|
||||
}
|
||||
|
||||
Completable.fromAction(() -> mRepository.updateAlarm(alarmInfo))
|
||||
addDisposable(Completable.fromAction(() -> mRepository.updateAlarm(alarmInfo))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new CompletableObserver() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.d(TAG, "开始更新闹钟");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e(TAG, "闹钟更新失败: " + e.getMessage());
|
||||
mUpdateResult.setValue(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.d(TAG, "更新闹钟完成");
|
||||
if (alarmInfo.isEnabled()) {
|
||||
AlarmManagerHelper.setExactAlarm(getSafeContext(), alarmInfo.getId(), alarmInfo.getNextTriggerTime());
|
||||
} else {
|
||||
AlarmManagerHelper.cancelAlarm(getSafeContext(), alarmInfo.getId());
|
||||
}
|
||||
mUpdateResult.setValue(true);
|
||||
}
|
||||
});
|
||||
.subscribe(() -> {
|
||||
Logger.d(TAG, "更新闹钟完成");
|
||||
if (alarmInfo.isEnabled()) {
|
||||
AlarmManagerHelper.setExactAlarm(getAppContext(), alarmInfo.getId(), alarmInfo.getNextTriggerTime());
|
||||
} else {
|
||||
AlarmManagerHelper.cancelAlarm(getAppContext(), alarmInfo.getId());
|
||||
}
|
||||
mUpdateResult.setValue(true);
|
||||
},
|
||||
throwable -> {
|
||||
Logger.e(TAG, "闹钟更新失败: " + throwable.getMessage());
|
||||
mUpdateResult.setValue(false);
|
||||
}));
|
||||
}
|
||||
|
||||
public void deleteAlarm(AlarmInfo alarmInfo) {
|
||||
Completable.fromAction(() -> mRepository.deleteAlarm(alarmInfo))
|
||||
addDisposable(Completable.fromAction(() -> mRepository.deleteAlarm(alarmInfo))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new CompletableObserver() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.d(TAG, "开始删除闹钟");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e(TAG, "闹钟删除失败: " + e.getMessage());
|
||||
mDeleteResult.setValue(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.d(TAG, "删除闹钟完成");
|
||||
AlarmManagerHelper.cancelAlarm(getSafeContext(), alarmInfo.getId());
|
||||
mDeleteResult.setValue(true);
|
||||
}
|
||||
});
|
||||
.subscribe(() -> {
|
||||
Logger.d(TAG, "删除闹钟完成");
|
||||
AlarmManagerHelper.cancelAlarm(getAppContext(), alarmInfo.getId());
|
||||
mDeleteResult.setValue(true);
|
||||
},
|
||||
throwable -> {
|
||||
Logger.e(TAG, "闹钟删除失败: " + throwable.getMessage());
|
||||
mDeleteResult.setValue(false);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +109,8 @@ public class AlarmListActivity extends BaseMvvmActivity<AlarmListViewModel, Acti
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.mAlarmListData.observe(this, new Observer<List<AlarmInfo>>() {
|
||||
protected void observeViewModel() {
|
||||
mViewModel.getAlarmListData().observe(this, new Observer<List<AlarmInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<AlarmInfo> alarmInfos) {
|
||||
mViewDataBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
@@ -121,7 +121,7 @@ public class AlarmListActivity extends BaseMvvmActivity<AlarmListViewModel, Acti
|
||||
}
|
||||
});
|
||||
|
||||
mViewModel.mDeleteLiveData.observe(this, new Observer<Boolean>() {
|
||||
mViewModel.getDeleteLiveData().observe(this, new Observer<Boolean>() {
|
||||
@Override
|
||||
public void onChanged(Boolean success) {
|
||||
if (success) {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package com.ttstd.dialer.activity.alarm.list;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.trello.rxlifecycle4.RxLifecycle;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.alarmclock.AlarmManagerHelper;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.ActivityAlarmListBinding;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.db.alarm.AlarmInfo;
|
||||
import com.ttstd.dialer.db.alarm.AlarmRepository;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
@@ -16,111 +14,76 @@ import com.ttstd.dialer.utils.Logger;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Completable;
|
||||
import io.reactivex.rxjava3.core.CompletableObserver;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.core.SingleObserver;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class AlarmListViewModel extends BaseViewModel<ActivityAlarmListBinding, ActivityEvent> {
|
||||
public class AlarmListViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "AlarmListViewModel";
|
||||
private AlarmRepository mRepository;
|
||||
private final AlarmRepository mRepository;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = new AlarmRepository(context);
|
||||
private final MutableLiveData<List<AlarmInfo>> mAlarmListData = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> mDeleteLiveData = new MutableLiveData<>();
|
||||
|
||||
public AlarmListViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = new AlarmRepository(application);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<AlarmInfo>> mAlarmListData = new MutableLiveData<>();
|
||||
public LiveData<List<AlarmInfo>> getAlarmListData() {
|
||||
return mAlarmListData;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getDeleteLiveData() {
|
||||
return mDeleteLiveData;
|
||||
}
|
||||
|
||||
public void getAllAlarms() {
|
||||
Single.fromCallable(() -> mRepository.getAllAlarms())
|
||||
addDisposable(Single.fromCallable(() -> mRepository.getAllAlarms())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new SingleObserver<List<AlarmInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.d(TAG, "开始加载闹钟列表");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(List<AlarmInfo> alarmInfos) {
|
||||
Logger.d(TAG, "加载闹钟列表成功,数量: " + alarmInfos.size());
|
||||
mAlarmListData.setValue(alarmInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e(TAG, "加载闹钟列表失败: " + e.getMessage());
|
||||
mAlarmListData.setValue(null);
|
||||
}
|
||||
});
|
||||
.subscribe(alarmInfos -> {
|
||||
Logger.d(TAG, "加载闹钟列表成功,数量: " + alarmInfos.size());
|
||||
mAlarmListData.setValue(alarmInfos);
|
||||
},
|
||||
throwable -> {
|
||||
Logger.e(TAG, "加载闹钟列表失败: " + throwable.getMessage());
|
||||
mAlarmListData.setValue(null);
|
||||
}));
|
||||
}
|
||||
|
||||
public void updateAlarmEnabled(AlarmInfo alarmInfo) {
|
||||
Completable.fromAction(() -> {
|
||||
addDisposable(Completable.fromAction(() -> {
|
||||
mRepository.updateAlarmEnabled(alarmInfo.getId(), alarmInfo.isEnabled());
|
||||
if (alarmInfo.isEnabled()) {
|
||||
long nextTime = AlarmManagerHelper.calculateNextTime(alarmInfo);
|
||||
alarmInfo.setNextTriggerTime(nextTime);
|
||||
mRepository.updateNextTriggerTime(alarmInfo.getId(), nextTime);
|
||||
AlarmManagerHelper.setExactAlarm(getSafeContext(), alarmInfo.getId(), nextTime);
|
||||
AlarmManagerHelper.setExactAlarm(getAppContext(), alarmInfo.getId(), nextTime);
|
||||
Logger.d(TAG, "updateAlarmEnabled: 闹钟状态开启");
|
||||
} else {
|
||||
AlarmManagerHelper.cancelAlarm(getSafeContext(), alarmInfo.getId());
|
||||
AlarmManagerHelper.cancelAlarm(getAppContext(), alarmInfo.getId());
|
||||
Logger.d(TAG, "updateAlarmEnabled: 闹钟状态关闭");
|
||||
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new CompletableObserver() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.d(TAG, "updateAlarmEnabled: 更新闹钟状态成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e(TAG, "updateAlarmEnabled: 更新闹钟状态失败: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
.subscribe(() -> Logger.d(TAG, "updateAlarmEnabled: 更新闹钟状态成功"),
|
||||
throwable -> Logger.e(TAG, "updateAlarmEnabled: 更新闹钟状态失败: " + throwable.getMessage())));
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> mDeleteLiveData = new MutableLiveData<>();
|
||||
|
||||
public void deleteAlarm(AlarmInfo alarmInfo) {
|
||||
Completable.fromAction(() -> mRepository.deleteAlarm(alarmInfo))
|
||||
addDisposable(Completable.fromAction(() -> mRepository.deleteAlarm(alarmInfo))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new CompletableObserver() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.d(TAG, "开始删除闹钟");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e(TAG, "删除闹钟失败: " + e.getMessage());
|
||||
mDeleteLiveData.setValue(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.d(TAG, "删除闹钟完成");
|
||||
AlarmManagerHelper.cancelAlarm(getSafeContext(), alarmInfo.getId());
|
||||
mDeleteLiveData.setValue(true);
|
||||
}
|
||||
});
|
||||
.subscribe(() -> {
|
||||
Logger.d(TAG, "删除闹钟完成");
|
||||
AlarmManagerHelper.cancelAlarm(getAppContext(), alarmInfo.getId());
|
||||
mDeleteLiveData.setValue(true);
|
||||
},
|
||||
throwable -> {
|
||||
Logger.e(TAG, "删除闹钟失败: " + throwable.getMessage());
|
||||
mDeleteLiveData.setValue(false);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,13 +159,13 @@ public class AppListActivity extends BaseMvvmActivity<AppListViewModel, Activity
|
||||
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
protected void observeViewModel() {
|
||||
LiveDataBus.get().<String>on(LiveDataAction.ACTION_UPDATE_APPS)
|
||||
.observe(this, event -> {
|
||||
mViewModel.getDbAppList();
|
||||
mViewModel.getHotseatApp();
|
||||
});
|
||||
mViewModel.mHotseatAppData.observe(this, new Observer<List<AppInfo>>() {
|
||||
mViewModel.getHotseatAppData().observe(this, new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<AppInfo> appInfos) {
|
||||
if (appInfos != null && !appInfos.isEmpty()) {
|
||||
@@ -177,18 +177,15 @@ public class AppListActivity extends BaseMvvmActivity<AppListViewModel, Activity
|
||||
mAppGridAdapter.setAppInfos(appInfos);
|
||||
}
|
||||
});
|
||||
mViewModel.getHotseatApp();
|
||||
|
||||
mViewModel.mDesktopSortAppData.observe(this, new Observer<List<AppInfo>>() {
|
||||
mViewModel.getDesktopSortAppData().observe(this, new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<AppInfo> appInfos) {
|
||||
mMoreAppAdapter.setAppInfos(appInfos);
|
||||
}
|
||||
});
|
||||
|
||||
mViewModel.getDbAppList();
|
||||
|
||||
mViewModel.mAppUpdateData.observe(this, new Observer<Integer>() {
|
||||
mViewModel.getAppUpdateData().observe(this, new Observer<Integer>() {
|
||||
@Override
|
||||
public void onChanged(Integer integer) {
|
||||
if (integer > 0) {
|
||||
@@ -198,7 +195,12 @@ public class AppListActivity extends BaseMvvmActivity<AppListViewModel, Activity
|
||||
mViewModel.getAllApp();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoadData() {
|
||||
mViewModel.getHotseatApp();
|
||||
mViewModel.getDbAppList();
|
||||
mViewModel.getAllApp();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.ttstd.dialer.activity.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
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.databinding.ActivityAppListBinding;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.db.app.AppInfo;
|
||||
import com.ttstd.dialer.db.app.AppRepository;
|
||||
import com.ttstd.dialer.manager.AppManager;
|
||||
@@ -17,132 +15,90 @@ import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class AppListViewModel extends BaseViewModel<ActivityAppListBinding, ActivityEvent> {
|
||||
public class AppListViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "AppListViewModel";
|
||||
|
||||
private AppRepository mAppRepository;
|
||||
private final AppRepository mAppRepository;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mAppRepository = new AppRepository(context);
|
||||
private final MutableLiveData<List<AppInfo>> mAllAppData = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<AppInfo>> mHotseatAppData = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<AppInfo>> mDesktopSortAppData = new MutableLiveData<>();
|
||||
private final MutableLiveData<Integer> mAppUpdateData = new MutableLiveData<>();
|
||||
|
||||
public AppListViewModel(Application application) {
|
||||
super(application);
|
||||
mAppRepository = new AppRepository(application);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<AppInfo>> mAllAppData = new MutableLiveData<>();
|
||||
public LiveData<List<AppInfo>> getAllAppData() {
|
||||
return mAllAppData;
|
||||
}
|
||||
|
||||
public LiveData<List<AppInfo>> getHotseatAppData() {
|
||||
return mHotseatAppData;
|
||||
}
|
||||
|
||||
public LiveData<List<AppInfo>> getDesktopSortAppData() {
|
||||
return mDesktopSortAppData;
|
||||
}
|
||||
|
||||
public LiveData<Integer> getAppUpdateData() {
|
||||
return mAppUpdateData;
|
||||
}
|
||||
|
||||
public void getAllApp() {
|
||||
Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
addDisposable(Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
@Override
|
||||
public List<AppInfo> call() throws Exception {
|
||||
return mAppRepository.getAllApp();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("getAllApp", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<AppInfo> appInfos) {
|
||||
Logger.e("getAllApp", "onNext: " + appInfos);
|
||||
mAllAppData.setValue(appInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("getAllApp", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("getAllApp", "onComplete: ");
|
||||
}
|
||||
});
|
||||
.subscribe(appInfos -> {
|
||||
Logger.e("getAllApp", "onNext: " + appInfos);
|
||||
mAllAppData.setValue(appInfos);
|
||||
},
|
||||
throwable -> Logger.e("getAllApp", "onError: " + throwable.getMessage())));
|
||||
}
|
||||
|
||||
public MutableLiveData<List<AppInfo>> mHotseatAppData = new MutableLiveData<>();
|
||||
|
||||
public void getHotseatApp() {
|
||||
Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
addDisposable(Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
@Override
|
||||
public List<AppInfo> call() throws Exception {
|
||||
return mAppRepository.getHotseatApp();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("getHotseatApp", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<AppInfo> appInfos) {
|
||||
Logger.e("getHotseatApp", "onNext: " + appInfos);
|
||||
mHotseatAppData.setValue(appInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("getHotseatApp", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("getHotseatApp", "onComplete: ");
|
||||
}
|
||||
});
|
||||
.subscribe(appInfos -> {
|
||||
Logger.e("getHotseatApp", "onNext: " + appInfos);
|
||||
mHotseatAppData.setValue(appInfos);
|
||||
},
|
||||
throwable -> Logger.e("getHotseatApp", "onError: " + throwable.getMessage())));
|
||||
}
|
||||
|
||||
public MutableLiveData<List<AppInfo>> mDesktopSortAppData = new MutableLiveData<>();
|
||||
|
||||
public void getDbAppList() {
|
||||
Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
addDisposable(Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
@Override
|
||||
public List<AppInfo> call() throws Exception {
|
||||
return mAppRepository.getInsideApp();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("getDbAppList", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<AppInfo> appInfos) {
|
||||
Logger.e("getDbAppList", "onNext: " + appInfos);
|
||||
mDesktopSortAppData.setValue(appInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("getDbAppList", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("getDbAppList", "onComplete: ");
|
||||
}
|
||||
});
|
||||
.subscribe(appInfos -> {
|
||||
Logger.e("getDbAppList", "onNext: " + appInfos);
|
||||
mDesktopSortAppData.setValue(appInfos);
|
||||
},
|
||||
throwable -> Logger.e("getDbAppList", "onError: " + throwable.getMessage())));
|
||||
}
|
||||
|
||||
public MutableLiveData<Integer> mAppUpdateData = new MutableLiveData<>();
|
||||
|
||||
public void updateAppInfo(AppInfo appInfo) {
|
||||
Observable.fromCallable(new Callable<Integer>() {
|
||||
addDisposable(Observable.fromCallable(new Callable<Integer>() {
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
if (appInfo.getOutside() == 0) {
|
||||
@@ -166,32 +122,15 @@ public class AppListViewModel extends BaseViewModel<ActivityAppListBinding, Acti
|
||||
|
||||
return mAppRepository.update(appInfo);
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<Integer>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("updateAppInfo", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull Integer row) {
|
||||
Logger.e("updateAppInfo", "onNext: " + row);
|
||||
mAppUpdateData.setValue(row);
|
||||
AppManager.getInstance().reorderAppPositions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("updateAppInfo", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("updateAppInfo", "onComplete: ");
|
||||
}
|
||||
});
|
||||
.subscribe(row -> {
|
||||
Logger.e("updateAppInfo", "onNext: " + row);
|
||||
mAppUpdateData.setValue(row);
|
||||
AppManager.getInstance().reorderAppPositions();
|
||||
},
|
||||
throwable -> Logger.e("updateAppInfo", "onError: " + throwable.getMessage())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,8 +80,8 @@ public class ContactAddActivity extends BaseMvvmActivity<ContactAddViewModel, Ac
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.mOnlineIdData.observe(this, new Observer<Long>() {
|
||||
protected void observeViewModel() {
|
||||
mViewModel.getOnlineIdData().observe(this, new Observer<Long>() {
|
||||
@Override
|
||||
public void onChanged(Long aLong) {
|
||||
if (aLong > 0) {
|
||||
@@ -92,7 +92,7 @@ public class ContactAddActivity extends BaseMvvmActivity<ContactAddViewModel, Ac
|
||||
}
|
||||
}
|
||||
});
|
||||
mViewModel.mDbIdData.observe(this, new Observer<Long>() {
|
||||
mViewModel.getDbIdData().observe(this, new Observer<Long>() {
|
||||
@Override
|
||||
public void onChanged(Long aLong) {
|
||||
PopTip.show("添加成功").iconSuccess();
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.ttstd.dialer.activity.contact.add;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.data.repository.ContactDataRepository;
|
||||
import com.ttstd.dialer.databinding.ActivityContactAddBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
@@ -17,22 +16,27 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
* 新增联系人 ViewModel(Google 标准 MVVM):
|
||||
* 网络优先 / 本地降级的策略已下沉到 Repository,ViewModel 只负责状态分发。
|
||||
*/
|
||||
public class ContactAddViewModel extends BaseViewModel<ActivityContactAddBinding, ActivityEvent> {
|
||||
public class ContactAddViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "ContactAddViewModel";
|
||||
|
||||
private ContactDataRepository mRepository;
|
||||
private final ContactDataRepository mRepository;
|
||||
|
||||
/**
|
||||
* 服务端保存成功返回的 id
|
||||
*/
|
||||
public MutableLiveData<Long> mOnlineIdData = new MutableLiveData<>();
|
||||
/** 服务端保存成功返回的 id */
|
||||
private final MutableLiveData<Long> mOnlineIdData = new MutableLiveData<>();
|
||||
/** 网络失败降级到本地 Room 保存返回的 id */
|
||||
public MutableLiveData<Long> mDbIdData = new MutableLiveData<>();
|
||||
private final MutableLiveData<Long> mDbIdData = new MutableLiveData<>();
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = ContactDataRepository.getInstance(context);
|
||||
public ContactAddViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = ContactDataRepository.getInstance(application);
|
||||
}
|
||||
|
||||
public LiveData<Long> getOnlineIdData() {
|
||||
return mOnlineIdData;
|
||||
}
|
||||
|
||||
public LiveData<Long> getDbIdData() {
|
||||
return mDbIdData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,15 +35,7 @@ public class ContactEditActivity extends BaseMvvmActivity<ContactEditViewModel,
|
||||
@Override
|
||||
protected void initDataBinding() {
|
||||
mViewDataBinding.setClick(new BtnClick());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initView() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
Intent intent = getIntent();
|
||||
mContactInfo = (ContactInfo) intent.getSerializableExtra("ContactInfo");
|
||||
if (mContactInfo == null) {
|
||||
@@ -52,7 +44,16 @@ public class ContactEditActivity extends BaseMvvmActivity<ContactEditViewModel,
|
||||
}
|
||||
mViewDataBinding.setContactInfo(mContactInfo);
|
||||
GlideUtils.loadImageSafe(ContactEditActivity.this, mContactInfo.getAvatar(), mViewDataBinding.nvAvatar, AvatarCacheUtil.getAvatar(ContactEditActivity.this, mContactInfo.getName()));
|
||||
mViewModel.mBooleanMutableLiveData.observe(this, new Observer<Boolean>() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initView() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void observeViewModel() {
|
||||
mViewModel.getBooleanMutableLiveData().observe(this, new Observer<Boolean>() {
|
||||
@Override
|
||||
public void onChanged(Boolean aBoolean) {
|
||||
if (aBoolean) {
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.ttstd.dialer.activity.contact.edit;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.kongzue.dialogx.dialogs.PopTip;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.data.ApiException;
|
||||
import com.ttstd.dialer.data.repository.ContactDataRepository;
|
||||
import com.ttstd.dialer.databinding.ActivityContactEditBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
@@ -18,17 +17,20 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
/**
|
||||
* 编辑联系人 ViewModel(Google 标准 MVVM):只依赖 Repository。
|
||||
*/
|
||||
public class ContactEditViewModel extends BaseViewModel<ActivityContactEditBinding, ActivityEvent> {
|
||||
public class ContactEditViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "ContactEditViewModel";
|
||||
|
||||
private ContactDataRepository mRepository;
|
||||
private final ContactDataRepository mRepository;
|
||||
|
||||
public MutableLiveData<Boolean> mBooleanMutableLiveData = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> mBooleanMutableLiveData = new MutableLiveData<>();
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = ContactDataRepository.getInstance(context);
|
||||
public ContactEditViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = ContactDataRepository.getInstance(application);
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getBooleanMutableLiveData() {
|
||||
return mBooleanMutableLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -159,7 +159,7 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
protected void observeViewModel() {
|
||||
// 观察 Resource 状态:LOADING / SUCCESS(含缓存 stale 数据) / ERROR(含兜底数据)
|
||||
mViewModel.getContactListData().observe(this, new Observer<Resource<List<ContactInfo>>>() {
|
||||
@Override
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package com.ttstd.dialer.activity.contact.list;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.data.Resource;
|
||||
import com.ttstd.dialer.data.repository.ContactDataRepository;
|
||||
import com.ttstd.dialer.databinding.ActivityContactListBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
@@ -21,18 +19,17 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
* 联系人列表 ViewModel(Google 标准 MVVM):
|
||||
* 只依赖 Repository,向 UI 暴露 LiveData<Resource<T>>,不感知网络/缓存/数据库细节。
|
||||
*/
|
||||
public class ContactListViewModel extends BaseViewModel<ActivityContactListBinding, ActivityEvent> {
|
||||
public class ContactListViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "ContactListViewModel";
|
||||
|
||||
private ContactDataRepository mRepository;
|
||||
private final ContactDataRepository mRepository;
|
||||
|
||||
private final MutableLiveData<Resource<List<ContactInfo>>> mContactList = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> mDeleteResult = new MutableLiveData<>();
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = ContactDataRepository.getInstance(context);
|
||||
public ContactListViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = ContactDataRepository.getInstance(application);
|
||||
}
|
||||
|
||||
public LiveData<Resource<List<ContactInfo>>> getContactListData() {
|
||||
|
||||
@@ -162,8 +162,8 @@ public class ContactTestActivity extends BaseMvvmActivity<ContactTestViewModel,
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.mOnlineContactListData.observe(this, new Observer<List<ContactInfo>>() {
|
||||
protected void observeViewModel() {
|
||||
mViewModel.getOnlineContactListData().observe(this, new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<ContactInfo> contactInfos) {
|
||||
if (contactInfos == null) {
|
||||
@@ -177,7 +177,7 @@ public class ContactTestActivity extends BaseMvvmActivity<ContactTestViewModel,
|
||||
}
|
||||
});
|
||||
|
||||
mViewModel.mLocalContactListData.observe(this, new Observer<List<ContactInfo>>() {
|
||||
mViewModel.getLocalContactListData().observe(this, new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<ContactInfo> contactInfos) {
|
||||
if (contactInfos == null) {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.ttstd.dialer.activity.contact.test;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.data.repository.ContactDataRepository;
|
||||
import com.ttstd.dialer.databinding.ActivityContactTestBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
@@ -18,19 +17,26 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
/**
|
||||
* 联系人测试页 ViewModel(Google 标准 MVVM):只依赖 Repository。
|
||||
*/
|
||||
public class ContactTestViewModel extends BaseViewModel<ActivityContactTestBinding, ActivityEvent> {
|
||||
public class ContactTestViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "ContactTestViewModel";
|
||||
|
||||
private ContactDataRepository mRepository;
|
||||
private final ContactDataRepository mRepository;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = ContactDataRepository.getInstance(context);
|
||||
private final MutableLiveData<List<ContactInfo>> mOnlineContactListData = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<ContactInfo>> mLocalContactListData = new MutableLiveData<>();
|
||||
|
||||
public ContactTestViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = ContactDataRepository.getInstance(application);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<ContactInfo>> mOnlineContactListData = new MutableLiveData<>();
|
||||
public MutableLiveData<List<ContactInfo>> mLocalContactListData = new MutableLiveData<>();
|
||||
public LiveData<List<ContactInfo>> getOnlineContactListData() {
|
||||
return mOnlineContactListData;
|
||||
}
|
||||
|
||||
public LiveData<List<ContactInfo>> getLocalContactListData() {
|
||||
return mLocalContactListData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 网络联系人(走多级缓存 + SWR,数据已按 position 排序)
|
||||
|
||||
@@ -205,8 +205,39 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
Log.e(TAG, "initData: ");
|
||||
protected void observeViewModel() {
|
||||
LiveDataBus.get().<String>on(LiveDataAction.ACTION_UPDATE_APPS)
|
||||
.observe(this, event -> {
|
||||
mViewModel.getOutsideApp();
|
||||
mViewModel.getHotseatApp();
|
||||
});
|
||||
|
||||
mViewModel.getDesktopSortAppData().observe(this, new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<AppInfo> appInfos) {
|
||||
mAppInfos = appInfos;
|
||||
Logger.e(TAG, "onChanged: mAppInfos size = " + mAppInfos.size());
|
||||
setAppList();
|
||||
}
|
||||
});
|
||||
|
||||
mViewModel.getHotseatAppData().observe(this, new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<AppInfo> appInfos) {
|
||||
if (appInfos != null && !appInfos.isEmpty()) {
|
||||
GridLayoutManager layoutManager = (GridLayoutManager) mViewDataBinding.gvApp.getLayoutManager();
|
||||
if (layoutManager != null) {
|
||||
layoutManager.setSpanCount(Math.max(1, appInfos.size()));
|
||||
}
|
||||
}
|
||||
mAppGridAdapter.setAppInfos(appInfos);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoadData() {
|
||||
Log.e(TAG, "onLoadData: ");
|
||||
registerReceivers();
|
||||
AppManager.getInstance().addProgressCallback(new AppManager.ProgressCallback() {
|
||||
@Override
|
||||
@@ -219,37 +250,8 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
mViewModel.getOutsideApp();
|
||||
}
|
||||
});
|
||||
|
||||
LiveDataBus.get().<String>on(LiveDataAction.ACTION_UPDATE_APPS)
|
||||
.observe(this, event -> {
|
||||
mViewModel.getOutsideApp();
|
||||
mViewModel.getHotseatApp();
|
||||
});
|
||||
|
||||
mViewModel.mDesktopSortAppData.observe(this, new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<AppInfo> appInfos) {
|
||||
mAppInfos = appInfos;
|
||||
Logger.e(TAG, "onChanged: mAppInfos size = " + mAppInfos.size());
|
||||
setAppList();
|
||||
}
|
||||
});
|
||||
mViewModel.getOutsideApp();
|
||||
|
||||
mViewModel.mHotseatAppData.observe(this, new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<AppInfo> appInfos) {
|
||||
if (appInfos != null && !appInfos.isEmpty()) {
|
||||
GridLayoutManager layoutManager = (GridLayoutManager) mViewDataBinding.gvApp.getLayoutManager();
|
||||
if (layoutManager != null) {
|
||||
layoutManager.setSpanCount(Math.max(1, appInfos.size()));
|
||||
}
|
||||
}
|
||||
mAppGridAdapter.setAppInfos(appInfos);
|
||||
}
|
||||
});
|
||||
mViewModel.getHotseatApp();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.ttstd.dialer.activity.main;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
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.databinding.ActivityMainBinding;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.db.app.AppInfo;
|
||||
import com.ttstd.dialer.db.app.AppRepository;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
@@ -16,91 +14,60 @@ import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class MainViewModel extends BaseViewModel<ActivityMainBinding, ActivityEvent> {
|
||||
public class MainViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "MainViewModel";
|
||||
|
||||
private AppRepository mAppRepository;
|
||||
private final AppRepository mAppRepository;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mAppRepository = new AppRepository(context);
|
||||
private final MutableLiveData<List<AppInfo>> mDesktopSortAppData = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<AppInfo>> mHotseatAppData = new MutableLiveData<>();
|
||||
|
||||
public MainViewModel(Application application) {
|
||||
super(application);
|
||||
mAppRepository = new AppRepository(application);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<AppInfo>> mDesktopSortAppData = new MutableLiveData<>();
|
||||
public LiveData<List<AppInfo>> getDesktopSortAppData() {
|
||||
return mDesktopSortAppData;
|
||||
}
|
||||
|
||||
public LiveData<List<AppInfo>> getHotseatAppData() {
|
||||
return mHotseatAppData;
|
||||
}
|
||||
|
||||
public void getOutsideApp() {
|
||||
Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
addDisposable(Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
@Override
|
||||
public List<AppInfo> call() throws Exception {
|
||||
return mAppRepository.getOutsideAppWithoutHotseat();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("getOutsideApp", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<AppInfo> appInfos) {
|
||||
Logger.e("getOutsideApp", "onNext: " + appInfos);
|
||||
mDesktopSortAppData.setValue(appInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("getOutsideApp", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("getOutsideApp", "onComplete: ");
|
||||
}
|
||||
});
|
||||
.subscribe(appInfos -> {
|
||||
Logger.e("getOutsideApp", "onNext: " + appInfos);
|
||||
mDesktopSortAppData.setValue(appInfos);
|
||||
},
|
||||
throwable -> Logger.e("getOutsideApp", "onError: " + throwable.getMessage())));
|
||||
}
|
||||
|
||||
public MutableLiveData<List<AppInfo>> mHotseatAppData = new MutableLiveData<>();
|
||||
|
||||
public void getHotseatApp() {
|
||||
Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
addDisposable(Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
@Override
|
||||
public List<AppInfo> call() throws Exception {
|
||||
return mAppRepository.getHotseatApp();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("getHotseatApp", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<AppInfo> appInfos) {
|
||||
Logger.e("getHotseatApp", "onNext: " + appInfos);
|
||||
mHotseatAppData.setValue(appInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("getHotseatApp", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("getHotseatApp", "onComplete: ");
|
||||
}
|
||||
});
|
||||
.subscribe(appInfos -> {
|
||||
Logger.e("getHotseatApp", "onNext: " + appInfos);
|
||||
mHotseatAppData.setValue(appInfos);
|
||||
},
|
||||
throwable -> Logger.e("getHotseatApp", "onError: " + throwable.getMessage())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class SettingsCallActivity extends BaseMvvmActivity<SettingsCallViewModel
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.ttstd.dialer.activity.settings.call;
|
||||
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.ActivitySettingsCallBinding;
|
||||
|
||||
public class SettingsCallViewModel extends BaseViewModel<ActivitySettingsCallBinding, ActivityEvent> {
|
||||
public class SettingsCallViewModel extends BaseViewModel {
|
||||
|
||||
}
|
||||
|
||||
@@ -44,11 +44,15 @@ public class SettingsActivity extends BaseMvvmActivity<SettingsViewModel, Activi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.snRegister();
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoadData() {
|
||||
mViewModel.snRegister();
|
||||
}
|
||||
|
||||
public class BtnClick {
|
||||
public void exit(View view) {
|
||||
finish();
|
||||
|
||||
@@ -1,42 +1,15 @@
|
||||
package com.ttstd.dialer.activity.settings.home;
|
||||
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.bean.BaseResponse;
|
||||
import com.ttstd.dialer.databinding.ActivitySettingsBinding;
|
||||
import com.ttstd.dialer.network.OkHttpManager;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
public class SettingsViewModel extends BaseViewModel<ActivitySettingsBinding, ActivityEvent> {
|
||||
public class SettingsViewModel extends BaseViewModel {
|
||||
|
||||
public void snRegister() {
|
||||
OkHttpManager.getInstance().getSnRegisterObservable(getLifecycle())
|
||||
.subscribe(new Observer<BaseResponse>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("snRegister", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull BaseResponse baseResponse) {
|
||||
Logger.e("snRegister", "onNext: " + baseResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("snRegister", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("snRegister", "onComplete: ");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
addDisposable(OkHttpManager.getInstance().getSnRegisterObservable()
|
||||
.subscribe(baseResponse -> Logger.e("snRegister", "onNext: " + baseResponse),
|
||||
throwable -> Logger.e("snRegister", "onError: " + throwable.getMessage())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ public class SettingsUtilsActivity extends BaseMvvmActivity<SettingsUtilsViewMod
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package com.ttstd.dialer.activity.settings.utils;
|
||||
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.ActivitySettingsCallBinding;
|
||||
import com.ttstd.dialer.databinding.ActivitySettingsUtilsBinding;
|
||||
|
||||
public class SettingsUtilsViewModel extends BaseViewModel<ActivitySettingsUtilsBinding, ActivityEvent> {
|
||||
public class SettingsUtilsViewModel extends BaseViewModel {
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class TemplateActivity extends BaseMvvmActivity<TemplateViewModel, Activi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.ttstd.dialer.activity.template;
|
||||
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.ActivityTemplateBinding;
|
||||
|
||||
public class TemplateViewModel extends BaseViewModel<ActivityTemplateBinding, ActivityEvent> {
|
||||
public class TemplateViewModel extends BaseViewModel {
|
||||
|
||||
}
|
||||
|
||||
@@ -67,23 +67,23 @@ public class WeatherMainActivity extends BaseMvvmActivity<WeatherMainViewModel,
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
Logger.e(TAG, "initData: ");
|
||||
protected void observeViewModel() {
|
||||
Logger.e(TAG, "observeViewModel: ");
|
||||
|
||||
mViewModel.mWeatherNowData.observe(this, new Observer<WeatherNow>() {
|
||||
mViewModel.getWeatherNowData().observe(this, new Observer<WeatherNow>() {
|
||||
@Override
|
||||
public void onChanged(WeatherNow weatherNow) {
|
||||
mViewDataBinding.setWeatherNow(weatherNow);
|
||||
}
|
||||
});
|
||||
mViewModel.mWeather24hData.observe(this, new Observer<List<WeatherHourly>>() {
|
||||
mViewModel.getWeather24hData().observe(this, new Observer<List<WeatherHourly>>() {
|
||||
@Override
|
||||
public void onChanged(List<WeatherHourly> weatherHourlies) {
|
||||
mHourlyWeatherAdapter.setWeatherHourlyList(weatherHourlies);
|
||||
}
|
||||
});
|
||||
|
||||
mViewModel.mWeatherDailyListData.observe(this, new Observer<List<WeatherDaily>>() {
|
||||
mViewModel.getWeatherDailyListData().observe(this, new Observer<List<WeatherDaily>>() {
|
||||
@Override
|
||||
public void onChanged(List<WeatherDaily> weatherDailies) {
|
||||
Optional<WeatherDaily> dailyOptional = weatherDailies.stream().filter(new Predicate<WeatherDaily>() {
|
||||
@@ -101,7 +101,10 @@ public class WeatherMainActivity extends BaseMvvmActivity<WeatherMainViewModel,
|
||||
mWeatherAdapter.setWeatherDailyList(weatherDailies);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoadData() {
|
||||
boolean manually = mMMKV.decodeBool(CommonConfig.MANUALLY_SELECT_LOCATION, CommonConfig.MANUALLY_SELECT_LOCATION_DEFAULT_VALUE);
|
||||
if (manually) {
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ttstd.dialer.activity.weather.main;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.qweather.sdk.Callback;
|
||||
@@ -10,19 +11,31 @@ import com.qweather.sdk.response.weather.WeatherHourly;
|
||||
import com.qweather.sdk.response.weather.WeatherHourlyResponse;
|
||||
import com.qweather.sdk.response.weather.WeatherNow;
|
||||
import com.qweather.sdk.response.weather.WeatherNowResponse;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.ActivityWeatherMainBinding;
|
||||
import com.ttstd.dialer.gson.GsonUtils;
|
||||
import com.ttstd.dialer.manager.WeatherManager;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WeatherMainViewModel extends BaseViewModel<ActivityWeatherMainBinding, ActivityEvent> {
|
||||
public class WeatherMainViewModel extends BaseViewModel {
|
||||
private static final String TAG = "WeatherMainViewModel";
|
||||
|
||||
public MutableLiveData<WeatherNow> mWeatherNowData = new MutableLiveData<>();
|
||||
private final MutableLiveData<WeatherNow> mWeatherNowData = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<WeatherHourly>> mWeather24hData = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<WeatherDaily>> mWeatherDailyListData = new MutableLiveData<>();
|
||||
|
||||
public LiveData<WeatherNow> getWeatherNowData() {
|
||||
return mWeatherNowData;
|
||||
}
|
||||
|
||||
public LiveData<List<WeatherHourly>> getWeather24hData() {
|
||||
return mWeather24hData;
|
||||
}
|
||||
|
||||
public LiveData<List<WeatherDaily>> getWeatherDailyListData() {
|
||||
return mWeatherDailyListData;
|
||||
}
|
||||
|
||||
public void getWeatherNow(String adCode) {
|
||||
Logger.e(TAG, "getWeatherNow: " + adCode);
|
||||
@@ -48,8 +61,6 @@ public class WeatherMainViewModel extends BaseViewModel<ActivityWeatherMainBindi
|
||||
});
|
||||
}
|
||||
|
||||
public MutableLiveData<List<WeatherHourly>> mWeather24hData = new MutableLiveData<>();
|
||||
|
||||
public void getWeather24h(String adCode) {
|
||||
Logger.e(TAG, "getWeather24h: " + adCode);
|
||||
WeatherManager.getInstance().getWeather24HourAdCode(adCode, new Callback<WeatherHourlyResponse>() {
|
||||
@@ -74,9 +85,6 @@ public class WeatherMainViewModel extends BaseViewModel<ActivityWeatherMainBindi
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public MutableLiveData<List<WeatherDaily>> mWeatherDailyListData = new MutableLiveData<>();
|
||||
|
||||
public void getWeather10D(String adCode) {
|
||||
Logger.e(TAG, "getWeather10D: " + adCode);
|
||||
WeatherManager.getInstance().getWeather10DayAdCode(adCode, new Callback<WeatherDailyResponse>() {
|
||||
|
||||
@@ -1,44 +1,135 @@
|
||||
package com.ttstd.dialer.base;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.ttstd.dialer.base.rx.BaseRxFragment;
|
||||
|
||||
/**
|
||||
* Fragment 基类,提供标准的懒加载框架
|
||||
* <p>
|
||||
* 兼容两种宿主场景:
|
||||
* 1. ViewPager(v1) + FragmentPagerAdapter:通过 {@link #setUserVisibleHint} 判断可见性(老接口,deprecated)
|
||||
* 2. ViewPager2 / FragmentTransaction.setMaxLifecycle:通过 onResume/onPause 判断可见性
|
||||
* <p>
|
||||
* 懒加载核心思路:
|
||||
* 1. 视图创建完成({@code isViewInitiated}) + 当前页可见({@code isVisibleToUser}) 两个条件同时满足时,
|
||||
* 才触发首次加载({@link #onLazyLoad()}),之后切回该页不再重复触发。
|
||||
* 2. {@link #fetchData()} 每次可见都会回调,用于需要刷新的场景。
|
||||
* 3. View 销毁重建后自动重置懒加载状态,保证重建后的页面能重新渲染。
|
||||
*/
|
||||
public abstract class BaseFragment extends BaseRxFragment {
|
||||
|
||||
private static final String TAG = "BaseFragment";
|
||||
|
||||
/** 视图是否已创建(onViewCreated 之后为 true) */
|
||||
protected boolean isViewInitiated;
|
||||
/** 当前 Fragment 是否对用户可见 */
|
||||
protected boolean isVisibleToUser;
|
||||
/** 首次数据是否已初始化 */
|
||||
protected boolean isDataInitiated;
|
||||
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
public void onViewCreated(@androidx.annotation.NonNull android.view.View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
isViewInitiated = true;
|
||||
// 视图已创建,检查是否满足懒加载条件
|
||||
prepareFetchData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// ViewPager2 / setMaxLifecycle 场景下没有 setUserVisibleHint 回调,用 onResume 判断可见性;
|
||||
// 兼容 ViewPager(v1):off-screen 页 getUserVisibleHint()==false,不会被误判为可见
|
||||
if (!isViewInitiated || isHidden() || !getUserVisibleHint()) {
|
||||
return;
|
||||
}
|
||||
setVisibleToUser(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
// ViewPager2 / setMaxLifecycle 场景下用 onPause 判断不可见
|
||||
if (isViewInitiated && !isHidden() && getUserVisibleHint()) {
|
||||
setVisibleToUser(false);
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
// View 销毁重建后,重置懒加载状态,保证重建后的页面能重新渲染控件
|
||||
// 否则 Fragment 实例保留的 isDataInitiated=true 会导致重建后不再触发 onLazyLoad,控件消失
|
||||
isDataInitiated = false;
|
||||
isViewInitiated = false;
|
||||
isVisibleToUser = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewPager(v1) + FragmentPagerAdapter 场景下,通过此回调精确判断当前页是否可见
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
this.isVisibleToUser = isVisibleToUser;
|
||||
if (!isViewInitiated) {
|
||||
return;
|
||||
}
|
||||
setVisibleToUser(isVisibleToUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一更新可见性并触发懒加载判断
|
||||
*/
|
||||
private void setVisibleToUser(boolean visible) {
|
||||
if (this.isVisibleToUser == visible) {
|
||||
return;
|
||||
}
|
||||
this.isVisibleToUser = visible;
|
||||
prepareFetchData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发真实数据加载,子类重写实现具体加载逻辑
|
||||
*/
|
||||
public abstract void fetchData();
|
||||
|
||||
/**
|
||||
* 懒加载入口:视图已创建 且 当前页可见 时触发一次
|
||||
*/
|
||||
public boolean prepareFetchData() {
|
||||
return prepareFetchData(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 懒加载入口
|
||||
*
|
||||
* @param forceUpdate 为 true 时,即使已加载过也强制重新加载
|
||||
*/
|
||||
public boolean prepareFetchData(boolean forceUpdate) {
|
||||
if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
|
||||
if (!isDataInitiated) {
|
||||
Log.d(TAG, "lazyLoad trigger: " + getClass().getSimpleName());
|
||||
onLazyLoad();
|
||||
}
|
||||
// 只在非强制刷新时标记为已初始化,保证首屏只渲染一次
|
||||
if (!forceUpdate) {
|
||||
isDataInitiated = true;
|
||||
}
|
||||
fetchData();
|
||||
//注释掉保证每次都更新数据
|
||||
// isDataInitiated = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 首次可见时回调,用于做一次性的重操作(如创建控件、加载图片等)
|
||||
* 默认空实现,子类按需重写
|
||||
*/
|
||||
protected void onLazyLoad() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.ttstd.dialer.base.mvvm;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* MVVM ViewModel 基类(带 Context 版本)
|
||||
*
|
||||
* 继承 {@link AndroidViewModel},可通过 {@link #getAppContext()} 获取 Application 级别的 Context。
|
||||
* Application Context 生命周期与进程一致,不会造成内存泄漏。
|
||||
*
|
||||
* 职责:
|
||||
* - 持有 UI 状态(LiveData)
|
||||
* - 处理业务逻辑
|
||||
* - 暴露数据给 View 层
|
||||
* - 通过 {@link #addDisposable(Disposable)} 统一管理 RxJava 异步任务
|
||||
* - 可通过 {@link #getAppContext()} 获取 Application Context(安全)
|
||||
*
|
||||
* 禁止:
|
||||
* - 持有任何 View 引用(Activity / Fragment / View)
|
||||
* - 使用 Activity Context 或持有 View 的 Context(只能使用 Application)
|
||||
* - 直接进行网络请求或数据库操作(必须通过 Repository)
|
||||
* - 在 ViewModel 中弹 Toast / Dialog / Snackbar
|
||||
* - 手动创建 Thread / Executor / AsyncTask 执行异步任务(必须使用 RxJava + {@link #addDisposable(Disposable)})
|
||||
* - 忘记将 Disposable add 到 {@link #mDisposables} 中
|
||||
*/
|
||||
public abstract class BaseAndroidViewModel extends AndroidViewModel implements IMvvmUiState {
|
||||
|
||||
// ============================================================
|
||||
// 通用 UI 状态
|
||||
// ============================================================
|
||||
|
||||
/** 全局加载状态 */
|
||||
private final MutableLiveData<Boolean> mLoadingLiveData = new MutableLiveData<>(false);
|
||||
|
||||
/** 全局错误提示 */
|
||||
private final MutableLiveData<String> mErrorLiveData = new MutableLiveData<>();
|
||||
|
||||
/** 全局成功提示 */
|
||||
private final MutableLiveData<String> mSuccessLiveData = new MutableLiveData<>();
|
||||
|
||||
// ============================================================
|
||||
// RxJava 异步管理(核心)
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* CompositeDisposable 用于统一管理所有 RxJava 订阅。
|
||||
* 在 onCleared() 中自动 dispose,防止内存泄漏。
|
||||
*/
|
||||
protected final CompositeDisposable mDisposables = new CompositeDisposable();
|
||||
|
||||
// ============================================================
|
||||
// 构造方法
|
||||
// ============================================================
|
||||
|
||||
public BaseAndroidViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 对外暴露(只读)
|
||||
// ============================================================
|
||||
|
||||
public LiveData<Boolean> getLoadingLiveData() {
|
||||
return mLoadingLiveData;
|
||||
}
|
||||
|
||||
public LiveData<String> getErrorLiveData() {
|
||||
return mErrorLiveData;
|
||||
}
|
||||
|
||||
public LiveData<String> getSuccessLiveData() {
|
||||
return mSuccessLiveData;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 受保护的方法(子类调用)
|
||||
// ============================================================
|
||||
|
||||
protected void setLoading(boolean loading) {
|
||||
mLoadingLiveData.postValue(loading);
|
||||
}
|
||||
|
||||
protected void setError(String message) {
|
||||
mErrorLiveData.postValue(message);
|
||||
}
|
||||
|
||||
protected void setSuccess(String message) {
|
||||
mSuccessLiveData.postValue(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 便捷方法:将 Disposable 添加到 {@link #mDisposables} 中管理。
|
||||
* 子类在发起 RxJava 请求时调用此方法。
|
||||
*/
|
||||
protected void addDisposable(Disposable disposable) {
|
||||
mDisposables.add(disposable);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Context 安全访问
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* 获取 Application Context(安全,不会泄漏)。
|
||||
* 子类可通过此方法访问:
|
||||
* - getApplication().getSharedPreferences(...)
|
||||
* - getApplication().getResources().getString(...)
|
||||
* - getApplication().getSystemService(...)
|
||||
*/
|
||||
@NonNull
|
||||
protected Application getAppContext() {
|
||||
return getApplication();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 生命周期
|
||||
// ============================================================
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
super.onCleared();
|
||||
// ViewModel 销毁时,自动取消所有正在执行的 RxJava 任务
|
||||
if (!mDisposables.isDisposed()) {
|
||||
mDisposables.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.ttstd.dialer.base.mvvm;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
@@ -14,6 +16,33 @@ import com.ttstd.dialer.utils.Logger;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
||||
/**
|
||||
* MVVM Activity 基类
|
||||
*
|
||||
* 职责:
|
||||
* - 绑定 DataBinding
|
||||
* - 初始化 ViewModel(默认通过反射自动创建)
|
||||
* - 订阅 ViewModel 中的 LiveData({@link #observeViewModel()})
|
||||
* - 订阅全局通用状态({@link #observeCommonState()})
|
||||
* - 页面创建完成后加载数据({@link #onLoadData()})
|
||||
* - 将用户操作转发给 ViewModel
|
||||
*
|
||||
* 生命周期顺序(onCreate):
|
||||
* 1. 创建 DataBinding
|
||||
* 2. 创建 ViewModel({@link #createViewModel()})
|
||||
* 3. 订阅通用状态({@link #observeCommonState()})
|
||||
* 4. 订阅业务状态({@link #observeViewModel()})
|
||||
* 5. 初始化界面({@link #initDataBinding()} / {@link #initView()})
|
||||
* 6. 加载数据({@link #onLoadData()})
|
||||
*
|
||||
* 禁止:
|
||||
* - 在 Activity 中直接进行网络请求或数据库操作(必须通过 ViewModel → Repository)
|
||||
* - 持有可变 LiveData 的引用(应通过 LiveData 回调观察)
|
||||
* - 在 Activity 中写业务逻辑
|
||||
*
|
||||
* @param <VM> ViewModel 类型,必须继承 {@link BaseViewModel} 或 {@link BaseAndroidViewModel}
|
||||
* @param <VDB> ViewDataBinding 类型
|
||||
*/
|
||||
public abstract class BaseMvvmActivity<VM extends ViewModel, VDB extends ViewDataBinding> extends BaseTransparentActivity {
|
||||
|
||||
private static final String TAG = BaseMvvmActivity.class.getSimpleName();
|
||||
@@ -22,39 +51,131 @@ public abstract class BaseMvvmActivity<VM extends ViewModel, VDB extends ViewDat
|
||||
protected VDB mViewDataBinding;
|
||||
protected Class<VM> vmClass;
|
||||
|
||||
// ============================================================
|
||||
// 生命周期
|
||||
// ============================================================
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
//ViewDataBinding
|
||||
|
||||
// 1. 创建 DataBinding
|
||||
mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId());
|
||||
mViewDataBinding.setLifecycleOwner(this);
|
||||
//ViewModel
|
||||
vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
boolean isAbstract = Modifier.isAbstract(vmClass.getModifiers());
|
||||
Logger.e(TAG, "isLocalClass:" + vmClass.getSimpleName().equals(ViewModel.class.getSimpleName()) + " isAbstract:" + isAbstract);
|
||||
if (!isAbstract) {//不是一个抽象类
|
||||
mViewModel = new ViewModelProvider(this).get(vmClass);
|
||||
if (mViewModel instanceof BaseViewModel) {
|
||||
BaseViewModel<?, ?> baseVm = (BaseViewModel<?, ?>) mViewModel;
|
||||
baseVm.setContext(this);
|
||||
baseVm.setVDBinding(mViewDataBinding);
|
||||
baseVm.setLifecycle(getLifecycleSubject());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 创建 ViewModel
|
||||
mViewModel = createViewModel();
|
||||
|
||||
// 3. 订阅通用状态
|
||||
observeCommonState();
|
||||
|
||||
// 4. 订阅业务状态
|
||||
observeViewModel();
|
||||
|
||||
// 5. 初始化界面
|
||||
initDataBinding();
|
||||
initView();
|
||||
initData();
|
||||
|
||||
// 6. 加载数据
|
||||
onLoadData();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 抽象方法(子类必须实现)
|
||||
// ============================================================
|
||||
|
||||
/** 创建 ViewModel 实例(默认通过反射自动创建,子类可按需重写) */
|
||||
protected VM createViewModel() {
|
||||
vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
boolean isAbstract = Modifier.isAbstract(vmClass.getModifiers());
|
||||
if (isAbstract) {
|
||||
Logger.e(TAG, "ViewModel is abstract: " + vmClass.getSimpleName());
|
||||
return null;
|
||||
}
|
||||
return new ViewModelProvider(this).get(vmClass);
|
||||
}
|
||||
|
||||
/** 初始化 DataBinding(如设置 setClick、绑定表达式等) */
|
||||
protected abstract void initDataBinding();
|
||||
|
||||
/**
|
||||
* 初始化视图
|
||||
*/
|
||||
/** 初始化视图(如设置 Adapter、Listener 等) */
|
||||
protected abstract void initView();
|
||||
|
||||
/** 订阅 ViewModel 中的业务 LiveData */
|
||||
protected abstract void observeViewModel();
|
||||
|
||||
// ============================================================
|
||||
// 可选重写
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* 初始化数据
|
||||
* 页面创建完成后加载数据
|
||||
* 子类可重写此方法触发首次数据加载
|
||||
*/
|
||||
protected abstract void initData();
|
||||
protected void onLoadData() {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅全局通用状态(loading / error / success)
|
||||
* 子类可在 {@link #observeViewModel()} 中调用 super.observeCommonState(),或直接重写
|
||||
*/
|
||||
protected void observeCommonState() {
|
||||
if (!(mViewModel instanceof IMvvmUiState)) return;
|
||||
IMvvmUiState vm = (IMvvmUiState) mViewModel;
|
||||
|
||||
vm.getLoadingLiveData().observe(this, loading -> {
|
||||
if (loading != null && loading) {
|
||||
showLoading();
|
||||
} else {
|
||||
hideLoading();
|
||||
}
|
||||
});
|
||||
|
||||
vm.getErrorLiveData().observe(this, error -> {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
showError(error);
|
||||
}
|
||||
});
|
||||
|
||||
vm.getSuccessLiveData().observe(this, msg -> {
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
showSuccess(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// UI 辅助方法(子类可重写)
|
||||
// ============================================================
|
||||
|
||||
protected void showLoading() {
|
||||
// 默认实现:可替换为自定义 LoadingDialog
|
||||
// LoadingDialog.show(this);
|
||||
}
|
||||
|
||||
protected void hideLoading() {
|
||||
// LoadingDialog.dismiss();
|
||||
}
|
||||
|
||||
protected void showError(String message) {
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
protected void showSuccess(String message) {
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 禁止使用的模式(编译期约束)
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* @deprecated 禁止在 MVVM Activity 中直接创建 Handler 做延时操作
|
||||
* → 应使用 ViewModel + LiveData 驱动
|
||||
*/
|
||||
@Deprecated
|
||||
protected Handler getHandler() {
|
||||
throw new UnsupportedOperationException("禁止在 MVVM Activity 中使用 Handler");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,75 +1,106 @@
|
||||
package com.ttstd.dialer.base.mvvm;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.databinding.ViewDataBinding;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||
|
||||
public abstract class BaseViewModel<VDB extends ViewDataBinding, T> extends ViewModel {
|
||||
/**
|
||||
* MVVM ViewModel 基类(无 Context 版本)
|
||||
*
|
||||
* 职责:
|
||||
* - 持有 UI 状态(LiveData)
|
||||
* - 处理业务逻辑
|
||||
* - 暴露数据给 View 层
|
||||
* - 通过 {@link #addDisposable(Disposable)} 统一管理 RxJava 异步任务
|
||||
*
|
||||
* 禁止:
|
||||
* - 持有任何 View 引用(Activity / Fragment / View / Context)
|
||||
* - 直接进行网络请求或数据库操作(必须通过 Repository)
|
||||
* - 在 ViewModel 中弹 Toast / Dialog / Snackbar
|
||||
* - 手动创建 Thread / Executor / AsyncTask 执行异步任务(必须使用 RxJava + {@link #addDisposable(Disposable)})
|
||||
* - 忘记将 Disposable add 到 {@link #mDisposables} 中
|
||||
*
|
||||
* 若需要 Context / Application(如 SharedPreferences、AlarmManager 等),请继承
|
||||
* {@link BaseAndroidViewModel},通过 {@code getAppContext()} 获取 Application Context。
|
||||
*/
|
||||
public abstract class BaseViewModel extends ViewModel implements IMvvmUiState {
|
||||
|
||||
// ============================================================
|
||||
// 通用 UI 状态
|
||||
// ============================================================
|
||||
|
||||
/** 全局加载状态 */
|
||||
private final MutableLiveData<Boolean> mLoadingLiveData = new MutableLiveData<>(false);
|
||||
|
||||
/** 全局错误提示 */
|
||||
private final MutableLiveData<String> mErrorLiveData = new MutableLiveData<>();
|
||||
|
||||
/** 全局成功提示 */
|
||||
private final MutableLiveData<String> mSuccessLiveData = new MutableLiveData<>();
|
||||
|
||||
// ============================================================
|
||||
// RxJava 异步管理(核心)
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Google 标准写法:ViewModel 内统一管理 Rx 订阅,
|
||||
* onCleared 时自动取消,防止内存泄漏。
|
||||
* CompositeDisposable 用于统一管理所有 RxJava 订阅。
|
||||
* 在 onCleared() 中自动 dispose,防止内存泄漏。
|
||||
*/
|
||||
protected final CompositeDisposable mDisposables = new CompositeDisposable();
|
||||
|
||||
// ============================================================
|
||||
// 对外暴露(只读)
|
||||
// ============================================================
|
||||
|
||||
public LiveData<Boolean> getLoadingLiveData() {
|
||||
return mLoadingLiveData;
|
||||
}
|
||||
|
||||
public LiveData<String> getErrorLiveData() {
|
||||
return mErrorLiveData;
|
||||
}
|
||||
|
||||
public LiveData<String> getSuccessLiveData() {
|
||||
return mSuccessLiveData;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 受保护的方法(子类调用)
|
||||
// ============================================================
|
||||
|
||||
protected void setLoading(boolean loading) {
|
||||
mLoadingLiveData.postValue(loading);
|
||||
}
|
||||
|
||||
protected void setError(String message) {
|
||||
mErrorLiveData.postValue(message);
|
||||
}
|
||||
|
||||
protected void setSuccess(String message) {
|
||||
mSuccessLiveData.postValue(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将订阅托管给 ViewModel 生命周期
|
||||
* 便捷方法:将 Disposable 添加到 {@link #mDisposables} 中管理。
|
||||
* 子类在发起 RxJava 请求时调用此方法,确保 ViewModel 销毁时自动取消订阅。
|
||||
*/
|
||||
protected void addDisposable(Disposable disposable) {
|
||||
mDisposables.add(disposable);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 生命周期
|
||||
// ============================================================
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
mDisposables.clear();
|
||||
super.onCleared();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前viewmodel对应的页面binding
|
||||
*/
|
||||
protected VDB binding;
|
||||
|
||||
public void setVDBinding(ViewDataBinding vdBinding) {
|
||||
binding = (VDB) vdBinding;
|
||||
}
|
||||
|
||||
public VDB getVDBinding() {
|
||||
if (binding == null) {
|
||||
throw new NullPointerException("BaseViewModel >> getVDBinding >> null!!!");
|
||||
// ViewModel 销毁时,自动取消所有正在执行的 RxJava 任务
|
||||
if (!mDisposables.isDisposed()) {
|
||||
mDisposables.clear();
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
private WeakReference<Context> weakContext;
|
||||
|
||||
public void setContext(Context context) {
|
||||
if (weakContext == null) {
|
||||
weakContext = new WeakReference<>(context.getApplicationContext());
|
||||
}
|
||||
}
|
||||
|
||||
public Context getSafeContext() {
|
||||
if (weakContext == null) {
|
||||
throw new NullPointerException("BaseViewModel >> getCtx >> null!!!");
|
||||
}
|
||||
return weakContext.get();
|
||||
}
|
||||
|
||||
private BehaviorSubject<T> mBehaviorSubject;
|
||||
|
||||
public void setLifecycle(BehaviorSubject subject) {
|
||||
this.mBehaviorSubject = (BehaviorSubject<T>) subject;
|
||||
}
|
||||
|
||||
public BehaviorSubject<T> getLifecycle() {
|
||||
return mBehaviorSubject;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.ttstd.dialer.base.mvvm;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
/**
|
||||
* MVVM ViewModel 通用 UI 状态接口
|
||||
*
|
||||
* {@link BaseViewModel} 与 {@link BaseAndroidViewModel} 均实现本接口,
|
||||
* 使基类({@link BaseMvvmActivity} / {@link BaseMvvmFragment} / {@link BaseMvvmDialogFragment})
|
||||
* 能以统一的 {@code VM extends ViewModel} 泛型约束订阅 loading / error / success 状态。
|
||||
*/
|
||||
public interface IMvvmUiState {
|
||||
|
||||
/** 全局加载状态(只读) */
|
||||
LiveData<Boolean> getLoadingLiveData();
|
||||
|
||||
/** 全局错误提示(只读) */
|
||||
LiveData<String> getErrorLiveData();
|
||||
|
||||
/** 全局成功提示(只读) */
|
||||
LiveData<String> getSuccessLiveData();
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -16,20 +17,35 @@ import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.ttstd.dialer.base.BaseDialogFragment;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.base.mvvm.IMvvmUiState;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
||||
/**
|
||||
* 优化生命周期管理,去掉冗余的 Bundle 定义
|
||||
* @param <VM> ViewModel 类型
|
||||
* MVVM DialogFragment 基类
|
||||
*
|
||||
* 职责:
|
||||
* - 绑定 DataBinding
|
||||
* - 初始化 ViewModel(默认通过反射自动创建)
|
||||
* - 订阅 ViewModel 中的 LiveData({@link #observeViewModel()})
|
||||
* - 订阅全局通用状态({@link #observeCommonState()})
|
||||
* - 页面创建完成后加载数据({@link #onLoadData()})
|
||||
* - 将用户操作转发给 ViewModel
|
||||
*
|
||||
* 禁止:
|
||||
* - 在 DialogFragment 中直接进行网络请求或数据库操作(必须通过 ViewModel → Repository)
|
||||
* - 持有可变 LiveData 的引用(应通过 LiveData 回调观察)
|
||||
* - 在 DialogFragment 中写业务逻辑
|
||||
*
|
||||
* @param <VM> ViewModel 类型,必须继承 {@link BaseViewModel} 或 {@link BaseAndroidViewModel}
|
||||
* @param <VDB> ViewDataBinding 类型
|
||||
*/
|
||||
public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends ViewDataBinding> extends BaseDialogFragment {
|
||||
|
||||
protected final String mTag = this.getClass().getSimpleName();
|
||||
|
||||
|
||||
protected boolean mIsVisible;
|
||||
protected boolean mHasPrepare;
|
||||
|
||||
@@ -48,18 +64,16 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
ctx = new WeakReference<>(context);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 生命周期
|
||||
// ============================================================
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// ViewModel 初始化移至 onCreate
|
||||
// ViewModel 初始化
|
||||
try {
|
||||
Class<VM> vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
mViewModel = new ViewModelProvider(this).get(vmClass);
|
||||
if (mViewModel instanceof BaseViewModel) {
|
||||
BaseViewModel<?, ?> baseVm = (BaseViewModel<?, ?>) mViewModel;
|
||||
baseVm.setContext(getContext());
|
||||
baseVm.setLifecycle(getLifecycleSubject());
|
||||
}
|
||||
mViewModel = createViewModel();
|
||||
} catch (Exception e) {
|
||||
Logger.e(mTag, "ViewModel initialization failed: " + e.getMessage());
|
||||
}
|
||||
@@ -68,10 +82,8 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
// DataBinding 初始化
|
||||
mViewDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false);
|
||||
if (mViewModel instanceof BaseViewModel) {
|
||||
((BaseViewModel<?, ?>) mViewModel).setVDBinding(mViewDataBinding);
|
||||
}
|
||||
return mViewDataBinding.getRoot();
|
||||
}
|
||||
|
||||
@@ -80,9 +92,17 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mViewDataBinding.setLifecycleOwner(getViewLifecycleOwner());
|
||||
|
||||
// 订阅通用状态
|
||||
observeCommonState();
|
||||
|
||||
// 订阅业务状态
|
||||
observeViewModel();
|
||||
|
||||
initDataBinding();
|
||||
initView(getArguments());
|
||||
initData(savedInstanceState);
|
||||
initView(savedInstanceState);
|
||||
|
||||
// 加载数据
|
||||
onLoadData();
|
||||
|
||||
mHasPrepare = true;
|
||||
if (mIsVisible || getUserVisibleHint()) {
|
||||
@@ -96,9 +116,6 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
super.onDestroyView();
|
||||
mHasPrepare = false;
|
||||
// 及时解绑 Binding,防止内存泄漏
|
||||
if (mViewModel instanceof BaseViewModel) {
|
||||
((BaseViewModel<?, ?>) mViewModel).setVDBinding(null);
|
||||
}
|
||||
mViewDataBinding = null;
|
||||
}
|
||||
|
||||
@@ -122,14 +139,85 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
public void fetchData() {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 抽象方法(子类必须实现)
|
||||
// ============================================================
|
||||
|
||||
/** 创建 ViewModel 实例(默认通过反射自动创建,子类可按需重写) */
|
||||
protected VM createViewModel() {
|
||||
Class<VM> vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
return new ViewModelProvider(this).get(vmClass);
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
protected abstract int getLayoutId();
|
||||
|
||||
/** 初始化 DataBinding(如设置 setClick、绑定表达式等) */
|
||||
protected abstract void initDataBinding();
|
||||
|
||||
protected abstract void initView(Bundle bundle);
|
||||
/** 初始化视图(如设置 Adapter、Listener 等) */
|
||||
protected abstract void initView(Bundle savedInstanceState);
|
||||
|
||||
protected abstract void initData(Bundle savedInstanceState);
|
||||
/** 订阅 ViewModel 中的业务 LiveData */
|
||||
protected abstract void observeViewModel();
|
||||
|
||||
// ============================================================
|
||||
// 可选重写
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* 页面创建完成后加载数据
|
||||
* 子类可重写此方法触发首次数据加载
|
||||
*/
|
||||
protected void onLoadData() {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅全局通用状态(loading / error / success)
|
||||
*/
|
||||
protected void observeCommonState() {
|
||||
if (!(mViewModel instanceof IMvvmUiState)) return;
|
||||
IMvvmUiState vm = (IMvvmUiState) mViewModel;
|
||||
|
||||
vm.getLoadingLiveData().observe(getViewLifecycleOwner(), loading -> {
|
||||
if (loading != null && loading) {
|
||||
showLoading();
|
||||
} else {
|
||||
hideLoading();
|
||||
}
|
||||
});
|
||||
|
||||
vm.getErrorLiveData().observe(getViewLifecycleOwner(), error -> {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
showError(error);
|
||||
}
|
||||
});
|
||||
|
||||
vm.getSuccessLiveData().observe(getViewLifecycleOwner(), msg -> {
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
showSuccess(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// UI 辅助方法(子类可重写)
|
||||
// ============================================================
|
||||
|
||||
protected void showLoading() {
|
||||
}
|
||||
|
||||
protected void hideLoading() {
|
||||
}
|
||||
|
||||
protected void showError(String message) {
|
||||
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
protected void showSuccess(String message) {
|
||||
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -16,27 +17,41 @@ import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.ttstd.dialer.base.BaseFragment;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.base.mvvm.IMvvmUiState;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
||||
/**
|
||||
* 优化生命周期管理,去掉冗余的 Bundle 定义
|
||||
* @param <VM> ViewModel 类型
|
||||
* MVVM Fragment 基类
|
||||
*
|
||||
* 职责:
|
||||
* - 绑定 DataBinding
|
||||
* - 初始化 ViewModel(默认通过反射自动创建)
|
||||
* - 订阅 ViewModel 中的 LiveData({@link #observeViewModel()})
|
||||
* - 订阅全局通用状态({@link #observeCommonState()})
|
||||
* - 页面创建完成后加载数据({@link #onLoadData()})
|
||||
* - 支持懒加载({@link #onEnter()} / {@link #onExit()})
|
||||
* - 将用户操作转发给 ViewModel
|
||||
*
|
||||
* 禁止:
|
||||
* - 在 Fragment 中直接进行网络请求或数据库操作(必须通过 ViewModel → Repository)
|
||||
* - 持有可变 LiveData 的引用(应通过 LiveData 回调观察)
|
||||
* - 在 Fragment 中写业务逻辑
|
||||
* - 使用 getActivity() 强转后直接操作 Activity(应通过 ViewModel 通信)
|
||||
*
|
||||
* @param <VM> ViewModel 类型,必须继承 {@link BaseViewModel} 或 {@link BaseAndroidViewModel}
|
||||
* @param <VDB> ViewDataBinding 类型
|
||||
*/
|
||||
public abstract class BaseMvvmFragment<VM extends ViewModel, VDB extends ViewDataBinding> extends BaseFragment {
|
||||
|
||||
protected final String mTag = this.getClass().getSimpleName();
|
||||
|
||||
/**
|
||||
* 是否可见(用于懒加载逻辑)
|
||||
*/
|
||||
|
||||
/** 是否可见(用于懒加载逻辑) */
|
||||
protected boolean mIsVisible;
|
||||
/**
|
||||
* View 是否准备完毕
|
||||
*/
|
||||
|
||||
/** View 是否准备完毕 */
|
||||
protected boolean mHasPrepare;
|
||||
|
||||
protected VM mViewModel;
|
||||
@@ -54,18 +69,16 @@ public abstract class BaseMvvmFragment<VM extends ViewModel, VDB extends ViewDat
|
||||
ctx = new WeakReference<>(context);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 生命周期
|
||||
// ============================================================
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// ViewModel 初始化
|
||||
try {
|
||||
Class<VM> vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
mViewModel = new ViewModelProvider(this).get(vmClass);
|
||||
if (mViewModel instanceof BaseViewModel) {
|
||||
BaseViewModel<?, ?> baseVm = (BaseViewModel<?, ?>) mViewModel;
|
||||
baseVm.setContext(getContext());
|
||||
baseVm.setLifecycle(getLifecycleSubject());
|
||||
}
|
||||
mViewModel = createViewModel();
|
||||
} catch (Exception e) {
|
||||
Logger.e(mTag, "ViewModel initialization failed: " + e.getMessage());
|
||||
}
|
||||
@@ -74,11 +87,8 @@ public abstract class BaseMvvmFragment<VM extends ViewModel, VDB extends ViewDat
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
// ViewDataBinding 初始化
|
||||
// DataBinding 初始化
|
||||
mViewDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false);
|
||||
if (mViewModel instanceof BaseViewModel) {
|
||||
((BaseViewModel<?, ?>) mViewModel).setVDBinding(mViewDataBinding);
|
||||
}
|
||||
return mViewDataBinding.getRoot();
|
||||
}
|
||||
|
||||
@@ -86,11 +96,18 @@ public abstract class BaseMvvmFragment<VM extends ViewModel, VDB extends ViewDat
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mViewDataBinding.setLifecycleOwner(getViewLifecycleOwner());
|
||||
|
||||
|
||||
// 订阅通用状态
|
||||
observeCommonState();
|
||||
|
||||
// 订阅业务状态
|
||||
observeViewModel();
|
||||
|
||||
initDataBinding();
|
||||
// 去掉重复的 bundle 和 savedInstanceState 定义,直接从参数/方法获取
|
||||
initView(getArguments());
|
||||
initData(savedInstanceState);
|
||||
initView(savedInstanceState);
|
||||
|
||||
// 加载数据
|
||||
onLoadData();
|
||||
|
||||
mHasPrepare = true;
|
||||
// 检查初始可见性
|
||||
@@ -105,9 +122,6 @@ public abstract class BaseMvvmFragment<VM extends ViewModel, VDB extends ViewDat
|
||||
super.onDestroyView();
|
||||
mHasPrepare = false;
|
||||
// 及时解绑 Binding,防止内存泄漏
|
||||
if (mViewModel instanceof BaseViewModel) {
|
||||
((BaseViewModel<?, ?>) mViewModel).setVDBinding(null);
|
||||
}
|
||||
mViewDataBinding = null;
|
||||
}
|
||||
|
||||
@@ -127,14 +141,91 @@ public abstract class BaseMvvmFragment<VM extends ViewModel, VDB extends ViewDat
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 抽象方法(子类必须实现)
|
||||
// ============================================================
|
||||
|
||||
/** 创建 ViewModel 实例(默认通过反射自动创建,子类可按需重写) */
|
||||
protected VM createViewModel() {
|
||||
Class<VM> vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
return new ViewModelProvider(this).get(vmClass);
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
protected abstract int getLayoutId();
|
||||
|
||||
/** 初始化 DataBinding(如设置 setClick、绑定表达式等) */
|
||||
protected abstract void initDataBinding();
|
||||
|
||||
protected abstract void initView(Bundle bundle);
|
||||
/** 初始化视图(如设置 Adapter、Listener 等) */
|
||||
protected abstract void initView(Bundle savedInstanceState);
|
||||
|
||||
protected abstract void initData(Bundle savedInstanceState);
|
||||
/** 订阅 ViewModel 中的业务 LiveData */
|
||||
protected abstract void observeViewModel();
|
||||
|
||||
// ============================================================
|
||||
// 可选重写
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* 页面创建完成后加载数据
|
||||
* 子类可重写此方法触发首次数据加载
|
||||
*/
|
||||
protected void onLoadData() {
|
||||
// 默认空实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅全局通用状态(loading / error / success)
|
||||
* 子类可在 {@link #observeViewModel()} 中调用 super.observeCommonState(),或直接重写
|
||||
*/
|
||||
protected void observeCommonState() {
|
||||
if (!(mViewModel instanceof IMvvmUiState)) return;
|
||||
IMvvmUiState vm = (IMvvmUiState) mViewModel;
|
||||
|
||||
vm.getLoadingLiveData().observe(getViewLifecycleOwner(), loading -> {
|
||||
if (loading != null && loading) {
|
||||
showLoading();
|
||||
} else {
|
||||
hideLoading();
|
||||
}
|
||||
});
|
||||
|
||||
vm.getErrorLiveData().observe(getViewLifecycleOwner(), error -> {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
showError(error);
|
||||
}
|
||||
});
|
||||
|
||||
vm.getSuccessLiveData().observe(getViewLifecycleOwner(), msg -> {
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
showSuccess(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// UI 辅助方法(子类可重写)
|
||||
// ============================================================
|
||||
|
||||
protected void showLoading() {
|
||||
// 默认实现:可替换为自定义 LoadingDialog
|
||||
}
|
||||
|
||||
protected void hideLoading() {
|
||||
}
|
||||
|
||||
protected void showError(String message) {
|
||||
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
protected void showSuccess(String message) {
|
||||
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 懒加载回调(子类可重写)
|
||||
// ============================================================
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
@@ -150,4 +241,17 @@ public abstract class BaseMvvmFragment<VM extends ViewModel, VDB extends ViewDat
|
||||
public boolean isAttached() {
|
||||
return getCtx() != null && isAdded();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 禁止使用的模式(编译期约束)
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* @deprecated 禁止在 MVVM Fragment 中通过 getActivity() 强转后直接操作 Activity
|
||||
* → 应通过 ViewModel 通信
|
||||
*/
|
||||
@Deprecated
|
||||
protected android.app.Activity getActivityAs() {
|
||||
throw new UnsupportedOperationException("禁止在 MVVM Fragment 中使用 getActivity() 强转");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,10 +104,10 @@ public class AppFragment extends BaseMvvmFragment<AppViewModel, FragmentAppBindi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
Logger.e(TAG, "initData: ");
|
||||
Logger.e(TAG, "initData: " + mViewModel.mAppUpdateData);
|
||||
mViewModel.mAppUpdateData.observe(getViewLifecycleOwner(), new Observer<Integer>() {
|
||||
protected void observeViewModel() {
|
||||
Logger.e(TAG, "observeViewModel: ");
|
||||
Logger.e(TAG, "observeViewModel: " + mViewModel.getAppUpdateData());
|
||||
mViewModel.getAppUpdateData().observe(getViewLifecycleOwner(), new Observer<Integer>() {
|
||||
@Override
|
||||
public void onChanged(Integer integer) {
|
||||
if (integer > 0) {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package com.ttstd.dialer.fragment.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import com.trello.rxlifecycle4.RxLifecycle;
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.FragmentAppBinding;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.db.app.AppInfo;
|
||||
import com.ttstd.dialer.db.app.AppRepository;
|
||||
import com.ttstd.dialer.livedata.SingleLiveEvent;
|
||||
@@ -14,31 +11,27 @@ import com.ttstd.dialer.utils.Logger;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class AppViewModel extends BaseViewModel<FragmentAppBinding, FragmentEvent> {
|
||||
public class AppViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "AppViewModel";
|
||||
|
||||
private AppRepository mAppRepository;
|
||||
private final AppRepository mAppRepository;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mAppRepository = new AppRepository(context);
|
||||
private final SingleLiveEvent<Integer> mAppUpdateData = new SingleLiveEvent<>();
|
||||
|
||||
public AppViewModel(Application application) {
|
||||
super(application);
|
||||
mAppRepository = new AppRepository(application);
|
||||
}
|
||||
|
||||
public SingleLiveEvent<Integer> mAppUpdateData = new SingleLiveEvent<>();
|
||||
|
||||
// public void resetLiveData() {
|
||||
// mAppUpdateData = new MutableLiveData<>();
|
||||
// }
|
||||
public SingleLiveEvent<Integer> getAppUpdateData() {
|
||||
return mAppUpdateData;
|
||||
}
|
||||
|
||||
public void updateAppInfo(AppInfo appInfo) {
|
||||
Observable.fromCallable(new Callable<Integer>() {
|
||||
addDisposable(Observable.fromCallable(new Callable<Integer>() {
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
// 根据状态自动设置位置为最大值
|
||||
@@ -53,30 +46,13 @@ public class AppViewModel extends BaseViewModel<FragmentAppBinding, FragmentEven
|
||||
}
|
||||
return mAppRepository.update(appInfo);
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY))
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<Integer>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("updateAppInfo", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull Integer row) {
|
||||
Logger.e("updateAppInfo", "onNext: " + row);
|
||||
mAppUpdateData.setValue(row);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("updateAppInfo", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("updateAppInfo", "onComplete: ");
|
||||
}
|
||||
});
|
||||
.subscribe(row -> {
|
||||
Logger.e("updateAppInfo", "onNext: " + row);
|
||||
mAppUpdateData.setValue(row);
|
||||
},
|
||||
throwable -> Logger.e("updateAppInfo", "onError: " + throwable.getMessage())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,9 +56,8 @@ public class ContactFragment extends BaseMvvmFragment<ContactViewModel, Fragment
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
mViewModel.preloadData();
|
||||
mViewModel.mContactListData.observe(getViewLifecycleOwner(), new Observer<List<ContactInfo>>() {
|
||||
protected void observeViewModel() {
|
||||
mViewModel.getContactListData().observe(getViewLifecycleOwner(), new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<ContactInfo> contactInfos) {
|
||||
Logger.e(TAG, "mContactListData: " + contactInfos);
|
||||
@@ -68,6 +67,11 @@ public class ContactFragment extends BaseMvvmFragment<ContactViewModel, Fragment
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoadData() {
|
||||
mViewModel.preloadData();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void fetchData() {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.ttstd.dialer.fragment.contact;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.base.mvvm.BaseAndroidViewModel;
|
||||
import com.ttstd.dialer.data.repository.ContactDataRepository;
|
||||
import com.ttstd.dialer.databinding.FragmentContactBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
@@ -18,19 +17,25 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
/**
|
||||
* 主页联系人 ViewModel(Google 标准 MVVM):
|
||||
* 统一走 Repository 多级缓存 + SWR,内存/磁盘缓存秒出,后台自动 revalidate。
|
||||
*
|
||||
* 需通过 {@link #getAppContext()} 获取 Application Context 初始化 Repository,
|
||||
* 不持有任何 View / Activity 引用。
|
||||
*/
|
||||
public class ContactViewModel extends BaseViewModel<FragmentContactBinding, FragmentEvent> {
|
||||
public class ContactViewModel extends BaseAndroidViewModel {
|
||||
private static final String TAG = "ContactViewModel";
|
||||
|
||||
private ContactDataRepository mRepository;
|
||||
private final ContactDataRepository mRepository;
|
||||
private boolean isDataLoaded = false;
|
||||
|
||||
public MutableLiveData<List<ContactInfo>> mContactListData = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<ContactInfo>> mContactListData = new MutableLiveData<>();
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = ContactDataRepository.getInstance(context);
|
||||
public ContactViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = ContactDataRepository.getInstance(application);
|
||||
}
|
||||
|
||||
public LiveData<List<ContactInfo>> getContactListData() {
|
||||
return mContactListData;
|
||||
}
|
||||
|
||||
public void preloadData() {
|
||||
|
||||
@@ -59,7 +59,7 @@ public class CallFragment extends BaseMvvmDialogFragment<CallViewModel, DialogFr
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.ttstd.dialer.fragment.dialog.contact.call;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.DialogFragmentContactCallBinding;
|
||||
|
||||
public class CallViewModel extends BaseViewModel<DialogFragmentContactCallBinding, FragmentEvent> {
|
||||
public class CallViewModel extends BaseViewModel {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class ContactDeleteDialogFragment extends BaseMvvmDialogFragment<ContactD
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.ttstd.dialer.fragment.dialog.contact.delete;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.DialogFragmentDeleteContactBinding;
|
||||
|
||||
public class ContactDeleteViewModel extends BaseViewModel<DialogFragmentDeleteContactBinding, FragmentEvent> {
|
||||
public class ContactDeleteViewModel extends BaseViewModel {
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class EditDialogFragment extends BaseMvvmDialogFragment<EditViewModel, Di
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.ttstd.dialer.fragment.dialog.contact.edit;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.DialogFragmentEditContactBinding;
|
||||
|
||||
public class EditViewModel extends BaseViewModel<DialogFragmentEditContactBinding, FragmentEvent> {
|
||||
public class EditViewModel extends BaseViewModel {
|
||||
}
|
||||
|
||||
@@ -87,11 +87,6 @@ public class DockAppDialogFagment extends BaseMvvmDialogFragment<DockAppViewMode
|
||||
|
||||
@Override
|
||||
protected void initView(Bundle bundle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
if (TextUtils.isEmpty(mTitile)) {
|
||||
mViewDataBinding.tvTitle.setText("提示");
|
||||
} else {
|
||||
@@ -130,6 +125,11 @@ public class DockAppDialogFagment extends BaseMvvmDialogFragment<DockAppViewMode
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package com.ttstd.dialer.fragment.dialog.dock;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.FragmentDialogDockAppBinding;
|
||||
import com.ttstd.dialer.databinding.FragmentDialogShortcutBinding;
|
||||
|
||||
public class DockAppViewModel extends BaseViewModel <FragmentDialogDockAppBinding, FragmentEvent>{
|
||||
public class DockAppViewModel extends BaseViewModel {
|
||||
|
||||
}
|
||||
|
||||
@@ -82,11 +82,6 @@ public class MoveAppDialogFagment extends BaseMvvmDialogFragment<MoveAppViewMode
|
||||
|
||||
@Override
|
||||
protected void initView(Bundle bundle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
if (TextUtils.isEmpty(mTitile)) {
|
||||
mViewDataBinding.tvTitle.setText("提示");
|
||||
} else {
|
||||
@@ -125,6 +120,11 @@ public class MoveAppDialogFagment extends BaseMvvmDialogFragment<MoveAppViewMode
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.ttstd.dialer.fragment.dialog.move;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.FragmentDialogMoveAppBinding;
|
||||
|
||||
public class MoveAppViewModel extends BaseViewModel <FragmentDialogMoveAppBinding, FragmentEvent>{
|
||||
public class MoveAppViewModel extends BaseViewModel {
|
||||
|
||||
}
|
||||
|
||||
@@ -87,11 +87,6 @@ public class ShortcutDialogFagment extends BaseMvvmDialogFragment<ShortcutViewMo
|
||||
|
||||
@Override
|
||||
protected void initView(Bundle bundle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
if (TextUtils.isEmpty(mTitile)) {
|
||||
mViewDataBinding.tvTitle.setText("提示");
|
||||
} else {
|
||||
@@ -130,6 +125,11 @@ public class ShortcutDialogFagment extends BaseMvvmDialogFragment<ShortcutViewMo
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.ttstd.dialer.fragment.dialog.shortcut;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.FragmentDialogShortcutBinding;
|
||||
|
||||
public class ShortcutViewModel extends BaseViewModel <FragmentDialogShortcutBinding, FragmentEvent>{
|
||||
public class ShortcutViewModel extends BaseViewModel {
|
||||
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public class HomeFragment extends BaseMvvmFragment<HomeViewModel, FragmentHomeBi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
protected void observeViewModel() {
|
||||
LiveEventBus.get(CommonConfig.LOCATION_CHANGED_KEY, SnLocationReq.class)
|
||||
.observeSticky(this, new Observer<SnLocationReq>() {
|
||||
@Override
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.ttstd.dialer.fragment.home;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.FragmentHomeBinding;
|
||||
|
||||
public class HomeViewModel extends BaseViewModel<FragmentHomeBinding, FragmentEvent> {
|
||||
public class HomeViewModel extends BaseViewModel {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class SettingsFragment extends BaseMvvmFragment<SettingsViewModel, Fragme
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
protected void observeViewModel() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.ttstd.dialer.fragment.settings;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.FragmentSettingsBinding;
|
||||
|
||||
public class SettingsViewModel extends BaseViewModel<FragmentSettingsBinding, FragmentEvent> {
|
||||
public class SettingsViewModel extends BaseViewModel {
|
||||
|
||||
}
|
||||
|
||||
@@ -319,6 +319,13 @@ public class OkHttpManager {
|
||||
return schedule(getApiService(SnApi.class).register(DeviceManagerService.getInstance().getSerial(), Build.MODEL), provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备注册(由 ViewModel 通过 addDisposable 管理订阅生命周期)
|
||||
*/
|
||||
public Observable<BaseResponse> getSnRegisterObservable() {
|
||||
return schedule(getApiService(SnApi.class).register(DeviceManagerService.getInstance().getSerial(), Build.MODEL));
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传设备基本信息
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user