Algorithm_String: 字符串与EditText_01

利用Java处理Android EditText与String方法
本博客介绍如何在Android应用中使用Java处理EditText组件的内容,包括去除空格、判断是否包含中文字符,并提供了相应的代码实现。文章还讨论了Java与Android中关于空格表示的差异。

虽然使用java来开发android的应用层,但是与Java的有些东西还是有所出入。

本篇博客结合android的EditText与String类的方法,希望能在开发中帮助到你。

这篇博客您可以了解到:

<1> 获取EditText的内容,去除该内容包含的所有空格。

<2>获取EditText的内容,判断该内容是否包含中文

效果图:


实现代码:

import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; public class EditTextAndString extends Activity { private static final char SPACE = 0x20; private EditText user = null; private EditText result = null; private Button button = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); user = (EditText) findViewById(R.id.user); result = (EditText) findViewById(R.id.result); button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { String name = user.getText().toString(); String res = removeAllSpace(name); result.append("去除所有空格后:" + res + "\n"); if (isChinese(name)) { // ToDo } } }); } /** * 该字符是否包含中文字符 * * @param c * 字符 * @return 如果包含中文返回true,否则false */ public boolean isChinese(char c) { Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { return true; } return false; } /** * 该字符串是否包含中文字符 * * @param str * 字符串 * @return 如果包含中文返回true,否则返回false */ public boolean isChinese(String str) { if ((str != null) && (!"".equals(str))) { char[] ch = str.toCharArray(); int len = ch.length; for (int i = 0; i < len; i++) { // Log.d("mark", "<---> " + ch[i]); if (isChinese(ch[i])) { result.append("该字符串中第一个中文:" + ch[i] + "\n"); return true; } } } return false; } /** * 去除字符串中所有空格 * * @param s * 字符串 * @return 字符串 * * 注意:String类的trim()只可以去除两端的空格 */ public String removeAllSpace(String s) { String endString = ""; StringBuilder builder = new StringBuilder(endString); int len = s.length(); for (int i = 0; i <len ; i++) { // 获得字符 char c = s.charAt(i); // 如果该字符不是空格 if (c != SPACE) { builder.append(String.valueOf(c)); } } return builder.toString(); } }这里需要注意一个问题:

在Java的JDK中,表示空格在java.awt.event.KeyEvent 类中有一个字段来表示:

public static final int VK_SPACE = 0x20;
但是在android中没有专门这个字段,专门查看android的import android.view.KeyEvent 类,也有一个字段:

public static final int KEYCODE_SPACE = 62;但是他表示的不是字符的空格。通过查找Ascii码(http://blog.youkuaiyun.com/androidbluetooth/article/details/6434049),可以知道空格的Ascii码知道,其值是0x20(32).


#include <windows.h> #include <cstdlib> #include <ctime> #include <string> #include <algorithm> // For std::min and std::max if needed // 控件ID定义 #define ID_BUTTON_GUESS 101 #define ID_EDIT_INPUT 102 #define ID_STATIC_HINT 103 #define ID_STATIC_ATTEMPTS 104 #define ID_BUTTON_SET_RANGE 105 // 新增按钮:设置范围 #define ID_EDIT_MAX_VALUE 106 // 新增编辑框:输入最大值 // 全局变量 int secretNumber; int attempts = 0; const int DEFAULT_MAX = 100; // 默认最大值为100 int currentMax = DEFAULT_MAX; // 当前最大值,可被用户修改 const int MAX_ATTEMPTS = 10; // 生成随机数,基于当前的currentMax void GenerateSecretNumber() { srand(time(0)); secretNumber = rand() % currentMax + 1; // 1到currentMax之间的随机数 } // 窗口过程函数 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hEditInput, hHint, hAttempts, hEditMax, hButtonSetRange; switch (message) { case WM_CREATE: { // 创建主标题静态文本,显示当前范围 std::wstring titleText = L"猜数字游戏 (1-"; titleText += std::to_wstring(currentMax); titleText += L")"; CreateWindow("STATIC", titleText.c_str(), WS_VISIBLE | WS_CHILD, 20, 20, 200, 25, hWnd, (HMENU)ID_STATIC_HINT, NULL, NULL); // 输入猜测数字的编辑框 hEditInput = CreateWindow("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_NUMBER, 20, 50, 100, 25, hWnd, (HMENU)ID_EDIT_INPUT, NULL, NULL); // “猜”按钮 CreateWindow("BUTTON", L"猜", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 130, 50, 80, 25, hWnd, (HMENU)ID_BUTTON_GUESS, NULL, NULL); // 提示信息的静态文本 hHint = CreateWindow("STATIC", L"输入数字后点击按钮", WS_VISIBLE | WS_CHILD, 20, 90, 300, 25, hWnd, (HMENU)ID_STATIC_HINT, NULL, NULL); // 剩余次数显示 hAttempts = CreateWindow("STATIC", (L"剩余次数: " + std::to_wstring(MAX_ATTEMPTS)).c_str(), WS_VISIBLE | WS_CHILD, 20, 120, 200, 25, hWnd, (HMENU)ID_STATIC_ATTEMPTS, NULL, NULL); // 新增:“设置范围”按钮 hButtonSetRange = CreateWindow("BUTTON", L"设置范围", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 20, 150, 100, 25, hWnd, (HMENU)ID_BUTTON_SET_RANGE, NULL, NULL); // 新增:输入最大值的编辑框,初始值为当前最大值 std::wstring initMaxStr = std::to_wstring(currentMax); hEditMax = CreateWindow("EDIT", initMaxStr.c_str(), WS_VISIBLE | WS_CHILD | WS_BORDER | ES_NUMBER, 130, 150, 100, 25, hWnd, (HMENU)ID_EDIT_MAX_VALUE, NULL, NULL); // 生成第一个秘密数字 GenerateSecretNumber(); break; } case WM_COMMAND: { int id = LOWORD(wParam); if (id == ID_BUTTON_GUESS) { // “猜”按钮被点击 char buffer[10]; GetWindowTextA(hEditInput, buffer, sizeof(buffer)); int guess = atoi(buffer); attempts++; int remaining = MAX_ATTEMPTS - attempts; SetWindowTextA(hAttempts, (std::string("剩余次数: ") + std::to_string(remaining)).c_str()); if (guess == secretNumber) { MessageBoxA(hWnd, "恭喜你猜对了!", "游戏胜利", MB_OK); GenerateSecretNumber(); attempts = 0; SetWindowTextA(hAttempts, (std::string("剩余次数: ") + std::to_string(MAX_ATTEMPTS)).c_str()); } else if (guess < secretNumber) { SetWindowTextA(hHint, "太小了!再试一次"); } else { SetWindowTextA(hHint, "太大了!再试一次"); } if (attempts >= MAX_ATTEMPTS) { MessageBoxA(hWnd, (std::string("游戏结束!数字是 ") + std::to_string(secretNumber)).c_str(), "游戏结束", MB_OK); GenerateSecretNumber(); attempts = 0; SetWindowTextA(hAttempts, (std::string("剩余次数: ") + std::to_string(MAX_ATTEMPTS)).c_str()); } SetWindowTextA(hEditInput, ""); // 清空输入框 } else if (id == ID_BUTTON_SET_RANGE) { // “设置范围”按钮被点击 char maxBuffer[10]; GetWindowTextA(hEditMax, maxBuffer, sizeof(maxBuffer)); int newMax = atoi(maxBuffer); // 验证输入是否有效 if (newMax < 2 || newMax > 200) { // 最小允许2,最大限制为200 MessageBoxA(hWnd, "请输入一个有效的最大值(2-200)", "无效输入", MB_ICONERROR); } else { currentMax = newMax; // 更新窗口标题以反映新的范围 std::wstring newTitle = L"猜数字游戏 (1-"; newTitle += std::to_wstring(currentMax); newTitle += L")"; SetWindowTextW(GetDlgItem(hWnd, 0), newTitle.c_str()); // 假设第一个子控件是标题 // 重新生成秘密数字 GenerateSecretNumber(); // 重置尝试次数 attempts = 0; SetWindowTextA(hAttempts, (std::string("剩余次数: ") + std::to_string(MAX_ATTEMPTS)).c_str()); // 清空猜测输入框并给出提示 SetWindowTextA(hEditInput, ""); SetWindowTextA(hHint, "已更新范围,请重新猜测"); } break; } break; } case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // WinMain入口函数 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 注册窗口类 WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW+1), NULL, L"GuessNumberWindowClass", NULL }; RegisterClassEx(&wc); // 创建窗口 HWND hWnd = CreateWindow(L"GuessNumberWindowClass", L"猜数字游戏", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 250, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // 消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }加多一个功能:例如输入30,1-100会变成1-30
08-02
package com.example.kucun2.data; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import androidx.annotation.NonNull; import androidx.room.Database; import androidx.room.Room; import androidx.room.RoomDatabase; import androidx.room.migration.Migration; import androidx.sqlite.db.SupportSQLiteDatabase; import com.example.kucun2.entity.User; import java.io.File; @Database(entities = {User.class}, version = 2, exportSchema = false ) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); private static volatile AppDatabase INSTANCE; public static AppDatabase getDatabase(Context context) { return Room.databaseBuilder(context, AppDatabase.class, "users.db") .addMigrations(MIGRATION_1_2) .addCallback(new RoomDatabase.Callback() { @Override public void onOpen(@NonNull SupportSQLiteDatabase db) { // 确保视图存在 db.execSQL("CREATE VIEW IF NOT EXISTS user_summary AS SELECT id, name FROM users"); } }) .fallbackToDestructiveMigrationOnDowngrade() .build(); } private static void migrateFromLegacy(Context context) { // 旧数据库迁移逻辑 SQLiteDatabase legacyDb = SQLiteDatabase.openDatabase( context.getDatabasePath("users.db").getPath(), null, SQLiteDatabase.OPEN_READONLY); Cursor cursor = legacyDb.rawQuery("SELECT * FROM users", null); // 数据迁移到Room数据库 UserDao dao = INSTANCE.userDao(); // 使用事务保证迁移完整性 INSTANCE.runInTransaction(() -> { while (cursor.moveToNext()) { User user = new User(cursor.getInt(0), cursor.getString(1), cursor.getString(2), cursor.getString(3), cursor.getInt(4) ); dao.insert(user); } cursor.close(); legacyDb.close(); }); } private static final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(@NonNull SupportSQLiteDatabase db) { // 示例:添加新字段 // 示例:创建视图(不修改表结构) db.execSQL("CREATE TABLE users_temp (id INTEGER PRIMARY KEY, " + "name TEXT, " + "andy TEXT, " + "pass TEXT, " + "role INTEGER)" + ""); // 3. 迁移数据 db.execSQL("INSERT INTO users_temp (id, name, andy, pass, role) " + "SELECT id, name, andy, pass, role FROM users"); // 4. 删除旧表并重命名 db.execSQL("DROP TABLE users"); db.execSQL("ALTER TABLE users_temp RENAME TO users"); // 5. 维护视图 db.execSQL("DROP VIEW IF EXISTS user_summary"); db.execSQL("CREATE VIEW user_summary AS SELECT id, name FROM users"); } }; public static void deleteDatabase(Context context) { // 1. 关闭现有连接 if (INSTANCE != null) { INSTANCE.close(); INSTANCE = null; } // 2. 删除物理文件 context.deleteDatabase("users.db"); // 3. 清理残留文件(WAL/SHM) File databaseDir = context.getDatabasePath("users.db").getParentFile(); if (databaseDir != null) { for (File file : databaseDir.listFiles()) { if (file.getName().startsWith("users.db")) { file.delete(); } } } } }package com.example.kucun2.ui.moban; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.graphics.Rect; import android.os.Bundle; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.DecelerateInterpolator; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import com.example.kucun2.Http.HttpApi; import com.example.kucun2.Http.ReturnMethod; import com.example.kucun2.R; import com.example.kucun2.data.AppDatabase; import com.example.kucun2.entity.User; import com.example.kucun2.manager.AuthManager; import java.io.File; public class MainActivity extends AppCompatActivity implements View.OnClickListener, View.OnFocusChangeListener, ViewTreeObserver.OnGlobalLayoutListener, TextWatcher { private String TAG = "ifu25"; private ImageButton mIbNavigationBack; private LinearLayout mLlLoginPull; private View mLlLoginLayer; private LinearLayout mLlLoginOptions; private EditText mEtLoginUsername; private EditText mEtLoginPwd; private LinearLayout mLlLoginUsername; private ImageView mIvLoginUsernameDel; private Button mBtLoginSubmit; private LinearLayout mLlLoginPwd; private ImageView mIvLoginPwdDel; private ImageView mIvLoginLogo; private LinearLayout mLayBackBar; private TextView mTvLoginForgetPwd; private Button mBtLoginRegister; private CheckBox cbAgree; //全局Toast private Toast mToast; private int mLogoHeight; private int mLogoWidth; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); initView(); } //初始化视图 private void initView() { //登录层、下拉层、其它登录方式层 mLlLoginPull = findViewById(R.id.ll_login_pull); mLlLoginOptions = findViewById(R.id.ll_login_options); //导航栏+返回按钮 mLayBackBar = findViewById(R.id.ly_retrieve_bar); mIbNavigationBack = findViewById(R.id.ib_navigation_back); //logo mIvLoginLogo = findViewById(R.id.iv_login_logo); //username mLlLoginUsername = findViewById(R.id.ll_login_username); mEtLoginUsername = findViewById(R.id.et_login_username); mIvLoginUsernameDel = findViewById(R.id.iv_login_username_del); //passwd mLlLoginPwd = findViewById(R.id.ll_login_pwd); mEtLoginPwd = findViewById(R.id.et_login_pwd); mIvLoginPwdDel = findViewById(R.id.iv_login_pwd_del); //提交、注册 mBtLoginSubmit = findViewById(R.id.bt_login_submit); //忘记密码 mTvLoginForgetPwd = findViewById(R.id.tv_login_forget_pwd); mTvLoginForgetPwd.setOnClickListener(this); //注册点击事件 mLlLoginPull.setOnClickListener(this); mIbNavigationBack.setOnClickListener(this); mEtLoginUsername.setOnClickListener(this); mIvLoginUsernameDel.setOnClickListener(this); mBtLoginSubmit.setOnClickListener(this); mEtLoginPwd.setOnClickListener(this); mIvLoginPwdDel.setOnClickListener(this); findViewById(R.id.ib_login_weibo).setOnClickListener(this); findViewById(R.id.ib_login_qq).setOnClickListener(this); findViewById(R.id.ib_login_wx).setOnClickListener(this); //注册其它事件 mLayBackBar.getViewTreeObserver().addOnGlobalLayoutListener(this); mEtLoginUsername.setOnFocusChangeListener(this); mEtLoginUsername.addTextChangedListener(this); mEtLoginPwd.setOnFocusChangeListener(this); mEtLoginPwd.addTextChangedListener(this); cbAgree = findViewById(R.id.cb_remember_login); cbAgree.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { Toast.makeText(this, "已同意协议", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "请阅读并同意协议", Toast.LENGTH_SHORT).show(); } }); } @SuppressLint("NonConstantResourceId") @Override public void onClick(View view) { switch (view.getId()) { case R.id.ib_navigation_back: //返回 finish(); break; case R.id.et_login_username: mEtLoginPwd.clearFocus(); mEtLoginUsername.setFocusableInTouchMode(true); mEtLoginUsername.requestFocus(); break; case R.id.et_login_pwd: mEtLoginUsername.clearFocus(); mEtLoginPwd.setFocusableInTouchMode(true); mEtLoginPwd.requestFocus(); break; case R.id.iv_login_username_del: //清空用户名 mEtLoginUsername.setText(null); break; case R.id.iv_login_pwd_del: //清空密码 mEtLoginPwd.setText(null); break; case R.id.bt_login_submit: //登录 loginRequest(); break; case R.id.tv_login_forget_pwd: //忘记密码 startActivity(new Intent(MainActivity.this, ForgetPwdActivity.class)); break; case R.id.ll_login_pull: mLlLoginPull.animate().cancel(); mLlLoginLayer.animate().cancel(); int height = mLlLoginOptions.getHeight(); float progress = (mLlLoginLayer.getTag() != null && mLlLoginLayer.getTag() instanceof Float) ? (float) mLlLoginLayer.getTag() : 1; int time = (int) (360 * progress); if (mLlLoginPull.getTag() != null) { mLlLoginPull.setTag(null); glide(height, progress, time); } else { mLlLoginPull.setTag(true); upGlide(height, progress, time); } break; case R.id.ib_login_weibo: weiboLogin(); break; case R.id.ib_login_qq: qqLogin(); break; case R.id.ib_login_wx: weixinLogin(); break; default: break; } } //用户名密码焦点改变 @Override public void onFocusChange(View v, boolean hasFocus) { int id = v.getId(); if (id == R.id.et_login_username) { if (hasFocus) { mLlLoginUsername.setActivated(true); mLlLoginPwd.setActivated(false); } } else { if (hasFocus) { mLlLoginPwd.setActivated(true); mLlLoginUsername.setActivated(false); } } } /** * menu glide * * @param height height * @param progress progress * @param time time */ private void glide(int height, float progress, int time) { mLlLoginPull.animate() .translationYBy(height - height * progress) .translationY(height) .setDuration(time) .start(); mLlLoginLayer.animate() .alphaBy(1 * progress) .alpha(0) .setDuration(time) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { if (animation instanceof ValueAnimator) { mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); } } @Override public void onAnimationEnd(Animator animation) { if (animation instanceof ValueAnimator) { mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); } mLlLoginLayer.setVisibility(View.GONE); } }) .start(); } /** * menu up glide * * @param height height * @param progress progress * @param time time */ private void upGlide(int height, float progress, int time) { mLlLoginPull.animate() .translationYBy(height * progress) .translationY(0) .setDuration(time) .start(); mLlLoginLayer.animate() .alphaBy(1 - progress) .alpha(1) .setDuration(time) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mLlLoginLayer.setVisibility(View.VISIBLE); } @Override public void onAnimationCancel(Animator animation) { if (animation instanceof ValueAnimator) { mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); } } @Override public void onAnimationEnd(Animator animation) { if (animation instanceof ValueAnimator) { mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue()); } } }) .start(); } //显示或隐藏logo @Override public void onGlobalLayout() { final ImageView ivLogo = this.mIvLoginLogo; Rect KeypadRect = new Rect(); mLayBackBar.getWindowVisibleDisplayFrame(KeypadRect); int screenHeight = mLayBackBar.getRootView().getHeight(); int keypadHeight = screenHeight - KeypadRect.bottom; //隐藏logo if (keypadHeight > 300 && ivLogo.getTag() == null) { final int height = ivLogo.getHeight(); final int width = ivLogo.getWidth(); this.mLogoHeight = height; this.mLogoWidth = width; ivLogo.setTag(true); ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0); valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); valueAnimator.addUpdateListener(animation -> { float animatedValue = (float) animation.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = ivLogo.getLayoutParams(); layoutParams.height = (int) (height * animatedValue); layoutParams.width = (int) (width * animatedValue); ivLogo.requestLayout(); ivLogo.setAlpha(animatedValue); }); if (valueAnimator.isRunning()) { valueAnimator.cancel(); } valueAnimator.start(); } //显示logo else if (keypadHeight < 300 && ivLogo.getTag() != null) { final int height = mLogoHeight; final int width = mLogoWidth; ivLogo.setTag(null); ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator()); valueAnimator.addUpdateListener(animation -> { float animatedValue = (float) animation.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = ivLogo.getLayoutParams(); layoutParams.height = (int) (height * animatedValue); layoutParams.width = (int) (width * animatedValue); ivLogo.requestLayout(); ivLogo.setAlpha(animatedValue); }); if (valueAnimator.isRunning()) { valueAnimator.cancel(); } valueAnimator.start(); } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } //用户名密码输入事件 @Override public void afterTextChanged(Editable s) { String username = mEtLoginUsername.getText().toString().trim(); String pwd = mEtLoginPwd.getText().toString().trim(); //是否显示清除按钮 if (username.length() > 0) { mIvLoginUsernameDel.setVisibility(View.VISIBLE); } else { mIvLoginUsernameDel.setVisibility(View.INVISIBLE); } if (pwd.length() > 0) { mIvLoginPwdDel.setVisibility(View.VISIBLE); } else { mIvLoginPwdDel.setVisibility(View.INVISIBLE); } //登录按钮是否可用 if (!TextUtils.isEmpty(pwd) && !TextUtils.isEmpty(username)) { mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit); mBtLoginSubmit.setTextColor(ContextCompat.getColor(this,R.color.white)); } else { mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock); mBtLoginSubmit.setTextColor(ContextCompat.getColor(this,R.color.account_lock_font_color)); } } //登录 private void loginRequest() { AppDatabase.deleteDatabase(this); // 验证是否删除成功 File dbFile = this.getDatabasePath("users.db"); if (!dbFile.exists()) { Log.d("Database", "数据库已彻底删除"); } String andy=mEtLoginUsername.getText().toString(); String pass=mEtLoginPwd.getText().toString(); Context context=this; try { HttpApi.HttpPost(getString(R.string.url_baidu), new User(0, null, andy, pass, 0), new ReturnMethod() { @Override public void Success(String data) { Log.d("success",data); // Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show(); User user =new User(0,"12323123","3211231","12312",0); AuthManager Auth=new AuthManager(context); Auth.register(user) ; Log.d("sql",""+ user.toString()); Log.d("sql",""+ Auth.login(user.getAndy(),user.getPass()) ); } @Override public void failed(String data) { } @Override public void error(Exception e) { // Toast.makeText(MainActivity.this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); Log.d("error",e.getLocalizedMessage()); } }); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } //微博登录 private void weiboLogin() { } //QQ登录 private void qqLogin() { } //微信登录 private void weixinLogin() { } /** * 显示Toast * * @param msg 提示信息内容 */ private void showToast(int msg) { if (null != mToast) { mToast.setText(msg); } else { mToast = Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT); } mToast.show(); } } package com.example.kucun2.entity; import androidx.room.Entity; import androidx.room.Ignore; import androidx.room.PrimaryKey; @Entity(tableName = "users") public class User { @PrimaryKey(autoGenerate = true) private Integer id; private String name; private String andy; private String pass; private Integer role; public int getId() { return id; } public String getName() { return name; } public String getAndy() { return andy; } public String getPass() { return pass; } public int getRole() { return role; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setAndy(String andy) { this.andy = andy; } public void setPass(String pass) { this.pass = pass; } public void setRole(int role) { this.role = role; } @Ignore public User(int id, String name, String andy, String pass, int role) { this.id = id; this.name = name; this.andy = andy; this.pass = pass; this.role = role; } public User() { } @Override public String toString() { StringBuilder sb = new StringBuilder("{"); // 处理属性名 sb.append("\"id\": "); // 处理不同数据类型 // 其他对象类型 sb.append((id != null) ? id : "null"); sb.append(","); // 处理属性名 sb.append("\"name\": "); // 处理不同数据类型 // 字符串类型处理(含转义) sb.append("\"") .append(name .replace("\\", "\\\\") .replace("\"", "\\\"") .replace("\b", "\\b") .replace("\f", "\\f") .replace("\n", "\\n") .replace("\r", "\\r") .replace("\t", "\\t")) .append("\""); sb.append(","); // 处理属性名 sb.append("\"andy\": "); // 处理不同数据类型 // 字符串类型处理(含转义) sb.append("\"") .append(andy .replace("\\", "\\\\") .replace("\"", "\\\"") .replace("\b", "\\b") .replace("\f", "\\f") .replace("\n", "\\n") .replace("\r", "\\r") .replace("\t", "\\t")) .append("\""); sb.append(","); // 处理属性名 sb.append("\"pass\": "); // 处理不同数据类型 // 字符串类型处理(含转义) sb.append("\"") .append(pass .replace("\\", "\\\\") .replace("\"", "\\\"") .replace("\b", "\\b") .replace("\f", "\\f") .replace("\n", "\\n") .replace("\r", "\\r") .replace("\t", "\\t")) .append("\""); sb.append(","); // 处理属性名 sb.append("\"role\": "); // 处理不同数据类型 // 其他对象类型 sb.append((role != null) ? role : "null"); sb.append("}"); return sb.toString(); } } package com.example.kucun2.manager; import android.content.Context; import androidx.room.Room; import com.example.kucun2.data.AppDatabase; import com.example.kucun2.data.UserDao; import com.example.kucun2.entity.User; import at.favre.lib.crypto.bcrypt.BCrypt; public class AuthManager { private final BCrypt.Hasher hasher = BCrypt.with(BCrypt.Version.VERSION_2Y); private final UserDao userDao; public AuthManager(Context context) { AppDatabase db = Room.databaseBuilder( context, AppDatabase.class, "app-db" ).build(); userDao = db.userDao(); } public boolean register(User user) { // 密码强度校验 if (!validatePassword(user.getPass())) return false; // 生成BCrypt哈希(自动处理盐值) String hash = hasher.hashToString(12, user.getPass().toCharArray()); // 异步插入数据库 new Thread(() -> { User us = new User(0,"000000",user.getAndy(),hash,0); userDao.insertUser(us); }).start(); return true; } private boolean validatePassword(String password) { return password.length() >= 8 && password.matches(".*[A-Z].*") && password.matches(".*\\d.*"); } public boolean login(String username, String password) { User user = userDao.findUserByUsername(username); if (user == null) return false; BCrypt.Result result = BCrypt.verifyer().verify( password.toCharArray(), user.getPass() ); return result.verified; } }
05-31
package com.example.diary03; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; /** * 用户登录界面 */ public class LoginActivity extends AppCompatActivity { private EditText etUsername, etPassword; private CheckBox cbRemember; private Button btnLogin; private TextView tvRegister; private DBHelper dbHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); // 初始化数据库辅助类 dbHelper = new DBHelper(this); // 获取UI组件 etUsername = findViewById(R.id.et_username); etPassword = findViewById(R.id.et_password); cbRemember = findViewById(R.id.cb_remember); btnLogin = findViewById(R.id.btn_login); tvRegister = findViewById(R.id.tv_register); // 如果勾选了"记住用户名",则从SharedPreferences加载用户名 loadRememberedUsername(); // 设置登录按钮点击事件 btnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String username = etUsername.getText().toString().trim(); String password = etPassword.getText().toString().trim(); // 验证输入 if (username.isEmpty() || password.isEmpty()) { Toast.makeText(LoginActivity.this, "用户名和密码不能为空", Toast.LENGTH_SHORT).show(); return; } // 验证用户凭据 if (dbHelper.checkUserCredentials(username, password)) { // 登录成功,保存登录状态 saveLoginStatus(username, cbRemember.isChecked()); // 跳转到主界面 startActivity(new Intent(LoginActivity.this, MainActivity.class)); finish(); } else { Toast.makeText(LoginActivity.this, "用户名或密码错误", Toast.LENGTH_SHORT).show(); } } }); // 注册链接点击事件 tvRegister.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(LoginActivity.this, RegisterActivity.class)); } }); } /** * 加载已记住的用户名 */ private void loadRememberedUsername() { SharedPreferences pref = getSharedPreferences("login_pref", Context.MODE_PRIVATE); if (pref.getBoolean("remember", false)) { String username = pref.getString("username", ""); etUsername.setText(username); cbRemember.setChecked(true); } } /** * 保存登录状态 * @param username 用户名 * @param remember 是否记住用户名 */ private void saveLoginStatus(String username, boolean remember) { SharedPreferences pref = getSharedPreferences("login_pref", Context.MODE_PRIVATE); SharedPreferences.Editor editor = pref.edit(); editor.putString("username", username); editor.putBoolean("remember", remember); editor.putBoolean("isLoggedIn", true); editor.apply(); } }将页面的记住用户名选项修改为记住密码选项
06-08
package com.example.kucun2.entity.data; import android.os.Handler; import android.os.Looper; import android.util.Log; import com.example.kucun2.entity.Information; import com.example.kucun2.entity.User; import com.example.kucun2.function.MyAppFunction; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import okhttp3.*; import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Map; /** * 重构版API客户端 - 更灵活的类型处理 * 主要改进: * 1. 分离请求参数类型和响应类型 * 2. 支持多种请求方法(GET/POST/PUT/DELETE) * 3. 支持表单和JSON两种请求格式 * 4. 自动推导响应类型 * 5. 统一的请求执行流程 */ public class ApiClient { private static final Gson gson = GsonFactory.createGson(); private static final String TAG = "ApiClient"; private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private static final int MAX_RETRY = 3; private static final Handler MAIN_HANDLER = new Handler(Looper.getMainLooper()); // ====================== 核心请求方法 ====================== /** * 执行API请求(核心方法) * @param request 构建好的OkHttp请求 * @param responseType 期望的响应类型 * @param callback 回调接口 * @param <R> 响应数据类型 */ public static <R> void executeRequest(Request request, Type responseType, ApiCallback<R> callback) { OkHttpClient client = MyAppFunction.getClient(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { handleFailure(call, e, callback, 0); } @Override public void onResponse(Call call, Response response) throws IOException { handleResponse(response, responseType, callback); } }); } // ====================== 请求构建方法 ====================== /** * 构建JSON请求 * @param url API地址 * @param method 请求方法("POST", "PUT", "DELETE") * @param requestData 请求数据对象 * @return 构建好的Request对象 */ public static Request buildJsonRequest(String url, String method, Object requestData) { String jsonRequest = ReflectionJsonUtils.toJson(requestData); Log.d(TAG, method + " URL: " + url); Log.d(TAG, "请求数据: " + jsonRequest); RequestBody body = RequestBody.create(JSON, jsonRequest); return new Request.Builder() .url(url) .method(method, body) .build(); } /** * 构建表单请求 * @param url API地址 * @param method 请求方法 * @param formData 表单数据 * @return 构建好的Request对象 */ public static Request buildFormRequest(String url, String method, Map<String, String> formData) { FormBody.Builder builder = new FormBody.Builder(); for (Map.Entry<String, String> entry : formData.entrySet()) { builder.add(entry.getKey(), entry.getValue()); } Log.d(TAG, method + " URL: " + url); Log.d(TAG, "表单数据: " + formData); return new Request.Builder() .url(url) .method(method, builder.build()) .build(); } // ====================== 响应处理方法 ====================== private static <R> void handleResponse(Response response, Type responseType, ApiCallback<R> callback) throws IOException { try (ResponseBody responseBody = response.body()) { if (!response.isSuccessful()) { String error = "HTTP " + response.code() + ": " + response.message(); Log.e(TAG, error); notifyError(callback, response.code(), error); return; } String jsonResponse = responseBody.string(); Log.d(TAG, "服务器响应: " + jsonResponse); // 解析服务端的Information包装 Information<R> wrapper = gson.fromJson(jsonResponse, responseType); if (wrapper != null && wrapper.getStatus() == 200) { notifySuccess(callback, wrapper.getData()); } else { String errorMsg = wrapper != null ? "服务端错误: " + wrapper.getStatus() + " - " + wrapper.getText() : "无效的响应格式"; Log.e(TAG, errorMsg); notifyError(callback, wrapper != null ? wrapper.getStatus() : -1, errorMsg); } } catch (Exception e) { Log.e(TAG, "响应处理异常: " + e.getMessage()); notifyError(callback, -2, "数据处理异常: " + e.getMessage()); } } // ====================== 失败处理重试 ====================== private static <R> void handleFailure(Call call, IOException e, ApiCallback<R> callback, int retryCount) { if (retryCount < MAX_RETRY) { Log.w(TAG, "请求失败,第" + (retryCount + 1) + "次重试: " + e.getMessage()); MAIN_HANDLER.postDelayed(() -> { call.clone().enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { handleFailure(call, e, callback, retryCount + 1); } @Override public void onResponse(Call call, Response response) throws IOException { handleResponse(response, getResponseType(callback), callback); } }); }, 2000); } else { Log.e(TAG, "最终请求失败: " + e.getMessage()); notifyError(callback, -1, "网络请求失败: " + e.getMessage()); } } // ====================== 类型处理工具 ====================== /** * 获取响应类型(通过回调接口的泛型参数) */ private static <R> Type getResponseType(ApiCallback<R> callback) { if (callback == null) { return new TypeToken<Information<Object>>(){}.getType(); } // 尝试获取泛型类型 Type[] genericInterfaces = callback.getClass().getGenericInterfaces(); for (Type type : genericInterfaces) { if (type instanceof ParameterizedType) { ParameterizedType pType = (ParameterizedType) type; if (pType.getRawType().equals(ApiCallback.class)) { Type dataType = pType.getActualTypeArguments()[0]; return TypeToken.getParameterized(Information.class, dataType).getType(); } } } // 默认返回Object类型 Log.w(TAG, "无法确定响应类型,使用默认Object类型"); return new TypeToken<Information<Object>>(){}.getType(); } // ====================== 回调通知方法 ====================== private static <R> void notifySuccess(ApiCallback<R> callback, R data) { if (callback != null) { MAIN_HANDLER.post(() -> callback.onSuccess(data)); } } private static <R> void notifyError(ApiCallback<R> callback, int code, String error) { if (callback != null) { MAIN_HANDLER.post(() -> callback.onError(code, error)); } } // ====================== 专用API方法 ====================== /** * 执行JSON API请求 * @param url API地址 * @param method 请求方法 * @param requestData 请求数据 * @param callback 回调接口 * @param <T> 请求数据类型 * @param <R> 响应数据类型 */ public static <T, R> void jsonRequest(String url, String method, T requestData, ApiCallback<R> callback) { Request request = buildJsonRequest(url, method, requestData); executeRequest(request, getResponseType(callback), callback); } /** * 执行表单API请求 * @param url API地址 * @param method 请求方法 * @param formData 表单数据 * @param callback 回调接口 * @param <R> 响应数据类型 */ public static <R> void formRequest(String url, String method, Map<String, String> formData, ApiCallback<R> callback) { Request request = buildFormRequest(url, method, formData); executeRequest(request, getResponseType(callback), callback); } // ====================== 便捷方法 ====================== public static <T, R> void postJson(String url, T data, ApiCallback<R> callback) { jsonRequest(url, "POST", data, callback); } public static <T, R> void putJson(String url, T data, ApiCallback<R> callback) { jsonRequest(url, "PUT", data, callback); } public static <T, R> void deleteJson(String url, T data, ApiCallback<R> callback) { jsonRequest(url, "DELETE", data, callback); } public static <R> void get(String url, ApiCallback<R> callback) { Request request = new Request.Builder().url(url).get().build(); executeRequest(request, getResponseType(callback), callback); } // ====================== 登录专用方法 ====================== public static void login(String username, String password, LoginCallback callback) { String url = MyAppFunction.getApiUrl("url_login"); Log.d(TAG, "login: " + url); formRequest(url, "POST", Map.of( "andy", username, "pass", password ), new ApiCallback<User>() { @Override public void onSuccess(User user) { if (callback != null) callback.onSuccess(user); } @Override public void onError(int statusCode, String error) { if (callback != null) callback.onFailure(error); } }); } // ====================== 回调接口定义 ====================== public interface ApiCallback<T> { void onSuccess(T data); void onError(int statusCode, String error); } public interface LoginCallback { void onSuccess(User user); void onFailure(String error); } } package com.example.kucun2.entity.data; import android.util.Log; import com.example.kucun2.function.MyAppFunction; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 可同步实体基类 * 提供实体到服务端的同步功能,包含自动重试机制和线程管理 */ public abstract class SynchronizableEntity implements EntityClassGrassrootsid { private static final String TAG = "SynchronizableEntity"; // 双重缓存结构:外层缓存类名,内层缓存字段名->Field对象 private static final Map<Class<?>, Map<String, Field>> CLASS_FIELD_CACHE = new HashMap<>(); // 网络请求线程池(静态共享) private static final ExecutorService NETWORK_EXECUTOR = Executors.newFixedThreadPool(4); /** * 获取指定类型操作的端点URL * * @param type 操作类型(如"create", "update", "delete"等) * @return 完整的端点URL路径 * * @apiNote 该方法通过资源键名拼接规则查找对应的URL资源 * @example 对于Product类的create操作,查找键为:"url_create_product" */ public String getEndpoint(String type) { // 构建资源键名:url_操作类型_类名小写 String key = "url_" + type + "_" + this.getClass().getSimpleName().toLowerCase(); return MyAppFunction.getApiUrl(key); } //================ 核心同步方法 ================// /** * 同步实体到服务端(公开接口) * * @param type 操作类型(如"add", "update","select","detect","all"等) * @param callback 同步结果回调接口 * * @implNote 内部调用私有方法实现带重试机制的同步 * @see #sync(String, SyncCallback, int) */ public void sync(String type, SyncCallback callback) { sync(type, callback, 0); // 初始重试次数为0 } private <T extends SynchronizableEntity> ApiClient.ApiCallback<T> getApiCallback(String type,SyncCallback callback,int retryCount,T thistype){ return new ApiClient.ApiCallback<T>() { @Override public void onSuccess(T responseData) { handleSyncSuccess(responseData, callback); } @Override public void onError(int statusCode, String error) { Log.d(TAG, "onError: "+thistype); handleSyncError(type, statusCode, error, callback, retryCount); } }; } private <T extends SynchronizableEntity> ApiClient.ApiCallback<T> getApiCallbackList(String type,SyncCallback callback,int retryCount,T thistype){ return new ApiClient.ApiCallback<T>() { @Override public void onSuccess(T responseData) { handleSyncSuccess(responseData, callback); } @Override public void onError(int statusCode, String error) { handleSyncError(type, statusCode, error, callback, retryCount); } }; } /** * 带重试机制的同步实现(私有方法) * * @param type 操作类型 * @param callback 同步结果回调 * @param retryCount 当前重试次数 * * @implSpec 1. 构建完整端点URL * 2. 通过线程池提交网络请求 * 3. 处理成功/失败回调 */ private void sync(String type, SyncCallback callback, int retryCount) { // 构建完整端点URL String endpoint =getEndpoint(type); Log.d(TAG, "同步端点: " + endpoint + ", 重试次数: " + retryCount); // 提交到线程池执行网络请求 NETWORK_EXECUTOR.execute(() -> { ApiClient.postJson(endpoint, this, getApiCallback(type,callback,retryCount,this)); }); } /** * 处理同步成功结果 * * @param responseData 服务端返回的实体数据 * @param callback 同步结果回调 * * @implNote 1. 更新实体ID * 2. 记录成功日志 * 3. 触发成功回调 */ private void handleSyncSuccess(SynchronizableEntity responseData, SyncCallback callback) { // 更新实体ID(如果服务端返回了新ID) if (responseData != null) { setId(responseData.getId()); Log.i(TAG, "同步成功, 新ID: " + responseData.getId()); } // 触发成功回调 if (callback != null) callback.onSyncSuccess(this); } /** * 处理同步错误(含重试逻辑) * * @param type 操作类型 * @param statusCode HTTP状态码(-1表示网络错误) * @param error 错误信息 * @param callback 同步结果回调 * @param retryCount 当前重试次数 * * @implSpec 1. 判断错误是否可重试(网络错误或5xx服务错误) * 2. 满足条件时进行指数退避重试 * 3. 达到最大重试次数后触发失败回调 * * @algorithm 使用指数退避算法:延迟时间 = 1000ms * 2^重试次数 */ private void handleSyncError(String type, int statusCode, String error, SyncCallback callback, int retryCount) { Log.e(TAG, "同步失败: " + error + ", 状态码: " + statusCode); // 判断是否可重试(网络错误或服务端5xx错误) boolean canRetry = statusCode == -1 || (statusCode >= 500 && statusCode < 600); // 满足重试条件(可重试错误且未达到最大重试次数) if (canRetry && retryCount < 3) { // 计算指数退避延迟时间 long delay = (long) (1000 * Math.pow(2, retryCount)); Log.w(TAG, "将在 " + delay + "ms 后重试"); try { // 当前线程休眠指定时间 Thread.sleep(delay); } catch (InterruptedException e) { // 恢复中断状态 Thread.currentThread().interrupt(); } // 递归调用进行重试(重试次数+1) sync(type, callback, retryCount + 1); } else { // 不可重试或达到最大重试次数,触发失败回调 if (callback != null) { String finalError = "同步失败: " + error; if (canRetry) finalError += " (重试失败)"; callback.onSyncFailure(finalError); } } } // 线程安全的对象复制方法 public void updateFrom(Object source) { if ( source == null) return; Class<?> targetClass = this.getClass(); Class<?> sourceClass = source.getClass(); // 获取或创建字段缓存 Map<String, Field> targetFields = getOrCreateFieldCache(targetClass); Map<String, Field> sourceFields = getOrCreateFieldCache(sourceClass); // 遍历源对象字段 for (Map.Entry<String, Field> entry : sourceFields.entrySet()) { String fieldName = entry.getKey(); Field sourceField = entry.getValue(); // 查找目标对象对应字段 Field targetField = targetFields.get(fieldName); if (targetField != null) { // 类型兼容性检查 if (isCompatibleTypes(sourceField.getType(), targetField.getType())) { try { // 复制字段值 Object value = sourceField.get(source); targetField.set(this, value); } catch (IllegalAccessException e) { // 处理异常,记录日志 } } } } } // 获取或创建类的字段缓存 private static Map<String, Field> getOrCreateFieldCache(Class<?> clazz) { // 双重检查锁确保线程安全 if (!CLASS_FIELD_CACHE.containsKey(clazz)) { synchronized (clazz) { if (!CLASS_FIELD_CACHE.containsKey(clazz)) { Map<String, Field> fieldMap = new HashMap<>(); // 递归获取所有字段(包括父类) for (Class<?> current = clazz; current != null; current = current.getSuperclass()) { for (Field field : current.getDeclaredFields()) { field.setAccessible(true); // 突破访问限制 fieldMap.put(field.getName(), field); } } CLASS_FIELD_CACHE.put(clazz, fieldMap); } } } return CLASS_FIELD_CACHE.get(clazz); } // 类型兼容性检查(支持自动装箱/拆箱) private static boolean isCompatibleTypes(Class<?> sourceType, Class<?> targetType) { // 处理基本类型和包装类的兼容性 if (sourceType.isPrimitive()) { sourceType = primitiveToWrapper(sourceType); } if (targetType.isPrimitive()) { targetType = primitiveToWrapper(targetType); } return targetType.isAssignableFrom(sourceType); } // 基本类型转包装类 private static Class<?> primitiveToWrapper(Class<?> primitiveType) { if (boolean.class.equals(primitiveType)) return Boolean.class; if (byte.class.equals(primitiveType)) return Byte.class; if (char.class.equals(primitiveType)) return Character.class; if (double.class.equals(primitiveType)) return Double.class; if (float.class.equals(primitiveType)) return Float.class; if (int.class.equals(primitiveType)) return Integer.class; if (long.class.equals(primitiveType)) return Long.class; if (short.class.equals(primitiveType)) return Short.class; if (void.class.equals(primitiveType)) return Void.class; return primitiveType; } //================ 回调接口 ================// /** * 同步操作回调接口 * * @implNote 使用方需实现此接口处理同步结果 */ public interface SyncCallback { /** * 同步成功回调 * * @param entity 同步后的实体对象(已更新ID) */ void onSyncSuccess(SynchronizableEntity entity); /** * 同步失败回调 * * @param error 失败原因描述 */ void onSyncFailure(String error); } } package com.example.kucun2.DataPreserver; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.util.Log; import com.example.kucun2.entity.*; import com.example.kucun2.entity.Information; import com.example.kucun2.entity.data.*; import com.example.kucun2.function.MyAppFunction; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.List; /** * 重构后的数据加载器:使用ApiClient处理网络请求 */ public class DataLoader { private static final String TAG = "DataLoader"; private final DataStore dataStore; private final DataAssociator dataAssociator; // private final DataPreserver dataPreserver; public DataLoader(DataStore dataStore, DataAssociator dataAssociator ) { this.dataStore = dataStore; this.dataAssociator = dataAssociator; // this.dataPreserver = dataPreserver; } public void loadAllData(Context context, LoadDataCallback callback) { if (Looper.myLooper() != Looper.getMainLooper()) { throw new IllegalStateException("必须在主线程调用Data.loadAllData"); } // dataPreserver.ensurePreservedObjects(); String url = MyAppFunction.getApiUrl("url_all"); Log.d(TAG, "开始加载数据, URL: " + url); // 使用ApiClient的get方法发送请求 ApiClient.get(url, new ApiClient.ApiCallback<DataLoader.AllDataResponse>() { @Override public void onSuccess(AllDataResponse allData) { Log.d(TAG, "数据加载成功"); parseAndAssignData(allData, callback); } @Override public void onError(int statusCode, String error) { Log.e(TAG, "数据加载失败: " + error + ", 状态码: " + statusCode); new Handler(Looper.getMainLooper()).post(callback::onFailure); } }); } private void parseAndAssignData(AllDataResponse allData, LoadDataCallback callback) { try { mergeAllLists(allData); dataAssociator.automaticAssociation(); callback.onSuccess(); } catch (Exception e) { Log.e(TAG, "数据处理异常: " + e.getMessage()); callback.onFailure(); } } private void mergeAllLists(AllDataResponse allData) { mergeList(dataStore.bancais, allData.bancais); mergeList(dataStore.caizhis, allData.caizhis); mergeList(dataStore.mupis, allData.mupis); mergeList(dataStore.chanpins, allData.chanpins); mergeList(dataStore.chanpin_zujians, allData.chanpin_zujians); mergeList(dataStore.dingdans, allData.dingdans); mergeList(dataStore.dingdan_chanpins, allData.dingdan_chanpins); mergeList(dataStore.dingdan_bancais, allData.dingdan_bancais); mergeList(dataStore.kucuns, allData.kucuns); mergeList(dataStore.zujians, allData.zujians); mergeList(dataStore.users, allData.users); mergeList(dataStore.jinhuos, allData.jinhuos); } private <T extends SynchronizableEntity> void mergeList( SynchronizedList<T> targetList, List<T> newList) { if (newList == null) return; targetList.mergeList(newList); } public interface LoadDataCallback { void onSuccess(); void onFailure(); } public static class AllDataResponse { public List<Bancai> bancais; public List<Caizhi> caizhis; public List<Mupi> mupis; public List<Chanpin> chanpins; public List<Chanpin_Zujian> chanpin_zujians; public List<Dingdan> dingdans; public List<Dingdan_Chanpin> dingdan_chanpins; public List<Dingdan_bancai> dingdan_bancais; public List<Kucun> kucuns; public List<Zujian> zujians; public List<User> users; public List<Jinhuo> jinhuos; } } package com.example.kucun2.ui.login; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.example.kucun2.DataPreserver.Data; import com.example.kucun2.MainActivity; import com.example.kucun2.R; import com.example.kucun2.entity.User; import com.example.kucun2.entity.data.ApiClient; public class LoginActivity extends AppCompatActivity { private EditText etUsername, etPassword; private CheckBox cbRemember, cbAutoLogin; private Button btnLogin; private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_loading); // 初始化视图 etUsername = findViewById(R.id.et_username); etPassword = findViewById(R.id.et_password); cbRemember = findViewById(R.id.cb_remember); cbAutoLogin = findViewById(R.id.cb_auto_login); btnLogin = findViewById(R.id.btn_login); progressBar = findViewById(R.id.progress_bar); // 设置登录按钮点击事件 btnLogin.setOnClickListener(v -> attemptLogin()); } private void attemptLogin() { String username = etUsername.getText().toString().trim(); String password = etPassword.getText().toString().trim(); if (username.isEmpty() || password.isEmpty()) { Toast.makeText(this, "用户名或密码不能为空", Toast.LENGTH_SHORT).show(); return; } // 显示进度条,禁用登录按钮 progressBar.setVisibility(View.VISIBLE); btnLogin.setEnabled(false); // 调用网络登录 ApiClient.login(username, password, new ApiClient.LoginCallback() { @Override public void onSuccess(User user) { runOnUiThread(() -> { progressBar.setVisibility(View.GONE); btnLogin.setEnabled(true); // 保存登录状态 saveLoginPreferences(username, password); // 设置当前用户 Data.setCurrentUser(user); // 跳转到主界面 startMainActivity(); }); } @Override public void onFailure(String error) { runOnUiThread(() -> { progressBar.setVisibility(View.GONE); btnLogin.setEnabled(true); Toast.makeText(LoginActivity.this, "登录失败: " + error, Toast.LENGTH_SHORT).show(); }); } }); } private void saveLoginPreferences(String username, String password) { // 在实际应用中,应使用加密方式存储密码 getSharedPreferences("login_prefs", MODE_PRIVATE).edit() .putString("username", username) .putString("password", password) .putBoolean("remember", cbRemember.isChecked()) .putBoolean("auto_login", cbAutoLogin.isChecked()) .apply(); } private void startMainActivity() { Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); // 关闭登录界面 } } ------------------------登录和获取初始数据的时候一点问题没有,只有通过基类传递时出错了------------------------------------ java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.example.kucun2.entity.data.SynchronizableEntity at com.example.kucun2.entity.data.SynchronizableEntity$1.onSuccess(SynchronizableEntity.java:56)
06-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值