什么网站免费购物商城,塑胶加工东莞网站建设技术支持,做礼品公司网站的费用,后台网站设计1. 背景与目标 (Background and Goal)
背景: 我们要创建一个用户登录界面。用户输入用户名和密码#xff0c;点击“登录”按钮。应用会显示一个加载中的“圈圈”#xff08;ProgressBar#xff09;#xff0c;然后模拟一个耗时2秒的网络请求。根据请求结果#xff0c;界面…1. 背景与目标 (Background and Goal)
背景: 我们要创建一个用户登录界面。用户输入用户名和密码点击“登录”按钮。应用会显示一个加载中的“圈圈”ProgressBar然后模拟一个耗时2秒的网络请求。根据请求结果界面会显示“登录成功”或“登录失败”的消息。
核心挑战:
在等待网络响应的2秒内如果用户旋转屏幕应用不能崩溃加载状态不能丢失“圈圈”必须继续转用户输入的内容也不能丢失。整个应用的组件网络服务、数据仓库、ViewModel等需要被优雅地组织和管理而不是在Activity里手动创建一大堆对象。
我们的目标: 通过这个例子你将看到
Hilt 如何像一个总管家自动创建并“注入”所有需要的对象。Repository 和 ApiService 如何使用**回调Callback**来处理异步的网络请求。ViewModel 如何作为UI的“大脑”管理所有UI状态加载状态、错误信息、用户输入并轻松应对屏幕旋转保证数据和状态不丢失。Activity 如何变得非常“轻量”只负责展示 ViewModel 提供的数据和发送用户指令。 2. 登场角色与职责
AuthCallback (接口): “汇报合同”。定义了登录任务的结果必须如何汇报成功或失败。AuthApiService (模拟的网络服务): “远程服务器接口人”。负责执行真正的模拟的登录网络请求并在完成后通过 AuthCallback 汇报结果。AuthRepository (数据仓库): “业务逻辑层”。作为 ViewModel 和数据源之间的中间人它负责调用 AuthApiService。LoginViewModel (UI的“大脑”): “状态管理器”。持有所有UI需要的数据和状态加载中成功/失败信息处理用户的登录请求并在屏幕旋转后存活下来。LoginActivity (UI界面): “视图展示层”。一个“傻瓜”界面只负责显示 LoginViewModel 给它的数据和告诉 LoginViewModel “用户点击了登录按钮”。
数据流向:
指令流: Activity - ViewModel - Repository - ApiService结果流: ApiService --(Callback)– Repository --(Callback)– ViewModel --(LiveData)– Activity 3. 代码实现一步步构建
第1步定义“合同”和“网络工人”
AuthCallback.java
public interface AuthCallback {void onSuccess(String successMessage);void onFailure(String errorMessage);
}AuthApiService.java
// 这个类模拟与远程服务器的通信
Singleton // 整个应用共享一个实例
public class AuthApiService {Inject // Hilt知道如何创建它public AuthApiService() {}// 模拟登录这是一个异步操作public void login(String username, String password, AuthCallback callback) {System.out.println(【API服务】: 开始向服务器发送登录请求...);// 用Handler模拟2秒的网络延迟new Handler(Looper.getMainLooper()).postDelayed(() - {if (username.equals(admin) password.equals(123456)) {// 登录成功通过callback通知调用者System.out.println(【API服务】: 服务器响应登录成功);callback.onSuccess(欢迎回来, username);} else {// 登录失败通过callback通知调用者System.out.println(【API服务】: 服务器响应用户名或密码错误);callback.onFailure(用户名或密码错误);}}, 2000);}
}第2步创建“业务逻辑层”
AuthRepository.java
Singleton
public class AuthRepository {private final AuthApiService apiService;Injectpublic AuthRepository(AuthApiService apiService) {this.apiService apiService;}// Repository的方法它接收ViewModel的指令并把callback传递给下一层public void login(String username, String password, AuthCallback callback) {System.out.println(【仓库层】: 收到登录请求正在转交给API服务...);apiService.login(username, password, callback);}
}第3步创建 Hilt 的“制造手册”
di/module/AppModule.java
Module
InstallIn(SingletonComponent.class)
public class AppModule {// 因为 AuthApiService 和 AuthRepository 的构造函数都被Inject标记了// Hilt可以自动创建它们所以这个Module暂时可以是空的。// 如果它们来自第三方库我们就在这里写 Provides 方法。
}讲解在这个例子中因为我们的类构造函数很简单都用了 Inject所以 Hilt 可以自动处理。但保留这个文件是好的实践未来可以用来提供 Room, Retrofit 等复杂对象。
第4. 创建 UI 的“大脑” (ViewModel)
LoginViewModel.java
HiltViewModel // 1. 标记为Hilt管理的ViewModel
public class LoginViewModel extends ViewModel {private final AuthRepository authRepository;// 2. 定义UI所需的所有状态并用LiveData包裹private final MutableLiveDataBoolean _isLoading new MutableLiveData(false);public final LiveDataBoolean isLoading _isLoading;private final MutableLiveDataString _loginResult new MutableLiveData();public final LiveDataString loginResult _loginResult;Inject // 3. Hilt会自动注入AuthRepositorypublic LoginViewModel(AuthRepository authRepository) {this.authRepository authRepository;}// 4. 定义一个方法供UI层调用以触发登录逻辑public void onLoginClicked(String username, String password) {System.out.println(【ViewModel】: 收到UI的登录点击事件);_isLoading.setValue(true); // 更新状态为“正在加载”// 5. 调用Repository并提供一个匿名的Callback实现来处理结果authRepository.login(username, password, new AuthCallback() {Overridepublic void onSuccess(String successMessage) {System.out.println(【ViewModel】: 收到成功回调正在更新UI状态...);_loginResult.postValue(successMessage);_isLoading.postValue(false); // 更新状态为“加载结束”}Overridepublic void onFailure(String errorMessage) {System.out.println(【ViewModel】: 收到失败回调正在更新UI状态...);_loginResult.postValue(errorMessage);_isLoading.postValue(false); // 更新状态为“加载结束”}});}
}第5步创建“轻量”的 UI 界面
activity_login.xml (布局文件)
LinearLayout ...EditText android:idid/username_input ... /EditText android:idid/password_input ... /Button android:idid/login_button android:text登录 ... /ProgressBar android:idid/loading_spinner android:visibilitygone ... /
/LinearLayoutLoginActivity.java
AndroidEntryPoint
public class LoginActivity extends AppCompatActivity {private LoginViewModel viewModel;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);// 用标准方式获取Hilt准备好的ViewModelviewModel new ViewModelProvider(this).get(LoginViewModel.class);EditText usernameInput findViewById(R.id.username_input);EditText passwordInput findViewById(R.id.password_input);Button loginButton findViewById(R.id.login_button);ProgressBar loadingSpinner findViewById(R.id.loading_spinner);// --- UI 操作只负责通知 ViewModel ---loginButton.setOnClickListener(v - {String username usernameInput.getText().toString();String password passwordInput.getText().toString();viewModel.onLoginClicked(username, password);});// --- UI 观察只负责根据 ViewModel 的数据更新自己 ---viewModel.isLoading.observe(this, isLoading - {System.out.println(【Activity】: 观察到isLoading状态变为 isLoading);loadingSpinner.setVisibility(isLoading ? View.VISIBLE : View.GONE);loginButton.setEnabled(!isLoading);});viewModel.loginResult.observe(this, resultMessage - {System.out.println(【Activity】: 观察到loginResult变化: resultMessage);Toast.makeText(this, resultMessage, Toast.LENGTH_SHORT).show();});}
}4. 运行与分析屏幕旋转的考验
输入正确的用户名(“admin”)和密码(“123456”)点击登录。 日志会显示指令从 Activity - ViewModel - Repository - ApiService 传递。UI上登录按钮会变灰加载“圈圈”开始旋转。 在2秒的等待时间内立刻旋转手机屏幕 LoginActivity 被销毁并重建。但 LoginViewModel 还活着它的 _isLoading 状态依然是 true。新的 LoginActivity 创建后重新获取到同一个 ViewModel 实例。viewModel.isLoading.observe(...) 被重新设置它立刻收到了当前的 true 值所以加载“圈圈”依然在旋转按钮依然是灰色。UI状态完美恢复 2秒结束后… AuthApiService 的回调被触发最终调用到 ViewModel 里的 onSuccess。ViewModel 调用 _isLoading.postValue(false) 和 _loginResult.postValue(欢迎回来...)。即使是在新的 Activity 实例中它的 Observer 也能立刻收到这两个更新。UI上加载“圈圈”消失按钮恢复并弹出一个“登录成功”的 Toast。
结论在这个例子中Hilt 负责组装Callback 负责异步通信ViewModel 负责状态保持。三者结合构成了一套非常强大、健壮、且易于测试的现代安卓应用架构轻松解决了异步操作和屏幕旋转带来的各种难题。