From 5c279d1ba69fae34d196c83c906b4cffce987c02 Mon Sep 17 00:00:00 2001 From: tongtongstudio Date: Tue, 14 Jul 2026 17:26:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=B9=E4=B8=BAMVVM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/main/AndroidManifest.xml | 2 +- .../{ => activity/main}/MainActivity.java | 80 +++++------ .../activity/main/MainViewModel.java | 6 + .../controlled/base/BaseMvvmActivity.java | 45 ++++++ .../ttstd/controlled/base/BaseViewModel.java | 10 ++ .../service/ScreenCaptureService.java | 2 +- .../app/src/main/res/layout/activity_main.xml | 136 +++++++++--------- 7 files changed, 169 insertions(+), 112 deletions(-) rename WebRTCControlled/app/src/main/java/com/ttstd/controlled/{ => activity/main}/MainActivity.java (73%) create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainViewModel.java create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseMvvmActivity.java create mode 100644 WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseViewModel.java diff --git a/WebRTCControlled/app/src/main/AndroidManifest.xml b/WebRTCControlled/app/src/main/AndroidManifest.xml index 2988b38..bc41e29 100644 --- a/WebRTCControlled/app/src/main/AndroidManifest.xml +++ b/WebRTCControlled/app/src/main/AndroidManifest.xml @@ -17,7 +17,7 @@ android:theme="@style/Theme.MaterialComponents.DayNight"> diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/MainActivity.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainActivity.java similarity index 73% rename from WebRTCControlled/app/src/main/java/com/ttstd/controlled/MainActivity.java rename to WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainActivity.java index bd1c2bf..a2ca738 100644 --- a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/MainActivity.java +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainActivity.java @@ -1,4 +1,4 @@ -package com.ttstd.controlled; +package com.ttstd.controlled.activity.main; import android.Manifest; import android.content.ComponentName; @@ -8,39 +8,29 @@ import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.media.projection.MediaProjectionManager; import android.os.Build; -import android.os.Bundle; import android.os.IBinder; import android.util.Log; -import android.widget.Button; -import android.widget.EditText; -import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; +import com.ttstd.controlled.R; +import com.ttstd.controlled.base.BaseMvvmActivity; +import com.ttstd.controlled.databinding.ActivityMainBinding; import com.ttstd.controlled.service.ScreenCaptureService; import com.ttstd.controlled.webrtc.WebRtcClient; import org.webrtc.RendererCommon; -import org.webrtc.SurfaceViewRenderer; -public class MainActivity extends AppCompatActivity { +public class MainActivity extends BaseMvvmActivity { private static final String TAG = "ControlledMain"; private static final int REQUEST_MEDIA_PROJECTION = 1001; private static final int REQUEST_NOTIFICATION_PERMISSION = 1002; - private EditText etServerUrl; - private EditText etDeviceId; - private Button btnStart; - private Button btnStop; - private TextView tvStatus; - private SurfaceViewRenderer localView; - private boolean isServiceRunning = false; private ScreenCaptureService screenCaptureService; private boolean isBound = false; @@ -63,28 +53,28 @@ public class MainActivity extends AppCompatActivity { }; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - etServerUrl = findViewById(R.id.et_server_url); - etDeviceId = findViewById(R.id.et_device_id); - btnStart = findViewById(R.id.btn_start); - btnStop = findViewById(R.id.btn_stop); - tvStatus = findViewById(R.id.tv_status); - localView = findViewById(R.id.local_view); + protected int getLayoutId() { + return R.layout.activity_main; + } + @Override + protected void initView() { // 默认服务器地址 - etServerUrl.setText("ws://175.178.213.60:8088/ws/signal"); + binding.etServerUrl.setText("ws://175.178.213.60:8088/ws/signal"); // 生成设备ID -// etDeviceId.setText("controlled_" + UUID.randomUUID().toString().substring(0, 8)); +// binding.etDeviceId.setText("controlled_" + UUID.randomUUID().toString().substring(0, 8)); - btnStart.setOnClickListener(v -> startScreenSharing()); - btnStop.setOnClickListener(v -> stopScreenSharing()); + binding.btnStart.setOnClickListener(v -> startScreenSharing()); + binding.btnStop.setOnClickListener(v -> stopScreenSharing()); updateUI(false); } + @Override + protected void initData() { + // Initialization logic if any + } + private void startScreenSharing() { // 检查通知权限 (Android 13+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { @@ -112,8 +102,8 @@ public class MainActivity extends AppCompatActivity { Intent serviceIntent = new Intent(this, ScreenCaptureService.class); serviceIntent.putExtra(ScreenCaptureService.EXTRA_RESULT_CODE, resultCode); serviceIntent.putExtra(ScreenCaptureService.EXTRA_RESULT_DATA, data); - serviceIntent.putExtra(ScreenCaptureService.EXTRA_SERVER_URL, etServerUrl.getText().toString()); - serviceIntent.putExtra(ScreenCaptureService.EXTRA_DEVICE_ID, etDeviceId.getText().toString()); + serviceIntent.putExtra(ScreenCaptureService.EXTRA_SERVER_URL, binding.etServerUrl.getText().toString()); + serviceIntent.putExtra(ScreenCaptureService.EXTRA_DEVICE_ID, binding.etDeviceId.getText().toString()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); @@ -150,8 +140,8 @@ public class MainActivity extends AppCompatActivity { } Intent serviceIntent = new Intent(this, ScreenCaptureService.class); stopService(serviceIntent); - if (localView != null) { - localView.release(); + if (binding.localView != null) { + binding.localView.release(); isLocalViewInitialized = false; } updateUI(false); @@ -163,17 +153,17 @@ public class MainActivity extends AppCompatActivity { WebRtcClient webRtcClient = screenCaptureService.getWebRtcClient(); if (webRtcClient != null && webRtcClient.getEglContext() != null) { try { - localView.init(webRtcClient.getEglContext(), null); - localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); - localView.setMirror(false); - webRtcClient.setLocalSink(localView); + binding.localView.init(webRtcClient.getEglContext(), null); + binding.localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); + binding.localView.setMirror(false); + webRtcClient.setLocalSink(binding.localView); isLocalViewInitialized = true; } catch (Exception e) { Log.e(TAG, "Error initializing local view", e); } } else { // 如果 webRtcClient 还没准备好,稍后重试 - localView.postDelayed(this::setupLocalPreview, 500); + binding.localView.postDelayed(this::setupLocalPreview, 500); } } } @@ -185,18 +175,18 @@ public class MainActivity extends AppCompatActivity { unbindService(serviceConnection); isBound = false; } - if (localView != null) { - localView.release(); + if (binding != null && binding.localView != null) { + binding.localView.release(); isLocalViewInitialized = false; } } private void updateUI(boolean running) { isServiceRunning = running; - btnStart.setEnabled(!running); - btnStop.setEnabled(running); - etServerUrl.setEnabled(!running); - etDeviceId.setEnabled(!running); - tvStatus.setText(running ? "状态: 运行中" : "状态: 已停止"); + binding.btnStart.setEnabled(!running); + binding.btnStop.setEnabled(running); + binding.etServerUrl.setEnabled(!running); + binding.etDeviceId.setEnabled(!running); + binding.tvStatus.setText(running ? "状态: 运行中" : "状态: 已停止"); } } diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainViewModel.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainViewModel.java new file mode 100644 index 0000000..f5baa29 --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/activity/main/MainViewModel.java @@ -0,0 +1,6 @@ +package com.ttstd.controlled.activity.main; + +import com.ttstd.controlled.base.BaseViewModel; + +public class MainViewModel extends BaseViewModel { +} diff --git a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseMvvmActivity.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseMvvmActivity.java new file mode 100644 index 0000000..a1e4e2e --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseMvvmActivity.java @@ -0,0 +1,45 @@ +package com.ttstd.controlled.base; + +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/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseViewModel.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseViewModel.java new file mode 100644 index 0000000..8271eb6 --- /dev/null +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/base/BaseViewModel.java @@ -0,0 +1,10 @@ +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/service/ScreenCaptureService.java b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureService.java index 5e73b14..dadbd3b 100644 --- a/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureService.java +++ b/WebRTCControlled/app/src/main/java/com/ttstd/controlled/service/ScreenCaptureService.java @@ -21,7 +21,7 @@ import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; -import com.ttstd.controlled.MainActivity; +import com.ttstd.controlled.activity.main.MainActivity; import com.ttstd.controlled.input.InputCommandHandler; import com.ttstd.controlled.signaling.SignalMessage; import com.ttstd.controlled.signaling.WebSocketClient; diff --git a/WebRTCControlled/app/src/main/res/layout/activity_main.xml b/WebRTCControlled/app/src/main/res/layout/activity_main.xml index c9fe8c7..a1e3f1c 100644 --- a/WebRTCControlled/app/src/main/res/layout/activity_main.xml +++ b/WebRTCControlled/app/src/main/res/layout/activity_main.xml @@ -1,75 +1,81 @@ - + - - - - - + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="24dp"> - + - + - + -