前言:
接到一个新需求,为已有安卓项目增加一个登录页,这里记录一下开发过程以及其中遇到的问题; 已有项目主要有initActivity和mainActivity;
碰到的问题1:在发送请求时(线上);程序直接挂掉;
分析原因及解决思路: 这是因为在主线程进行网络请求;Android 不允许在主线程中执行耗时的网络操作,这会导致应用无响应(ANR)或崩溃。所以我使用了异步任务(AsyncTask)来解决此问题;
问题2:因为当前程序中已有initActivity和mainActivity;入口是init 我现在要将login加入到里面; 有一个bug是 当我将程序切换到后台时,在进行登录时,会报错
分析原因及解决思路:main调用之前必须加载init;当我将程序切换到后台时,程序不会再在加载initActivity;这就导致我登录成功后跳转mainActivity会挂掉。 针对这种情况, 我将initAcitivity中的代码嵌入到LoginActivity中,并且在AndroidManifest.xml中 取消了initActivity作为启动入口就解决了此问题。
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 权限声明 -->
<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:usesCleartextTraffic="true"
android:icon="*******"
android:label=*******"
android:roundIcon="*******"
android:supportsRtl="*******"
android:theme="*******"
tools:targetApi="31">
<!-- 设置启动的 Activity 为 LoginActivity -->
<activity
android:name=".LoginActivity"
android:label="Login"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 设置主界面 Activity -->
<activity android:name=".MainActivity"/>
<!-- 其他 Activity -->
<activity android:name=".WebActivity" />
</application>
</manifest>
开发思路:
1.先去编写登录的页面login_layout ;
这里我就直接去gpt搜索让它给我编写一个登录页;然后我再复制到自己的项目中进行修改;以下是完整的代码; 里面有一些图片的引用,设计到logo就不便展示;可以替换为你们自己的图片
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="0dp"
android:background="@drawable/light_back2">
<ImageView
android:id="@+id/imageViewLogo"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_centerHorizontal="true"
android:src="@drawable/circle"
android:scaleType="fitXY"/>
<ImageView
android:id="@+id/lightCode"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_below="@id/imageViewLogo"
android:layout_centerHorizontal="true"
android:layout_marginTop="32dp"
android:src="@drawable/light_code" />
<EditText
android:id="@+id/editTextUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="35dp"
android:layout_below="@id/lightCode"
android:layout_centerHorizontal="true"
android:background="@drawable/edittext_background"
android:hint="请输入账号"
android:padding="8dp" />
<EditText
android:id="@+id/editTextPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:layout_marginLeft="70dp"
android:layout_below="@id/editTextUsername"
android:layout_centerHorizontal="true"
android:padding="8dp"
android:inputType="textPassword"
android:background="@drawable/edittext_background"
android:hint="请输入密码"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_below="@id/editTextPassword"
android:orientation="horizontal"
android:gravity="center_horizontal"
android:layout_margin="50dp">
<Button
android:id="@+id/buttonReset"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="重置"
android:backgroundTint="@color/white"
android:textColor="#000000"
android:layout_marginEnd="8dp" />
<View
android:layout_width="50dp"
android:layout_height="match_parent"/>
<Button
android:id="@+id/buttonLogin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:backgroundTint="@color/white"
android:layout_weight="1"
android:textColor="#000000"
android:text="登录"
android:layout_marginStart="8dp"/>
</LinearLayout>
</RelativeLayout>
这是效果图:
2.编写LoginActivity
onCreate方法
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_layout);
// 初始化视图
editTextUsername = findViewById(R.id.editTextUsername);
editTextPassword = findViewById(R.id.editTextPassword);
buttonLogin = findViewById(R.id.buttonLogin);
Button resetButton = findViewById(R.id.buttonReset);
resetButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
editTextUsername.setText("");
editTextPassword.setText("");
}
});
// 设置登录按钮点击事件
buttonLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 获取用户名和密码
String username = editTextUsername.getText().toString().trim();
String password = editTextPassword.getText().toString().trim();
// 检查是否有旧的任务在执行
if (userLoginTask != null && userLoginTask.getStatus() == AsyncTask.Status.RUNNING) {
return; // 如果有,则不再创建新任务
}
userLoginTask = new UserLoginTask(username, password,true);
userLoginTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
}
UserLoginTask类如下:
doInBackground():
- 在后台线程中执行耗时操作,例如网络请求、数据库查询等。
- 它的参数类型由 AsyncTask 的第一个泛型参数指定,在这个例子中是
Void
,表示没有输入参数。- 它的返回值类型由 AsyncTask 的第三个泛型参数指定,在这个例子中是
Boolean
,表示任务执行结果的类型
onPostExecute():
- 在主线程中执行,在
doInBackground()
执行完毕后调用。- 用于处理异步任务执行完成后的结果,例如更新 UI 或者执行其他操作。
- 它的参数类型是
doInBackground()
返回的结果类型,在这个例子中是Boolean
,表示任务执行的结果。
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
private final String account;
private final String password;
private final boolean loginServer;
UserLoginTask(String account, String password, boolean loginServer) {
this.account = account;
this.password = password;
this.loginServer = loginServer;
}
@Override
protected Boolean doInBackground(Void... params) {
if(loginServer){
JSONObject req = new JSONObject();
try {
req.put("userName", account);
req.put("password", password);
String retStr = HttpUtil.postJson("************", req.toString());
JSONObject retJson = new JSONObject(retStr);
if(retJson.getBoolean("success")){
return true;
}
} catch (Exception e) {
Log.d("zqfw", e.getMessage());
}
}
return false;
}
@Override
protected void onPostExecute(final Boolean success) {
userLoginTask = null;
if (success) {
//如果请求成功,则跳转MainActivity
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish(); // 关闭登录界面,防止用户返回到登录界面
} else {
Toast.makeText(LoginActivity.this, "账号或密码不正确,请重新输入!", Toast.LENGTH_SHORT).show();
}
}
}