gpt4 book ai didi

android - 如何在 Android Studio 的登录 Activity 模板中实现 AsyncTask

转载 作者:行者123 更新时间:2023-11-29 02:20:53 25 4
gpt4 key购买 nike

我想在我的 Android 应用程序中实现一个登录 Activity ,我使用 Android Studio 模板进行登录 Activity 。根据这里的谷歌文档:https://developer.android.com/studio/projects/templates#LoginActivity它应该包含一个 AsyncTask,我可以将其用于我的目的,但似乎当前版本的 Android Studio 不再提供此功能。

我当前使用的 android studio 版本是 3.4(2019 年 4 月 10 日),我的 sdk 是:

        minSdkVersion 23
targetSdkVersion 26

我有一个 LoginDataSource.java 类,其中包含我假设将用于身份验证工作的以下代码。但是,当我在 TODO 行下方调用我的 HTTP 方法时,它给了我一个关于无法在主线程中执行异步的异常:

/**
* Class that handles authentication w/ login credentials and retrieves user information.
*/
public class LoginDataSource {

public Result<LoggedInUser> login(String username, String password) {

try {
// TODO: handle loggedInUser authentication
LoggedInUser fakeUser =
new LoggedInUser(
java.util.UUID.randomUUID().toString(),
"Jane Doe");
return new Result.Success<>(fakeUser);
} catch (Exception e) {
return new Result.Error(new IOException("Error logging in", e));
}
}

public void logout() {
// TODO: revoke authentication
}
}

我在之前的项目中使用 asynctask 实现了一个 HTTP 调用,但它是在使用它的同一个 Activity 中,而不是使用这个模板。放置异步任务并调用它的最佳位置应该在哪里?

谢谢!

模板中的其他类:

LoginRepository.java

/**
* Class that requests authentication and user information from the remote data source and
* maintains an in-memory cache of login status and user credentials information.
*/
public class LoginRepository {

private static volatile LoginRepository instance;

private LoginDataSource dataSource;

// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
private LoggedInUser user = null;

// private constructor : singleton access
private LoginRepository(LoginDataSource dataSource) {
this.dataSource = dataSource;
}

public static LoginRepository getInstance(LoginDataSource dataSource) {
if (instance == null) {
instance = new LoginRepository(dataSource);
}
return instance;
}

public boolean isLoggedIn() {
return user != null;
}

public void logout() {
user = null;
dataSource.logout();
}

private void setLoggedInUser(LoggedInUser user) {
this.user = user;
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
}

public Result<LoggedInUser> login(String username, String password) {
// handle login
Result<LoggedInUser> result = dataSource.login(username, password);
if (result instanceof Result.Success) {
setLoggedInUser(((Result.Success<LoggedInUser>) result).getData());
}
return result;
}
}

LoggedInUserView.java

/**
* Class exposing authenticated user details to the UI.
*/
class LoggedInUserView implements Serializable {
private String displayName;
//... other data fields that may be accessible to the UI

LoggedInUserView(String displayName) {
this.displayName = displayName;
}

String getDisplayName() {
return displayName;
}
}

LoginViewModel.java

public class LoginViewModel extends ViewModel {

private MutableLiveData<LoginFormState> loginFormState = new MutableLiveData<>();
private MutableLiveData<LoginResult> loginResult = new MutableLiveData<>();
private LoginRepository loginRepository;

LoginViewModel(LoginRepository loginRepository) {
this.loginRepository = loginRepository;
}

LiveData<LoginFormState> getLoginFormState() {
return loginFormState;
}

LiveData<LoginResult> getLoginResult() {
return loginResult;
}

public void login(String username, String password) {
// can be launched in a separate asynchronous job
Result<LoggedInUser> result = loginRepository.login(username, password);

if (result instanceof Result.Success) {
LoggedInUser data = ((Result.Success<LoggedInUser>) result).getData();
loginResult.setValue(new LoginResult(new LoggedInUserView(data.getDisplayName())));
} else {
loginResult.setValue(new LoginResult(R.string.login_failed));
}
}

public void loginDataChanged(String username, String password) {
if (!isUserNameValid(username)) {
loginFormState.setValue(new LoginFormState(R.string.invalid_username, null));
} else if (!isPasswordValid(password)) {
loginFormState.setValue(new LoginFormState(null, R.string.invalid_password));
} else {
loginFormState.setValue(new LoginFormState(true));
}
}

// A placeholder username validation check
private boolean isUserNameValid(String username) {
if (username == null) {
return false;
}
if (username.contains("@")) {
return Patterns.EMAIL_ADDRESS.matcher(username).matches();
} else {
return !username.trim().isEmpty();
}
}

// A placeholder password validation check
private boolean isPasswordValid(String password) {
return password != null && password.trim().length() > 5;
}
}

LoginActivity.java

public class LoginActivity extends AppCompatActivity {

private LoginViewModel loginViewModel;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
loginViewModel = ViewModelProviders.of(this, new LoginViewModelFactory())
.get(LoginViewModel.class);

final EditText usernameEditText = findViewById(R.id.username);
final EditText passwordEditText = findViewById(R.id.password);
final Button loginButton = findViewById(R.id.login);
final ProgressBar loadingProgressBar = findViewById(R.id.loading);

loginViewModel.getLoginFormState().observe(this, new Observer<LoginFormState>() {
@Override
public void onChanged(@Nullable LoginFormState loginFormState) {
if (loginFormState == null) {
return;
}
loginButton.setEnabled(loginFormState.isDataValid());
if (loginFormState.getUsernameError() != null) {
usernameEditText.setError(getString(loginFormState.getUsernameError()));
}
if (loginFormState.getPasswordError() != null) {
passwordEditText.setError(getString(loginFormState.getPasswordError()));
}
}
});

loginViewModel.getLoginResult().observe(this, new Observer<LoginResult>() {
@Override
public void onChanged(@Nullable LoginResult loginResult) {
if (loginResult == null) {
return;
}
loadingProgressBar.setVisibility(View.GONE);
if (loginResult.getError() != null) {
showLoginFailed(loginResult.getError());
}
if (loginResult.getSuccess() != null) {
updateUiWithUser(loginResult.getSuccess());
}
setResult(Activity.RESULT_OK);

//Complete and destroy login activity once successful
finish();
}
});

TextWatcher afterTextChangedListener = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// ignore
}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// ignore
}

@Override
public void afterTextChanged(Editable s) {
loginViewModel.loginDataChanged(usernameEditText.getText().toString(),
passwordEditText.getText().toString());
}
};
usernameEditText.addTextChangedListener(afterTextChangedListener);
passwordEditText.addTextChangedListener(afterTextChangedListener);
passwordEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {

@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
loginViewModel.login(usernameEditText.getText().toString(),
passwordEditText.getText().toString());
}
return false;
}
});

loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
loadingProgressBar.setVisibility(View.VISIBLE);
loginViewModel.login(usernameEditText.getText().toString(),
passwordEditText.getText().toString());
}
});
}

private void updateUiWithUser(LoggedInUserView model) {
String welcome = getString(R.string.welcome) + model.getDisplayName();
// TODO : initiate successful logged in experience
Toast.makeText(getApplicationContext(), welcome, Toast.LENGTH_LONG).show();
}

private void showLoginFailed(@StringRes Integer errorString) {
Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_SHORT).show();
}
}

最佳答案

我也在寻找一个好的解决方案。目前我最终实现了 2 个 Listeners 接口(interface)。

public interface OnLoginListener {
void onLoginResult(Result result);
}
public interface OnRegistrationListener {
void onRegistrationResult(Result result);
}

我让我的 ViewModel 实现了这些接口(interface)并相应地更改了 UI,我不确定这是否遵循了 MVVM 模式的最佳实践。LoginDataSource 被传递给监听器的引用

private OnLoginListener onLoginListener;
private OnRegistrationListener onRegistrationListener;

并从 onPostExecute 调用 onRegistrationResult 方法,或者像我的情况一样从 Firebase 身份验证的 onComplete 方法调用。

@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "createUserWithEmail:success");
FirebaseUser user = mAuth.getCurrentUser();
onRegistrationListener.onRegistrationResult(new Result.Success<>(user));
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "createUserWithEmail:failure", task.getException());
onRegistrationListener.onRegistrationResult(new Result.Error(task.getException()));
}
}

我希望这对某人有帮助;)。

关于android - 如何在 Android Studio 的登录 Activity 模板中实现 AsyncTask,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55787064/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com