From 61398ff4ff63573778ecd2a4d967a44da250e8e3 Mon Sep 17 00:00:00 2001 From: TongTongStudio Date: Mon, 3 Aug 2026 00:25:25 +0800 Subject: [PATCH] =?UTF-8?q?feat(base):=20=E6=B7=BB=E5=8A=A0MVVM=E3=80=81Rx?= =?UTF-8?q?=E7=94=9F=E5=91=BD=E5=91=A8=E6=9C=9F=E5=92=8CWebRTC=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E7=AB=AF=E5=9F=BA=E7=A1=80=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 引入BaseApplication、BaseService及MVVM基类(BaseViewModel/BaseMvvmActivity), 集成RxLifecycle管理生命周期,新增WebRTC控制端MainActivity与信令客户端, 建立屏幕捕获、推送、JPush等模块初始化流程,完善项目核心框架。 --- .../controlled/base/BaseApplication.java | 235 ++++++++++++++++++ .../ttstd/controlled/base/BaseService.java | 61 +++++ .../ttstd/controlled/base/BaseViewModel.java | 10 - .../base/{ => mvvm}/BaseMvvmActivity.java | 2 +- .../controlled/base/mvvm/BaseViewModel.java | 57 +++++ .../controlled/base/rx/BaseRxActivity.java | 94 +++++++ .../base/rx/BaseRxDialogFragment.java | 123 +++++++++ .../controlled/base/rx/BaseRxFragment.java | 123 +++++++++ .../controlled/base/rx/BaseRxService.java | 56 +++++ .../ttstd/controlled/config/CommonConfig.java | 6 + .../service/ScreenCaptureModel.java | 60 +++++ .../{ => activity/main}/MainActivity.java | 8 +- .../activity/main/MainViewModel.java | 6 + .../controller/base/BaseApplication.java | 61 +++++ .../ttstd/controller/base/BaseService.java | 61 +++++ .../base/mvvm/BaseMvvmActivity.java | 45 ++++ .../controller/base/mvvm/BaseViewModel.java | 57 +++++ .../controller/base/rx/BaseRxActivity.java | 94 +++++++ .../base/rx/BaseRxDialogFragment.java | 123 +++++++++ .../controller/base/rx/BaseRxFragment.java | 123 +++++++++ .../controller/base/rx/BaseRxService.java | 56 +++++ 21 files changed, 1445 insertions(+), 16 deletions(-) create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseApplication.java create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseService.java delete mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseViewModel.java rename WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/{ => mvvm}/BaseMvvmActivity.java (97%) create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/mvvm/BaseViewModel.java create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxActivity.java create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxDialogFragment.java create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxFragment.java create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxService.java create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/config/CommonConfig.java create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureModel.java rename WebRTCController/app/src/main/java/com/ttstd/controller/{ => activity/main}/MainActivity.java (99%) create mode 100644 WebRTCController/app/src/main/java/com/ttstd/controller/activity/main/MainViewModel.java create mode 100644 WebRTCController/app/src/main/java/com/ttstd/controller/base/BaseApplication.java create mode 100644 WebRTCController/app/src/main/java/com/ttstd/controller/base/BaseService.java create mode 100644 WebRTCController/app/src/main/java/com/ttstd/controller/base/mvvm/BaseMvvmActivity.java create mode 100644 WebRTCController/app/src/main/java/com/ttstd/controller/base/mvvm/BaseViewModel.java create mode 100644 WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxActivity.java create mode 100644 WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxDialogFragment.java create mode 100644 WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxFragment.java create mode 100644 WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxService.java diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseApplication.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseApplication.java new file mode 100644 index 0000000..3aebfbf --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseApplication.java @@ -0,0 +1,235 @@ +package com.ttstd.dialer.base; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; + +import androidx.multidex.MultiDex; + +import com.alibaba.android.arouter.launcher.ARouter; +import com.arialyy.aria.core.Aria; +import com.kongzue.dialogx.DialogX; +import com.tencent.bugly.crashreport.CrashReport; +import com.tencent.mmkv.MMKV; +import com.ttstd.dialer.BuildConfig; +import com.ttstd.dialer.alarmclock.AlarmManagerHelper; +import com.ttstd.dialer.config.CommonConfig; +import com.ttstd.dialer.config.SystemIntentAction; +import com.ttstd.dialer.data.cache.CacheManager; +import com.ttstd.dialer.manager.AppManager; +import com.ttstd.dialer.manager.MapManager; +import com.ttstd.dialer.manager.WeatherManager; +import com.ttstd.dialer.mdm.DeviceManagerService; +import com.ttstd.dialer.network.OkHttpManager; +import com.ttstd.dialer.push.PushExecutor; +import com.ttstd.dialer.receiver.AppChangedReceiver; +import com.ttstd.dialer.receiver.HourlyChimeManager; +import com.ttstd.dialer.tts.sherpa_onnx.SherpaOnnxTtsManager; +import com.ttstd.dialer.utils.Logger; +import com.ttstd.dialer.utils.NativeUtils; +import com.ttstd.dialer.utils.SystemUtils; +import com.ttstd.iconloader.IconCacheManager; + +import cn.jiguang.api.JCoreInterface; +import cn.jiguang.api.utils.JCollectionAuth; +import cn.jpush.android.api.JPushInterface; + + +public class BaseApplication extends Application { + private static final String TAG = "BaseApplication"; + + private MMKV mMMKV; + + /** + * ViewModel中因为经常旋转导致弱引用为空 + */ + @SuppressLint("StaticFieldLeak") + private static Context mAppContext; + + public static Context getContext() { + return mAppContext; + } + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + MultiDex.install(this); + } + + @Override + public void onCreate() { + super.onCreate(); + Logger.e(TAG, "onCreate: "); + mAppContext = getApplicationContext(); + + if (!BuildConfig.DEBUG) { + catchException(); + } + // 在开始分析的地方调用,传入路径 + // 如果是放到外部路径,需要添加权限 + // 默认存储在/sdcard/Android/data/packagename/files +// Debug.startMethodTracing("App" + System.currentTimeMillis()); + init(); + } + + @Override + public void onTerminate() { + super.onTerminate(); + unregisterReceivers(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + } + + private void init() { + Logger.e(TAG, "init: "); + Logger.e(TAG, "init: getNonce = " + NativeUtils.getNonce()); + if (SystemUtils.isMainProcessName(this, android.os.Process.myPid())) { + Logger.initialize(this, BuildConfig.DEBUG); + Logger.setLogLevel(Logger.LogLevel.DEBUG); // 开发阶段记录所有日志 + + String rootDir = MMKV.initialize(this); + Logger.e(TAG, "mmkv root: " + rootDir); + mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + + DeviceManagerService.init(this); + OkHttpManager.init(this); + PushExecutor.init(this); + initJPush(); + + if (BuildConfig.DEBUG) { // 这两行必须写在init之前,否则这些配置在init过程中将无效 + ARouter.openLog(); // 打印日志 + ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险) + } + ARouter.init(this); // 尽可能早,推荐在Application中初始化 + + DialogX.init(this); + + Logger.e(TAG, "slowInit: "); + Aria.init(this); + CrashReport.initCrashReport(getApplicationContext(), "845e3ed68c", false); + CrashReport.setDeviceId(this, Build.MODEL); + xcrash.XCrash.init(this); + + AppManager.init(this); + MapManager.init(this); + MapManager.getInstance().initMap(); + MapManager.getInstance().startLocation(); + + WeatherManager.init(this); + IconCacheManager.init(this); + SherpaOnnxTtsManager.getInstance().init(this); + AlarmManagerHelper.rescheduleAllAlarms(this); + + if (mMMKV.decodeInt(CommonConfig.HOURLY_CHIME_ENABLE, 0) == 1) { + HourlyChimeManager.startChime(this); + } + + registerReceivers(); + + // 启动时异步清理磁盘缓存(过期淘汰 + 容量上限),不阻塞启动 + CacheManager.getInstance(this).cleanupAsync(); + } + } + + private void initJPush() { + /*jpush start*/ + JPushInterface.setDebugMode(true); + // 调整点一:调用启用推送业务功能代码前增加setAuth调用 + boolean isPrivacyReady = true; // app根据是否已弹窗获取隐私授权来赋值 + if (!isPrivacyReady) { + // JCore 5.0.4之前版本需要显式设置false + if (JCoreInterface.getJCoreSDKVersionInt() < 504) { // 5.0.4版本号对应504 + JCollectionAuth.setAuth(this, false); + } + // 所有版本在未授权时都不应初始化SDK + return; + } + JPushInterface.init(this); + JPushInterface.setAlias(this, 0, DeviceManagerService.getInstance().getSerial()); + + // 调整点二:App用户同意了隐私政策授权,并且开发者确定要开启推送服务后调用 + // JCore 5.0.4+会自动处理授权状态,可不需要显式设置true + JCollectionAuth.setAuth(this, true); + /*jpush end*/ + Logger.e(TAG, "initJPush: inited JPush"); + + } + + private void catchException() { + Thread.setDefaultUncaughtExceptionHandler( + new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + Logger.e("捕获异常子线程:", Thread.currentThread().getName() + + "在:" + e.getStackTrace()[0].getClassName()); + } + } + ); + //下面是新增方法! + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + while (true) { + try { + Looper.loop(); //会先执行这个方法,然后在执行下面的异常捕获方法! + } catch (Exception e) { + Logger.e("捕获异常主线程:", Thread.currentThread().getName() + "在:" + e.getStackTrace()[0].getClassName()); + e.printStackTrace(); + } + } + } + }); + } + + private void registerReceivers() { + registerAppChangedReceive(); + } + + @Deprecated + private void unregisterReceivers() { + if (mAppChangedReceiver != null) { + unregisterReceiver(mAppChangedReceiver); + } + } + + private AppChangedReceiver mAppChangedReceiver; + + + private void registerAppChangedReceive() { + if (null == mAppChangedReceiver) { + mAppChangedReceiver = new AppChangedReceiver(); + } + IntentFilter filter = new IntentFilter(); + filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); + filter.addAction(Intent.ACTION_PACKAGE_INSTALL); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REPLACED); + filter.addAction(Intent.ACTION_MY_PACKAGE_REPLACED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addAction(SystemIntentAction.ACTION_PACKAGE_ENABLE_ROLLBACK); + filter.addAction(SystemIntentAction.ACTION_CANCEL_ENABLE_ROLLBACK); + filter.addAction(SystemIntentAction.ACTION_ROLLBACK_COMMITTED); + filter.addDataScheme("package"); + registerReceiver(mAppChangedReceiver, filter); + + // 监听系统语言切换,刷新桌面应用名称(该广播不带 package data,需单独注册) + IntentFilter localeFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED); + registerReceiver(mAppChangedReceiver, localeFilter); + } + +} diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseService.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseService.java new file mode 100644 index 0000000..211330a --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseService.java @@ -0,0 +1,61 @@ +package com.ttstd.controlled.base; + +import android.content.Intent; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; +import androidx.lifecycle.ViewModelStore; +import androidx.lifecycle.ViewModelStoreOwner; + +import com.ttstd.controlled.base.rx.BaseRxService; + +import org.jetbrains.annotations.NotNull; + +/** + * Service 基类。 + * + * 同时实现 LifecycleOwner 与 ViewModelStoreOwner: + * - LifecycleOwner 让 LiveData.observe(this, ...) 可用; + * - ViewModelStoreOwner 让 ViewModelProvider 创建的 ViewModel 在 onDestroy + * 时收到 onCleared 回调,从而自动 dispose 其中的网络请求。 + */ +public abstract class BaseService extends BaseRxService implements LifecycleOwner, ViewModelStoreOwner { + + private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this); + private final ViewModelStore viewModelStore = new ViewModelStore(); + + @NotNull + @Override + public Lifecycle getLifecycle() { + return lifecycleRegistry; + } + + @NotNull + @Override + public ViewModelStore getViewModelStore() { + return viewModelStore; + } + + @Override + public void onCreate() { + super.onCreate(); + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); + //修补在Service中LiveData不能触发 + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + super.onDestroy(); + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY); + // 触发 ViewModel.onCleared(),取消所有在途请求 + viewModelStore.clear(); + } +} diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseViewModel.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseViewModel.java deleted file mode 100644 index 8271eb6..0000000 --- a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseViewModel.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.ttstd.controlled.base; - -import androidx.lifecycle.ViewModel; - -public class BaseViewModel extends ViewModel { - @Override - protected void onCleared() { - super.onCleared(); - } -} diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseMvvmActivity.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/mvvm/BaseMvvmActivity.java similarity index 97% rename from WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseMvvmActivity.java rename to WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/mvvm/BaseMvvmActivity.java index a1e4e2e..c994843 100644 --- a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseMvvmActivity.java +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/mvvm/BaseMvvmActivity.java @@ -1,4 +1,4 @@ -package com.ttstd.controlled.base; +package com.ttstd.controlled.base.mvvm; import android.os.Bundle; diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/mvvm/BaseViewModel.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/mvvm/BaseViewModel.java new file mode 100644 index 0000000..ae465dc --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/mvvm/BaseViewModel.java @@ -0,0 +1,57 @@ +package com.ttstd.controlled.base.mvvm; + +import androidx.lifecycle.ViewModel; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.disposables.CompositeDisposable; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.functions.Consumer; + +/** + * ViewModel 基类。 + * + * 内置 CompositeDisposable:所有网络请求通过 {@link #execute} 订阅, + * ViewModel 销毁(Activity finish / Service stop)时统一 dispose, + * 从而实现请求随生命周期自动取消,杜绝内存泄漏与野线程回调。 + */ +public class BaseViewModel extends ViewModel { + + private final CompositeDisposable disposables = new CompositeDisposable(); + + /** 注册一个 Disposable,交由本 ViewModel 生命周期托管。 */ + protected void addDisposable(Disposable disposable) { + if (disposable != null) { + disposables.add(disposable); + } + } + + /** + * 订阅一个 Single 并自动切回主线程,结果与异常都在主线程回调。 + */ + protected void execute(Single single, Consumer onSuccess, Consumer onError) { + addDisposable(single + .observeOn(io.reactivex.rxjava3.android.schedulers.AndroidSchedulers.mainThread()) + .subscribe(onSuccess, onError)); + } + + /** + * 订阅一个 Observable 并自动切回主线程。 + */ + protected void execute(Observable observable, Consumer onNext, Consumer onError) { + addDisposable(observable + .observeOn(io.reactivex.rxjava3.android.schedulers.AndroidSchedulers.mainThread()) + .subscribe(onNext, onError)); + } + + /** 主动清空当前所有订阅(不影响后续再次订阅)。 */ + protected void clearDisposables() { + disposables.clear(); + } + + @Override + protected void onCleared() { + disposables.clear(); + super.onCleared(); + } +} diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxActivity.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxActivity.java new file mode 100644 index 0000000..f81a922 --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxActivity.java @@ -0,0 +1,94 @@ +package com.ttstd.controlled.base.rx; + +import android.os.Bundle; + +import androidx.annotation.CallSuper; +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * {@link com.trello.rxlifecycle4.components.RxActivity} + * copied form RxActivity} + */ +public abstract class BaseRxActivity extends AppCompatActivity implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull ActivityEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindActivity(lifecycleSubject); + } + + @Override + @CallSuper + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lifecycleSubject.onNext(ActivityEvent.CREATE); + } + + @Override + @CallSuper + protected void onStart() { + super.onStart(); + lifecycleSubject.onNext(ActivityEvent.START); + } + + @Override + @CallSuper + protected void onResume() { + super.onResume(); + lifecycleSubject.onNext(ActivityEvent.RESUME); + } + + @Override + @CallSuper + protected void onPause() { + lifecycleSubject.onNext(ActivityEvent.PAUSE); + super.onPause(); + } + + @Override + @CallSuper + protected void onStop() { + lifecycleSubject.onNext(ActivityEvent.STOP); + super.onStop(); + } + + @Override + @CallSuper + protected void onDestroy() { + lifecycleSubject.onNext(ActivityEvent.DESTROY); + super.onDestroy(); + } +} + diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxDialogFragment.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxDialogFragment.java new file mode 100644 index 0000000..30f52fa --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxDialogFragment.java @@ -0,0 +1,123 @@ +package com.ttstd.controlled.base.rx; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.CallSuper; +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.FragmentEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * {@link com.trello.rxlifecycle4.components.RxFragment} + * copied form RxFragment} + */ +public class BaseRxDialogFragment extends DialogFragment implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull FragmentEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindFragment(lifecycleSubject); + } + + @Override + @CallSuper + public void onAttach(android.app.Activity activity) { + super.onAttach(activity); + lifecycleSubject.onNext(FragmentEvent.ATTACH); + } + + @Override + @CallSuper + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE); + } + + @Override + @CallSuper + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW); + } + + @Override + @CallSuper + public void onStart() { + super.onStart(); + lifecycleSubject.onNext(FragmentEvent.START); + } + + @Override + @CallSuper + public void onResume() { + super.onResume(); + lifecycleSubject.onNext(FragmentEvent.RESUME); + } + + @Override + @CallSuper + public void onPause() { + lifecycleSubject.onNext(FragmentEvent.PAUSE); + super.onPause(); + } + + @Override + @CallSuper + public void onStop() { + lifecycleSubject.onNext(FragmentEvent.STOP); + super.onStop(); + } + + @Override + @CallSuper + public void onDestroyView() { + lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW); + super.onDestroyView(); + } + + @Override + @CallSuper + public void onDestroy() { + lifecycleSubject.onNext(FragmentEvent.DESTROY); + super.onDestroy(); + } + + @Override + @CallSuper + public void onDetach() { + lifecycleSubject.onNext(FragmentEvent.DETACH); + super.onDetach(); + } +} + diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxFragment.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxFragment.java new file mode 100644 index 0000000..3033438 --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxFragment.java @@ -0,0 +1,123 @@ +package com.ttstd.controlled.base.rx; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.CallSuper; +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.FragmentEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * {@link com.trello.rxlifecycle4.components.RxFragment} + * copied form RxFragment} + */ +public class BaseRxFragment extends Fragment implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull FragmentEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindFragment(lifecycleSubject); + } + + @Override + @CallSuper + public void onAttach(android.app.Activity activity) { + super.onAttach(activity); + lifecycleSubject.onNext(FragmentEvent.ATTACH); + } + + @Override + @CallSuper + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE); + } + + @Override + @CallSuper + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW); + } + + @Override + @CallSuper + public void onStart() { + super.onStart(); + lifecycleSubject.onNext(FragmentEvent.START); + } + + @Override + @CallSuper + public void onResume() { + super.onResume(); + lifecycleSubject.onNext(FragmentEvent.RESUME); + } + + @Override + @CallSuper + public void onPause() { + lifecycleSubject.onNext(FragmentEvent.PAUSE); + super.onPause(); + } + + @Override + @CallSuper + public void onStop() { + lifecycleSubject.onNext(FragmentEvent.STOP); + super.onStop(); + } + + @Override + @CallSuper + public void onDestroyView() { + lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW); + super.onDestroyView(); + } + + @Override + @CallSuper + public void onDestroy() { + lifecycleSubject.onNext(FragmentEvent.DESTROY); + super.onDestroy(); + } + + @Override + @CallSuper + public void onDetach() { + lifecycleSubject.onNext(FragmentEvent.DETACH); + super.onDetach(); + } +} + diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxService.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxService.java new file mode 100644 index 0000000..72a65f9 --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/rx/BaseRxService.java @@ -0,0 +1,56 @@ +package com.ttstd.controlled.base.rx; + +import android.app.Service; + +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +public abstract class BaseRxService extends Service implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull ActivityEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindActivity(lifecycleSubject); + } + + @Override + public void onCreate() { + super.onCreate(); + lifecycleSubject.onNext(ActivityEvent.CREATE); + } + + @Override + public void onDestroy() { + super.onDestroy(); + lifecycleSubject.onNext(ActivityEvent.DESTROY); + } +} \ No newline at end of file diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/config/CommonConfig.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/config/CommonConfig.java new file mode 100644 index 0000000..cdd1474 --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/config/CommonConfig.java @@ -0,0 +1,6 @@ +package com.ttstd.controlled.config; + +public class CommonConfig { + public static final String MMKV_ID = "InterProcessKV"; + +} diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureModel.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureModel.java new file mode 100644 index 0000000..cf55b96 --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureModel.java @@ -0,0 +1,60 @@ +package com.ttstd.controlled.service; + +import android.util.Log; + +import androidx.lifecycle.ViewModel; + +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.ttstd.dialer.bean.BaseResponse; +import com.ttstd.dialer.bean.req.SnLocationReq; +import com.ttstd.dialer.network.BaseObserver; +import com.ttstd.dialer.network.OkHttpManager; + +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +public class ScreenCaptureModel extends ViewModel { + private static final String TAG = "MainServiceModel"; + + private BehaviorSubject lifecycleSubject; + + // 设置Service生命周期Subject + public void setLifecycleSubject(BehaviorSubject lifecycleSubject) { + this.lifecycleSubject = lifecycleSubject; + } + + // 绑定请求到Service销毁事件(自动取消请求) + private LifecycleTransformer bindToLifecycle() { + if (lifecycleSubject == null) { + throw new IllegalStateException("请先设置LifecycleSubject!"); + } + return RxLifecycle.bindUntilEvent(lifecycleSubject, ActivityEvent.DESTROY); + } + + @Override + protected void onCleared() { + super.onCleared(); + // 清空生命周期引用,防止内存泄漏 + this.lifecycleSubject = null; + } + + + public void uploadLocation(SnLocationReq locationReq) { + Log.e(TAG, "uploadLocation: "); + OkHttpManager.getInstance().getUploadLocationObservable(locationReq) + .compose(bindToLifecycle()) + .subscribe(new BaseObserver() { + @Override + public void onSuccess(BaseResponse baseResponse) { + Log.e("uploadLocation", "onSuccess: " + baseResponse); + } + + @Override + public void onFailure(Throwable e) { + Log.e("uploadLocation", "onFailure: " + e.getMessage()); + } + }); + + } +} diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/MainActivity.java b/WebRTCController/app/src/main/java/com/ttstd/controller/activity/main/MainActivity.java similarity index 99% rename from WebRTCController/app/src/main/java/com/ttstd/controller/MainActivity.java rename to WebRTCController/app/src/main/java/com/ttstd/controller/activity/main/MainActivity.java index 8e87246..0292401 100644 --- a/WebRTCController/app/src/main/java/com/ttstd/controller/MainActivity.java +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/activity/main/MainActivity.java @@ -1,4 +1,4 @@ -package com.ttstd.controller; +package com.ttstd.controller.activity.main; import android.Manifest; import android.content.pm.PackageManager; @@ -14,7 +14,6 @@ import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; -import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Spinner; @@ -38,6 +37,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.ttstd.control.Action; import com.ttstd.control.ControlMessage; +import com.ttstd.controller.R; import com.ttstd.controller.signaling.ApiClient; import com.ttstd.controller.signaling.SignalMessage; import com.ttstd.controller.signaling.WebSocketClient; @@ -52,8 +52,6 @@ import org.webrtc.IceCandidate; import org.webrtc.RendererCommon; import org.webrtc.SurfaceViewRenderer; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.Executors; @@ -156,7 +154,7 @@ public class MainActivity extends AppCompatActivity { btnDisconnectControl = findViewById(R.id.btn_disconnect_control); // 默认服务器地址 - etServerUrl.setText("wss://www.ttstd.com/signal"); + etServerUrl.setText("ws://192.168.5.224:8080/ws/signal"); // 设备ID 由服务端注册后下发(REGISTER_SUCCESS.fromDeviceId),用户无需填写。 etDeviceId.setEnabled(false); etDeviceId.setHint("连接后由服务端下发"); diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/activity/main/MainViewModel.java b/WebRTCController/app/src/main/java/com/ttstd/controller/activity/main/MainViewModel.java new file mode 100644 index 0000000..09545a4 --- /dev/null +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/activity/main/MainViewModel.java @@ -0,0 +1,6 @@ +package com.ttstd.controlled.activity.main; + +import com.ttstd.controlled.base.mvvm.BaseViewModel; + +public class MainViewModel extends BaseViewModel { +} diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/base/BaseApplication.java b/WebRTCController/app/src/main/java/com/ttstd/controller/base/BaseApplication.java new file mode 100644 index 0000000..c687027 --- /dev/null +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/base/BaseApplication.java @@ -0,0 +1,61 @@ +package com.ttstd.controller.base; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.Context; +import android.util.Log; + +import androidx.multidex.MultiDex; + +import com.tencent.mmkv.MMKV; + +public class BaseApplication extends Application { + private static final String TAG = "BaseApplication"; + + /** + * ViewModel中因为经常旋转导致弱引用为空 + */ + @SuppressLint("StaticFieldLeak") + private static Context mAppContext; + + public static Context getContext() { + return mAppContext; + } + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + MultiDex.install(this); + } + + @Override + public void onCreate() { + super.onCreate(); + Log.e(TAG, "onCreate: "); + mAppContext = getApplicationContext(); + + init(); + } + + @Override + public void onTerminate() { + super.onTerminate(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + } + + private void init() { + Log.e(TAG, "init: "); + String rootDir = MMKV.initialize(this); + Log.e(TAG, "mmkv root: " + rootDir); + } + +} diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/base/BaseService.java b/WebRTCController/app/src/main/java/com/ttstd/controller/base/BaseService.java new file mode 100644 index 0000000..80a527d --- /dev/null +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/base/BaseService.java @@ -0,0 +1,61 @@ +package com.ttstd.controller.base; + +import android.content.Intent; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; +import androidx.lifecycle.ViewModelStore; +import androidx.lifecycle.ViewModelStoreOwner; + +import com.ttstd.controlled.base.rx.BaseRxService; + +import org.jetbrains.annotations.NotNull; + +/** + * Service 基类。 + * + * 同时实现 LifecycleOwner 与 ViewModelStoreOwner: + * - LifecycleOwner 让 LiveData.observe(this, ...) 可用; + * - ViewModelStoreOwner 让 ViewModelProvider 创建的 ViewModel 在 onDestroy + * 时收到 onCleared 回调,从而自动 dispose 其中的网络请求。 + */ +public abstract class BaseService extends BaseRxService implements LifecycleOwner, ViewModelStoreOwner { + + private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this); + private final ViewModelStore viewModelStore = new ViewModelStore(); + + @NotNull + @Override + public Lifecycle getLifecycle() { + return lifecycleRegistry; + } + + @NotNull + @Override + public ViewModelStore getViewModelStore() { + return viewModelStore; + } + + @Override + public void onCreate() { + super.onCreate(); + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); + //修补在Service中LiveData不能触发 + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + super.onDestroy(); + lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY); + // 触发 ViewModel.onCleared(),取消所有在途请求 + viewModelStore.clear(); + } +} diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/base/mvvm/BaseMvvmActivity.java b/WebRTCController/app/src/main/java/com/ttstd/controller/base/mvvm/BaseMvvmActivity.java new file mode 100644 index 0000000..4a0f67c --- /dev/null +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/base/mvvm/BaseMvvmActivity.java @@ -0,0 +1,45 @@ +package com.ttstd.controller.base.mvvm; + +import android.os.Bundle; + +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; +import androidx.lifecycle.ViewModelProvider; + +import java.lang.reflect.ParameterizedType; + +public abstract class BaseMvvmActivity extends AppCompatActivity { + + protected VM viewModel; + protected DB binding; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = DataBindingUtil.setContentView(this, getLayoutId()); + binding.setLifecycleOwner(this); + + initViewModel(); + initView(); + initData(); + } + + @LayoutRes + protected abstract int getLayoutId(); + + protected abstract void initView(); + + protected abstract void initData(); + + @SuppressWarnings("unchecked") + private void initViewModel() { + ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); + if (type != null) { + Class viewModelClass = (Class) type.getActualTypeArguments()[0]; + viewModel = new ViewModelProvider(this).get(viewModelClass); + } + } +} diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/base/mvvm/BaseViewModel.java b/WebRTCController/app/src/main/java/com/ttstd/controller/base/mvvm/BaseViewModel.java new file mode 100644 index 0000000..e935a13 --- /dev/null +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/base/mvvm/BaseViewModel.java @@ -0,0 +1,57 @@ +package com.ttstd.controller.base.mvvm; + +import androidx.lifecycle.ViewModel; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.disposables.CompositeDisposable; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.functions.Consumer; + +/** + * ViewModel 基类。 + * + * 内置 CompositeDisposable:所有网络请求通过 {@link #execute} 订阅, + * ViewModel 销毁(Activity finish / Service stop)时统一 dispose, + * 从而实现请求随生命周期自动取消,杜绝内存泄漏与野线程回调。 + */ +public class BaseViewModel extends ViewModel { + + private final CompositeDisposable disposables = new CompositeDisposable(); + + /** 注册一个 Disposable,交由本 ViewModel 生命周期托管。 */ + protected void addDisposable(Disposable disposable) { + if (disposable != null) { + disposables.add(disposable); + } + } + + /** + * 订阅一个 Single 并自动切回主线程,结果与异常都在主线程回调。 + */ + protected void execute(Single single, Consumer onSuccess, Consumer onError) { + addDisposable(single + .observeOn(io.reactivex.rxjava3.android.schedulers.AndroidSchedulers.mainThread()) + .subscribe(onSuccess, onError)); + } + + /** + * 订阅一个 Observable 并自动切回主线程。 + */ + protected void execute(Observable observable, Consumer onNext, Consumer onError) { + addDisposable(observable + .observeOn(io.reactivex.rxjava3.android.schedulers.AndroidSchedulers.mainThread()) + .subscribe(onNext, onError)); + } + + /** 主动清空当前所有订阅(不影响后续再次订阅)。 */ + protected void clearDisposables() { + disposables.clear(); + } + + @Override + protected void onCleared() { + disposables.clear(); + super.onCleared(); + } +} diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxActivity.java b/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxActivity.java new file mode 100644 index 0000000..450d458 --- /dev/null +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxActivity.java @@ -0,0 +1,94 @@ +package com.ttstd.controller.base.rx; + +import android.os.Bundle; + +import androidx.annotation.CallSuper; +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * {@link com.trello.rxlifecycle4.components.RxActivity} + * copied form RxActivity} + */ +public abstract class BaseRxActivity extends AppCompatActivity implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull ActivityEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindActivity(lifecycleSubject); + } + + @Override + @CallSuper + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lifecycleSubject.onNext(ActivityEvent.CREATE); + } + + @Override + @CallSuper + protected void onStart() { + super.onStart(); + lifecycleSubject.onNext(ActivityEvent.START); + } + + @Override + @CallSuper + protected void onResume() { + super.onResume(); + lifecycleSubject.onNext(ActivityEvent.RESUME); + } + + @Override + @CallSuper + protected void onPause() { + lifecycleSubject.onNext(ActivityEvent.PAUSE); + super.onPause(); + } + + @Override + @CallSuper + protected void onStop() { + lifecycleSubject.onNext(ActivityEvent.STOP); + super.onStop(); + } + + @Override + @CallSuper + protected void onDestroy() { + lifecycleSubject.onNext(ActivityEvent.DESTROY); + super.onDestroy(); + } +} + diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxDialogFragment.java b/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxDialogFragment.java new file mode 100644 index 0000000..5f5a057 --- /dev/null +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxDialogFragment.java @@ -0,0 +1,123 @@ +package com.ttstd.controller.base.rx; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.CallSuper; +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.FragmentEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * {@link com.trello.rxlifecycle4.components.RxFragment} + * copied form RxFragment} + */ +public class BaseRxDialogFragment extends DialogFragment implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull FragmentEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindFragment(lifecycleSubject); + } + + @Override + @CallSuper + public void onAttach(android.app.Activity activity) { + super.onAttach(activity); + lifecycleSubject.onNext(FragmentEvent.ATTACH); + } + + @Override + @CallSuper + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE); + } + + @Override + @CallSuper + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW); + } + + @Override + @CallSuper + public void onStart() { + super.onStart(); + lifecycleSubject.onNext(FragmentEvent.START); + } + + @Override + @CallSuper + public void onResume() { + super.onResume(); + lifecycleSubject.onNext(FragmentEvent.RESUME); + } + + @Override + @CallSuper + public void onPause() { + lifecycleSubject.onNext(FragmentEvent.PAUSE); + super.onPause(); + } + + @Override + @CallSuper + public void onStop() { + lifecycleSubject.onNext(FragmentEvent.STOP); + super.onStop(); + } + + @Override + @CallSuper + public void onDestroyView() { + lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW); + super.onDestroyView(); + } + + @Override + @CallSuper + public void onDestroy() { + lifecycleSubject.onNext(FragmentEvent.DESTROY); + super.onDestroy(); + } + + @Override + @CallSuper + public void onDetach() { + lifecycleSubject.onNext(FragmentEvent.DETACH); + super.onDetach(); + } +} + diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxFragment.java b/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxFragment.java new file mode 100644 index 0000000..5abc11e --- /dev/null +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxFragment.java @@ -0,0 +1,123 @@ +package com.ttstd.controller.base.rx; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.CallSuper; +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.FragmentEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * {@link com.trello.rxlifecycle4.components.RxFragment} + * copied form RxFragment} + */ +public class BaseRxFragment extends Fragment implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull FragmentEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindFragment(lifecycleSubject); + } + + @Override + @CallSuper + public void onAttach(android.app.Activity activity) { + super.onAttach(activity); + lifecycleSubject.onNext(FragmentEvent.ATTACH); + } + + @Override + @CallSuper + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE); + } + + @Override + @CallSuper + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW); + } + + @Override + @CallSuper + public void onStart() { + super.onStart(); + lifecycleSubject.onNext(FragmentEvent.START); + } + + @Override + @CallSuper + public void onResume() { + super.onResume(); + lifecycleSubject.onNext(FragmentEvent.RESUME); + } + + @Override + @CallSuper + public void onPause() { + lifecycleSubject.onNext(FragmentEvent.PAUSE); + super.onPause(); + } + + @Override + @CallSuper + public void onStop() { + lifecycleSubject.onNext(FragmentEvent.STOP); + super.onStop(); + } + + @Override + @CallSuper + public void onDestroyView() { + lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW); + super.onDestroyView(); + } + + @Override + @CallSuper + public void onDestroy() { + lifecycleSubject.onNext(FragmentEvent.DESTROY); + super.onDestroy(); + } + + @Override + @CallSuper + public void onDetach() { + lifecycleSubject.onNext(FragmentEvent.DETACH); + super.onDetach(); + } +} + diff --git a/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxService.java b/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxService.java new file mode 100644 index 0000000..5bc827f --- /dev/null +++ b/WebRTCController/app/src/main/java/com/ttstd/controller/base/rx/BaseRxService.java @@ -0,0 +1,56 @@ +package com.ttstd.controller.base.rx; + +import android.app.Service; + +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +public abstract class BaseRxService extends Service implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull ActivityEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindActivity(lifecycleSubject); + } + + @Override + public void onCreate() { + super.onCreate(); + lifecycleSubject.onNext(ActivityEvent.CREATE); + } + + @Override + public void onDestroy() { + super.onDestroy(); + lifecycleSubject.onNext(ActivityEvent.DESTROY); + } +} \ No newline at end of file