package com.example.labmemotest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import android.Manifest;
import android.content.ActivityNotFoundException;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.example.labmemotest.bean.CustomOption;
import com.example.labmemotest.db.labDbHelper;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class AddInfoActivity extends AppCompatActivity {
private EditText edit_title, edit_content, edit_location;
private Button btn_camera, btn_photo, btn_save;
private LinearLayout previewContainer;
private String tmp_path;
private labDbHelper mhelper;
private SQLiteDatabase db;
private List<String> imagePaths = new ArrayList<>();
private Handler handler = new Handler(Looper.getMainLooper());
private ActivityResultLauncher<Intent> cameraLauncher;
private ActivityResultLauncher<Intent> galleryLauncher;
private static final int CAMERA_PERMISSION_CODE = 100;
private static final int GALLERY_PERMISSION_CODE = 200;
private LinearLayout containerPrefixGroups;
private List<Spinner> spinners = new ArrayList<>();
private String currentUserId = "USER001"; // 应从登录系统获取
//新增,修改
private Executor executor = Executors.newSingleThreadExecutor(); // 添加线程池
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_info);
// 修复初始化顺序
initView(); // 先初始化视图
initDb(); // 再初始化数据库
initLaunchers(); // 初始化结果启动器
loadCustomIdSelectors(); // 最后加载选择器
btnOnClick(); // 设置按钮监听
}
private void initLaunchers() {
cameraLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
File imgFile = new File(tmp_path);
if (imgFile.exists()) {
try {
Uri imageUri = FileProvider.getUriForFile(
this,
getPackageName() + ".fileprovider",
imgFile
);
// 添加持久化权限
grantPersistablePermission(imageUri);
imagePaths.add(imageUri.toString());
updateImagePreviews();
} catch (Exception e) {
Toast.makeText(this, "URI转换失败: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(this, "拍摄的图片未保存", Toast.LENGTH_LONG).show();
}
} else if (result.getResultCode() == RESULT_CANCELED) {
// 删除临时文件
new File(tmp_path).delete();
}
}
);
galleryLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
Intent data = result.getData();
try {
if (data.getClipData() != null) {
int count = data.getClipData().getItemCount();
for (int i = 0; i < count; i++) {
Uri uri = data.getClipData().getItemAt(i).getUri();
// 添加持久化权限
grantPersistablePermission(uri);
imagePaths.add(uri.toString());
}
} else if (data.getData() != null) {
Uri uri = data.getData();
grantPersistablePermission(uri);
imagePaths.add(uri.toString());
}
updateImagePreviews();
} catch (Exception e) {
Log.e("GalleryError", "相册选择失败", e);
Toast.makeText(this, "图片选择失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
);
}
// 统一处理持久化权限授予
private void grantPersistablePermission(Uri uri) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 获取持久化URI权限
getContentResolver().takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
} else {
// 旧版本使用临时权限
grantUriPermission(
getPackageName(),
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
}
// 显式添加URI权限(双重保障)
grantUriPermission(
getPackageName(),
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
} catch (SecurityException e) {
Log.e("PermissionError", "权限授予失败: " + uri, e);
Toast.makeText(this, "权限获取失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void initView() {
edit_title = findViewById(R.id.editText_title);
edit_content = findViewById(R.id.editText_content);
edit_location = findViewById(R.id.editText_location);
btn_camera = findViewById(R.id.button_camera);
btn_photo = findViewById(R.id.button_photo);
btn_save = findViewById(R.id.button_save);
previewContainer = findViewById(R.id.image_preview_container);
// ... 原有 findViewById ...
containerPrefixGroups = findViewById(R.id.container_prefix_groups);
// loadCustomIdSelectors(); // 加载编号选择器
}
// private void initDb() {
// try {
// mhelper = new labDbHelper(AddInfoActivity.this);
// db = mhelper.getWritableDatabase();
// } catch (Exception e) {
// Log.e("DbInitError", "数据库初始化失败", e);
// Toast.makeText(this, "数据库初始化失败", Toast.LENGTH_SHORT).show();
// }
// }
private void btnOnClick() {
btn_camera.setOnClickListener(v -> checkCameraPermission());
btn_photo.setOnClickListener(v -> checkGalleryPermission());
btn_save.setOnClickListener(v -> btnSave());
}
// 检查相机权限兼容Android各个版本
private void checkCameraPermission() {
List<String> permissionsNeeded = new ArrayList<>();
// 1. 相机权限是必须的
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.CAMERA);
}
// 2. 根据Android版本处理存储权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Android 13+ 需要READ_MEDIA_IMAGES权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.READ_MEDIA_IMAGES);
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// Android 10-12 不需要额外权限(使用分区存储)
} else {
// Android 9及以下需要WRITE_EXTERNAL_STORAGE权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
}
if (permissionsNeeded.isEmpty()) {
openCamera();
} else {
ActivityCompat.requestPermissions(
this,
permissionsNeeded.toArray(new String[0]),
CAMERA_PERMISSION_CODE
);
}
}
// 检查相册权限兼容Android各个版本
private void checkGalleryPermission() {
List<String> permissionsNeeded = new ArrayList<>();
// 根据Android版本处理读取权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Android 13+ 需要READ_MEDIA_IMAGES权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.READ_MEDIA_IMAGES);
}
} else {
// Android 12及以下需要READ_EXTERNAL_STORAGE权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
}
if (permissionsNeeded.isEmpty()) {
openGallery();
} else {
ActivityCompat.requestPermissions(
this,
permissionsNeeded.toArray(new String[0]),
GALLERY_PERMISSION_CODE
);
}
}
// 打开相机并创建临时文件
private void openCamera() {
try {
// 确保图片目录存在
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (storageDir == null) {
Toast.makeText(this, "无法访问存储空间", Toast.LENGTH_SHORT).show();
return;
}
if (!storageDir.exists() && !storageDir.mkdirs()) {
Toast.makeText(this, "无法创建图片目录", Toast.LENGTH_SHORT).show();
return;
}
// 创建带时间戳的唯一文件名
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
String imageFileName = "JPEG_" + timeStamp + ".jpg";
File imageFile = new File(storageDir, imageFileName);
tmp_path = imageFile.getAbsolutePath();
// 创建FileProvider URI
Uri photoURI = FileProvider.getUriForFile(
this,
getPackageName() + ".fileprovider",
imageFile
);
// 启动相机Intent
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
takePictureIntent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
);
// 确保有相机应用可以处理该Intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
cameraLauncher.launch(takePictureIntent);
} else {
Toast.makeText(this, "未找到相机应用", Toast.LENGTH_SHORT).show();
}
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "未找到相机应用", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e("CameraError", "相机启动失败", e);
Toast.makeText(this, "相机启动失败: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
// 打开相册选择图片
private void openGallery() {
try {
Intent galleryIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
galleryIntent.addCategory(Intent.CATEGORY_OPENABLE);
galleryIntent.setType("image/*");
galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
// 添加权限Flag确保可以获取持久化权限
galleryIntent.addFlags(
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
galleryLauncher.launch(galleryIntent);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "未找到图库应用", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e("GalleryError", "图库打开失败", e);
Toast.makeText(this, "图库打开失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
// 更新图片预览区域
private void updateImagePreviews() {
previewContainer.removeAllViews();
for (String uriString : imagePaths) {
try {
Uri uri = Uri.parse(uriString);
// 创建图片预览视图
ImageView imageView = new ImageView(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
300, 300
);
params.setMargins(8, 8, 8, 8);
imageView.setLayoutParams(params);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setBackgroundColor(Color.parseColor("#F5F5F5"));
// 使用Glide加载图片
Glide.with(this)
.load(uri)
.placeholder(R.drawable.ic_default_image)
.error(R.drawable.ic_error_image)
.into(imageView);
previewContainer.addView(imageView);
} catch (Exception e) {
Log.e("PreviewError", "图片预览失败: " + uriString, e);
Toast.makeText(this, "图片预览失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
// 修复1:确保在UI线程操作视图
private void loadCustomIdSelectors() {
// 确保在主线程操作UI
runOnUiThread(() -> {
try {
// 安全移除视图
if (containerPrefixGroups != null) {
containerPrefixGroups.removeAllViews();
}
spinners.clear();
// 检查数据库可用性
if (db == null || !db.isOpen()) {
Log.e("LoadSelector", "数据库不可用");
return;
}
// 使用线程池执行数据库查询
executor.execute(() -> {
Cursor cursor = null;
try {
cursor = db.rawQuery(
"SELECT group_id, option_index, display_text, code_char " +
"FROM tb_custom_config WHERE user_id=? ORDER BY group_id",
new String[]{currentUserId}
);
final Map<Integer, List<CustomOption>> groupsMap = new LinkedHashMap<>();
while (cursor != null && cursor.moveToNext()) {
int groupId = cursor.getInt(0);
int optionIdx = cursor.getInt(1);
String text = cursor.getString(2);
String code = cursor.getString(3);
groupsMap.computeIfAbsent(groupId, k -> new ArrayList<>())
.add(new CustomOption(currentUserId, groupId, optionIdx, text, code));
}
// 回到主线程更新UI
runOnUiThread(() -> {
if (groupsMap.isEmpty()) {
View selectorLayout = findViewById(R.id.layout_id_selection);
if (selectorLayout != null) {
selectorLayout.setVisibility(View.GONE);
}
return;
}
for (List<CustomOption> options : groupsMap.values()) {
addSpinnerForGroup(options);
}
});
} catch (Exception e) {
Log.e("LoadSelector", "查询失败", e);
} finally {
if (cursor != null) {
cursor.close();
}
}
});
} catch (Exception e) {
Log.e("LoadSelector", "初始化失败", e);
}
});
}
// 修复2:增强异常处理
private void addSpinnerForGroup(List<CustomOption> options) {
try {
LinearLayout row = new LinearLayout(this);
row.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
120));
row.setOrientation(LinearLayout.HORIZONTAL);
row.setPadding(0, 0, 0, 8);
Spinner spinner = new Spinner(this);
spinner.setLayoutParams(new LinearLayout.LayoutParams(0, 100, 1f));
spinner.setPadding(16, 0, 16, 0);
ArrayAdapter<CustomOption> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_spinner_item, options);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinners.add(spinner);
row.addView(spinner);
// 安全添加视图
if (containerPrefixGroups != null) {
containerPrefixGroups.addView(row);
}
} catch (Exception e) {
Log.e("AddSpinner", "创建选择器失败", e);
}
}
// 生成唯一备忘录ID
// private String generateUniqueMemoId() {
// if (db == null || !db.isOpen()) {
// initDb();
// }
//
// if (db == null) {
// Toast.makeText(this, "数据库不可用", Toast.LENGTH_SHORT).show();
// return "";
// }
//
// Random random = new Random();
// String memoId;
// int attempts = 0;
// boolean idExists;
//
// do {
// // 生成9位随机数
// memoId = String.valueOf(100000000 + random.nextInt(900000000));
// idExists = false;
//
//
//
//
// try {
// // 检查ID是否已存在
// Cursor cursor = db.query(
// "tb_memory",
// new String[]{"memo_id"},
// "memo_id = ?",
// new String[]{memoId},
// null, null, null
// );
// idExists = cursor.getCount() > 0;
// cursor.close();
// } catch (Exception e) {
// Log.e("GenerateIdError", "ID检查失败", e);
// Toast.makeText(this, "ID检查失败", Toast.LENGTH_SHORT).show();
// return "";
// }
//
// attempts++;
// // 防止无限循环
// if (attempts > 100) {
// Toast.makeText(this, "无法生成唯一ID", Toast.LENGTH_SHORT).show();
// return "";
// }
// } while (idExists);
//
// return memoId;
// }
// 替换原有的 generateUniqueMemoId()
// String uniqueMemoId = generateMemoIdFromSelection();
// 修复3:增强ID生成稳定性
private String generateMemoIdFromSelection() {
try {
StringBuilder prefix = new StringBuilder();
if (spinners == null || spinners.isEmpty()) {
return "X" + String.format(Locale.getDefault(), "%05d", new Random().nextInt(100000));
}
for (Spinner spinner : spinners) {
if (spinner == null) continue;
Object selected = spinner.getSelectedItem();
if (selected instanceof CustomOption) {
CustomOption option = (CustomOption) selected;
if (option.codeChar != null) {
prefix.append(option.codeChar);
}
}
}
if (prefix.length() == 0) prefix.append("X");
String suffix = String.format(Locale.getDefault(), "%05d", new Random().nextInt(100000));
return prefix.toString() + suffix;
} catch (Exception e) {
Log.e("GenID", "生成ID失败", e);
return "ERR" + System.currentTimeMillis();
}
}
// 修复4:增强数据库操作安全性
private void initDb() {
executor.execute(() -> {
try {
mhelper = new labDbHelper(AddInfoActivity.this);
db = mhelper.getWritableDatabase();
} catch (Exception e) {
Log.e("DbInit", "数据库初始化失败", e);
runOnUiThread(() ->
Toast.makeText(this, "数据库初始化失败", Toast.LENGTH_SHORT).show());
}
});
}
// 保存按钮点击事件
private void btnSave() {
String title = edit_title.getText().toString().trim();
String content = edit_content.getText().toString().trim();
String location = edit_location.getText().toString().trim();
String uniqueMemoId = generateMemoIdFromSelection(); // ✅ 正确位置
if (uniqueMemoId.isEmpty()) {
Toast.makeText(this, "无法生成有效ID", Toast.LENGTH_SHORT).show();
return;
}
// 验证输入
if (title.isEmpty()) {
Toast.makeText(this, "请输入标题", Toast.LENGTH_SHORT).show();
return;
}
// 确保数据库可用
if (db == null || !db.isOpen()) {
initDb();
if (db == null || !db.isOpen()) {
Toast.makeText(this, "数据库未准备好", Toast.LENGTH_SHORT).show();
return;
}
}
try {
// 格式化当前时间
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm", Locale.getDefault());
String mtime = sdf.format(date);
// 插入主备忘录数据
ContentValues memoryValues = new ContentValues();
memoryValues.put("memo_id", uniqueMemoId);
memoryValues.put("title", title);
memoryValues.put("content", content);
memoryValues.put("location", location);
memoryValues.put("mtime", mtime);
long insertResult = db.insert("tb_memory", null, memoryValues);
if (insertResult != -1) {
// 插入关联图片
for (String imagePath : imagePaths) {
ContentValues imageValues = new ContentValues();
imageValues.put("memo_id", uniqueMemoId);
imageValues.put("imgpath", imagePath);
db.insert("tb_image", null, imageValues);
}
Toast.makeText(this, "保存成功,包含 " + imagePaths.size() + " 张图片", Toast.LENGTH_SHORT).show();
// 延迟1秒后返回主页面
handler.postDelayed(() -> {
startActivity(new Intent(AddInfoActivity.this, MainActivity.class));
finish();
}, 1000);
} else {
Toast.makeText(this, "保存失败,请重试", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e("SaveError", "保存失败", e);
Toast.makeText(this, "保存失败: " + e.getMessage(), Toast.LENGTH_LONG).show();
} finally {
// 确保关闭数据库
if (db != null && db.isOpen()) {
try {
db.close();
} catch (Exception e) {
Log.e("DbClose", "数据库关闭失败", e);
}
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_CODE) {
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
openCamera();
} else {
Toast.makeText(this, "需要所有权限才能使用相机", Toast.LENGTH_SHORT).show();
}
}
else if (requestCode == GALLERY_PERMISSION_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openGallery();
} else {
Toast.makeText(this, "需要权限才能访问相册", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
goBackToMain();
}
@Override
protected void onDestroy() {
super.onDestroy();
// 清理资源
if (db != null && db.isOpen()) {
try {
db.close();
} catch (Exception e) {
Log.e("DestroyError", "数据库关闭失败", e);
}
}
}
private void goBackToMain() {
startActivity(new Intent(AddInfoActivity.this, MainActivity.class));
finish();
}
}
// 文件路径:com/example/labmemotest/SetupCustomIdActivity.java 用途:让用户首次或随时设置自定义编号组(最多6组,每组0-9项)
package com.example.labmemotest;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.labmemotest.db.labDbHelper;
public class SetupCustomIdActivity extends AppCompatActivity {
private EditText[][] inputs = new EditText[6][10];
private Button btnSave;
private labDbHelper dbHelper;
private SQLiteDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_custom_id);
dbHelper = new labDbHelper(this);
db = dbHelper.getWritableDatabase();
loadInputFields();
btnSave = findViewById(R.id.btn_save_config);
btnSave.setOnClickListener(v -> saveConfiguration());
}
private void loadInputFields() {
int[] groupLayoutIds = {
R.id.group1, R.id.group2, R.id.group3,
R.id.group4, R.id.group5, R.id.group6
};
for (int g = 0; g < 6; g++) {
LinearLayout groupLayout = findViewById(groupLayoutIds[g]);
for (int i = 0; i < 10; i++) {
EditText et = new EditText(this);
et.setHint("选项 " + i);
et.setTextSize(14);
et.setPadding(8, 8, 8, 8);
et.setTag("input_" + g + "_" + i);
groupLayout.addView(et);
inputs[g][i] = et;
}
}
}
private void saveConfiguration() {
String userId = getCurrentUserId(); // 如从 SharedPreferences 获取
if (TextUtils.isEmpty(userId)) userId = "default_user";
db.delete("tb_custom_config", "user_id=?", new String[]{userId});
boolean hasValidGroup = false;
for (int g = 0; g < 6; g++) {
boolean hasAny = false;
for (int i = 0; i < 10; i++) {
String text = inputs[g][i].getText().toString().trim();
if (!text.isEmpty()) {
String codeChar = String.valueOf((char) ('A' + (g * 10 + i) % 26)); // 自动分配字母
insertOption(userId, g + 1, i, text, codeChar);
hasAny = true;
}
}
if (hasAny) hasValidGroup = true;
}
if (!hasValidGroup) {
Toast.makeText(this, "至少填写一组编号!", Toast.LENGTH_SHORT).show();
return;
}
Toast.makeText(this, "配置保存成功!", Toast.LENGTH_SHORT).show();
finish();
}
private void insertOption(String userId, int groupId, int optionIndex, String displayText, String codeChar) {
db.execSQL("INSERT INTO tb_custom_config(user_id,group_id,option_index,display_text,code_char) VALUES(?,?,?,?,?)",
new Object[]{userId, groupId, optionIndex, displayText, codeChar});
}
private String getCurrentUserId() {
// TODO: 可从 SharedPreferences 或登录状态获取真实用户ID
return "USER001";
}
@Override
protected void onDestroy() {
super.onDestroy();
if (db != null && db.isOpen()) db.close();
if (dbHelper != null) dbHelper.close();
}
}
package com.example.labmemotest;
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.Toast;
import androidx.appcompat.app.AppCompatActivity;
//登录页面注册页面
public class LoginActivity extends AppCompatActivity {
// 定义对象
private EditText edit_inputname, edit_inputpwd;
private CheckBox check_reme;
private Button btn_login, btn_cancel, btn_register; // 新增:取消、注册按钮
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// 1. 绑定控件(新增取消、注册按钮)
initView();
// 新增:检查注册状态,控制注册按钮显示/隐藏
checkRegistrationStatus();
// 2. 绑定按钮点击事件(新增取消、注册按钮逻辑)
initClick();
// 3. 下次启动,直接显示记住的账号(原逻辑保留,修改为“显示账号”)
displayRememberedAccount();
}
// 1. 绑定控件(新增取消、注册按钮)
private void initView() {
edit_inputname = findViewById(R.id.editText_inputname);
edit_inputpwd = findViewById(R.id.editText_inputpwd);
check_reme = findViewById(R.id.checkBox_reme);
btn_login = findViewById(R.id.button_login);
btn_cancel = findViewById(R.id.button_cancel); // 绑定取消按钮
btn_register = findViewById(R.id.button_register); // 绑定注册按钮
}
// 新增:检查注册状态,控制注册按钮显示/隐藏
private void checkRegistrationStatus() {
SharedPreferences sp = getSharedPreferences("UserData", MODE_PRIVATE);
// 判断是否已有用户注册
boolean hasRegistered = sp.getBoolean("HAS_REGISTERED", false);
if (hasRegistered) {
// 已有用户注册,隐藏注册按钮
btn_register.setVisibility(View.GONE);
} else {
// 未注册,显示注册按钮
btn_register.setVisibility(View.VISIBLE);
}
}
// 2. 绑定按钮点击事件(整合原有登录逻辑,新增取消、注册)
private void initClick() {
// 取消按钮:清空输入
btn_cancel.setOnClickListener(v -> {
edit_inputname.setText("");
edit_inputpwd.setText("");
});
// 注册按钮:跳转到注册页
btn_register.setOnClickListener(v -> {
Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
startActivity(intent);
});
// 原有登录按钮逻辑:新增密码验证
btn_login.setOnClickListener(v -> {
String username = edit_inputname.getText().toString().trim();
String inputPwd = edit_inputpwd.getText().toString().trim();
// 1. 校验输入不为空
if (username.isEmpty()) {
Toast.makeText(LoginActivity.this, "请输入账号", Toast.LENGTH_SHORT).show();
return;
}
if (inputPwd.isEmpty()) {
Toast.makeText(LoginActivity.this, "请输入密码", Toast.LENGTH_SHORT).show();
return;
}
// 2. 从SharedPreferences读取已注册的密码
SharedPreferences sp = getSharedPreferences("UserData", MODE_PRIVATE);
String savedPwd = sp.getString("USER_" + username, null);
// 3. 验证账号是否存在
if (savedPwd == null) {
Toast.makeText(LoginActivity.this, "该账号未注册", Toast.LENGTH_SHORT).show();
return;
}
// 4. 验证密码是否正确
if (!savedPwd.equals(inputPwd)) {
Toast.makeText(LoginActivity.this, "密码不正确,无法登录", Toast.LENGTH_SHORT).show();
edit_inputpwd.setText(""); // 清空错误密码
return;
}
// 5. 登录成功:保存“记住账号”状态
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("REMEMBER_ACCOUNT", check_reme.isChecked()); // 是否记住账号
editor.putString("LAST_ACCOUNT", username); // 记录上次登录的账号
editor.apply();
// 跳转到MainActivity
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish(); // 关闭登录页,避免返回
});
}
// 下次启动,直接显示记住的账号(不自动填充密码)
private void displayRememberedAccount() {
SharedPreferences sp = getSharedPreferences("UserData", MODE_PRIVATE);
boolean isRemember = sp.getBoolean("REMEMBER_ACCOUNT", false);
String lastAccount = sp.getString("LAST_ACCOUNT", "");
if (isRemember && !lastAccount.isEmpty()) {
edit_inputname.setText(lastAccount); // 只填充账号
check_reme.setChecked(true);
} else {
edit_inputname.setText("");
check_reme.setChecked(false);
}
edit_inputpwd.setText(""); // 密码每次都清空,需用户输入
}
// 从注册页面返回时重新检查注册状态
@Override
protected void onResume() {
super.onResume();
checkRegistrationStatus();
}
}
package com.example.labmemotest.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
//数据库
public class labDbHelper extends SQLiteOpenHelper {
// 定义数据库名、版本号
private static final String DBNAME = "zsmemo.db";
private static final int VERSION = 3; // 版本号从2升级到3,支持多图存储
private static final String TAG = "labDbHelper";
public labDbHelper(Context context) {
super(context, DBNAME, null, VERSION);
}
// 创建数据库(仅首次安装时执行)
@Override
public void onCreate(SQLiteDatabase db) {
// 启用外键约束(关键:SQLite默认关闭外键约束)
db.execSQL("PRAGMA foreign_keys = ON;");
// 1. 日志表(移除imgpath字段)
String createMemoryTable = "CREATE TABLE tb_memory (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"memo_id TEXT unique," +
"title TEXT, " +
"content TEXT, " +
"location TEXT," +
"mtime TEXT)"; // 已移除原imgpath字段
// 2. 新增图片表(存储多图,关联日志表的memo_id)
String createImageTable = "CREATE TABLE tb_image (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"memo_id TEXT, " +
"imgpath TEXT, " +
"FOREIGN KEY(memo_id) REFERENCES tb_memory(memo_id))";
// 在 onCreate 方法内追加:添加新表 TB_CUSTOM_CONFIG用于储存自定义数据与编号
String createConfigTable = "CREATE TABLE tb_custom_config (" +
"user_id TEXT NOT NULL," +
"group_id INTEGER NOT NULL," +
"option_index INTEGER NOT NULL," +
"display_text TEXT," +
"code_char TEXT," +
"PRIMARY KEY (user_id, group_id, option_index)" +
")";
db.execSQL(createConfigTable);
try {
db.execSQL(createMemoryTable);
db.execSQL(createImageTable);
Log.d(TAG, "日志表和图片表创建成功");
} catch (Exception e) {
Log.e(TAG, "创建表失败:" + e.getMessage(), e);
// 移除强制崩溃的代码,改为友好处理
Log.e(TAG, "数据库初始化失败,应用可能无法正常工作", e);
}
}
// 升级数据库(版本号提升时执行)
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 升级时启用外键约束
db.execSQL("PRAGMA foreign_keys = ON;");
// 处理版本2升级到3的情况(支持多图存储)
if (oldVersion < 4) {
try {
// 兼容低版本SQLite,使用临时表迁移方式移除imgpath字段
// 1. 创建临时表(不含imgpath字段)
db.execSQL("CREATE TABLE tb_memory_temp (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"memo_id TEXT unique," +
"title TEXT, " +
"content TEXT, " +
"location TEXT," +
"mtime TEXT)");
// 2. 迁移旧表数据(排除imgpath字段)
db.execSQL("INSERT INTO tb_memory_temp " +
"(_id, memo_id, title, content, location, mtime) " +
"SELECT _id, memo_id, title, content, location, mtime FROM tb_memory");
// 3. 删除旧表
db.execSQL("DROP TABLE tb_memory");
// 4. 重命名临时表为正式表
db.execSQL("ALTER TABLE tb_memory_temp RENAME TO tb_memory");
// 5. 创建图片表
db.execSQL("CREATE TABLE tb_image (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"memo_id TEXT, " +
"imgpath TEXT, " +
"FOREIGN KEY(memo_id) REFERENCES tb_memory(memo_id))");
// 在 if(oldVersion < 3) 块中升级后添加:新建自定义数据与编号表
db.execSQL("CREATE TABLE IF NOT EXISTS tb_custom_config (...)");
Log.d(TAG, "数据库升级到版本3,支持多图存储");
} catch (Exception e) {
Log.e(TAG, "数据库升级失败:" + e.getMessage(), e);
}
}
}
}
// 文件路径:com/example/labmemotest/bean/CustomOption.java 用途:封装编号选项实体
package com.example.labmemotest.bean;
public class CustomOption {
public String userId;
public int groupId;
public int optionIndex;
public String displayText;
public String codeChar;
public CustomOption(String userId, int groupId, int optionIndex, String displayText, String codeChar) {
this.userId = userId;
this.groupId = groupId;
this.optionIndex = optionIndex;
this.displayText = displayText;
this.codeChar = codeChar;
}
@Override
public String toString() {
return optionIndex + ": " + displayText + " (" + codeChar + ")";
}
}
package com.example.labmemotest.adapter;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.example.labmemotest.DetailActivity;
import com.example.labmemotest.R;
import com.example.labmemotest.bean.MemoBean;
import com.example.labmemotest.db.labDbHelper;
import java.util.List;
import java.util.Random;
public class MemoAdapter extends RecyclerView.Adapter<MemoAdapter.ViewHolder> {
private Context mcontext;
private List<MemoBean> arr1;
// 移除类级别的数据库变量,改为在使用时局部声明
private static final int MAX_TITLE_LENGTH = 10;
private static final int MAX_CONTENT_LENGTH = 8;
private static final int COLOR_MIN = 180;
private static final int COLOR_MAX = 255;
public MemoAdapter(Context mcontext, List<MemoBean> arr1) {
this.mcontext = mcontext;
this.arr1 = arr1;
}
@NonNull
@Override
public MemoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mcontext).inflate(R.layout.recy_item, parent, false);
return new ViewHolder(view);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onBindViewHolder(@NonNull MemoAdapter.ViewHolder holder, int position) {
// 增加空数据判断,避免数组越界
if (arr1 == null || position >= arr1.size()) {
return;
}
final MemoBean memoBean = arr1.get(position);
// 防止memoBean为空导致的空指针
if (memoBean == null) {
return;
}
// 显示编号(增加非空判断)
holder.item_memo_id.setText("编号:" + (memoBean.getMemoId() != null ? memoBean.getMemoId() : "未知"));
// 处理标题长度
String title = memoBean.getTitle();
if (title == null) title = ""; // 防止空指针
if (title.length() > MAX_TITLE_LENGTH) {
title = title.substring(0, MAX_TITLE_LENGTH) + "...";
}
holder.item_title.setText(title);
// 处理内容显示
String content = memoBean.getContent();
if (content == null) content = ""; // 防止空指针
if (content.length() > MAX_CONTENT_LENGTH) {
content = content.substring(0, MAX_CONTENT_LENGTH) + "...";
}
holder.item_content.setText(content);
// 处理时间显示
String time = memoBean.getTime();
holder.item_time.setText(time != null ? time : "");
// 处理位置信息
String location = memoBean.getLocation();
if (location != null && !location.isEmpty()) {
holder.item_location.setText("位置:" + location);
} else {
holder.item_location.setText("地点:无");
}
holder.item_location.setVisibility(View.VISIBLE);
// 从tb_image表查询对应memo_id的第一张图片
// 使用局部变量处理数据库操作,避免多线程问题
labDbHelper dbHelper = new labDbHelper(mcontext);
SQLiteDatabase db = null;
Cursor cursor = null;
try {
db = dbHelper.getReadableDatabase();
// 确保memoId不为空
if (memoBean.getMemoId() != null) {
cursor = db.query(
"tb_image",
new String[]{"imgpath"},
"memo_id = ?",
new String[]{memoBean.getMemoId()},
null, null, null, "1"
);
if (cursor != null && cursor.moveToFirst()) {
String firstImgPath = cursor.getString(0);
if (firstImgPath != null && !firstImgPath.isEmpty()) {
// 加载图片
Glide.with(mcontext)
.load(Uri.parse(firstImgPath))
.error(R.drawable.ic_default_image)
.placeholder(R.drawable.ic_default_image) // 新增占位图
.into(holder.item_img);
} else {
holder.item_img.setImageResource(R.drawable.ic_default_image);
}
} else {
holder.item_img.setImageResource(R.drawable.ic_default_image);
}
} else {
holder.item_img.setImageResource(R.drawable.ic_default_image);
}
} catch (Exception e) {
Log.e("MemoAdapter", "图片加载失败", e);
holder.item_img.setImageResource(R.drawable.ic_default_image);
} finally {
// 确保资源关闭
if (cursor != null) {
try {
cursor.close();
} catch (Exception e) {
Log.e("MemoAdapter", "关闭cursor失败", e);
}
}
if (db != null && db.isOpen()) {
try {
db.close();
} catch (Exception e) {
Log.e("MemoAdapter", "关闭数据库失败", e);
}
}
}
// 设置背景颜色和形状
Random random = new Random();
int red = COLOR_MIN + random.nextInt(COLOR_MAX - COLOR_MIN);
int green = COLOR_MIN + random.nextInt(COLOR_MAX - COLOR_MIN);
int blue = COLOR_MIN + random.nextInt(COLOR_MAX - COLOR_MIN);
int color = Color.argb(200, red, green, blue);
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setShape(GradientDrawable.RECTANGLE);
gradientDrawable.setCornerRadius(10f);
gradientDrawable.setColor(color);
gradientDrawable.setStroke(2, Color.argb(50, 0, 0, 0));
holder.item_layout.setBackground(gradientDrawable);
// 子项点击事件 - 跳转到详情页
holder.item_layout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ScaleAnimation scaleAnim = new ScaleAnimation(
1.0f, 0.95f, 1.0f, 0.95f,
v.getWidth() / 2, v.getHeight() / 2);
scaleAnim.setDuration(100);
v.startAnimation(scaleAnim);
Intent intent = new Intent(mcontext, DetailActivity.class);
Bundle bundle = new Bundle();
bundle.putString("title", memoBean.getTitle());
bundle.putString("content", memoBean.getContent());
bundle.putString("time", memoBean.getTime());
bundle.putString("memo_id", memoBean.getMemoId());
bundle.putString("location", memoBean.getLocation());
intent.putExtras(bundle);
mcontext.startActivity(intent);
}
});
// 长按事件 - 删除功能
holder.item_layout.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
new AlertDialog.Builder(mcontext)
.setMessage("确定删除吗?")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int which) {
// 使用局部变量处理数据库
labDbHelper deleteHelper = new labDbHelper(mcontext);
SQLiteDatabase deleteDb = null;
try {
deleteDb = deleteHelper.getWritableDatabase();
int pos = holder.getAdapterPosition();
if (pos != RecyclerView.NO_POSITION && arr1.get(pos) != null
&& arr1.get(pos).getMemoId() != null) {
// 删除主表记录
deleteDb.delete("tb_memory",
"memo_id = ?",
new String[]{arr1.get(pos).getMemoId()});
// 删除关联图片
deleteDb.delete("tb_image",
"memo_id = ?",
new String[]{arr1.get(pos).getMemoId()});
// 更新列表
arr1.remove(pos);
notifyItemRemoved(pos);
notifyItemRangeChanged(pos, arr1.size());
}
} catch (Exception e) {
Log.e("MemoAdapter", "删除失败", e);
} finally {
if (deleteDb != null && deleteDb.isOpen()) {
try {
deleteDb.close();
} catch (Exception e) {
Log.e("MemoAdapter", "关闭数据库失败", e);
}
}
}
dialogInterface.dismiss();
}
})
.setNegativeButton("取消", null)
.setCancelable(false)
.show();
return true;
}
});
}
@Override
public int getItemCount() {
return arr1 == null ? 0 : arr1.size(); // 防止空指针
}
public boolean isEmpty() {
return arr1 == null || arr1.isEmpty();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView item_title, item_content, item_time, item_memo_id, item_location;
ImageView item_img;
LinearLayout item_layout;
public ViewHolder(@NonNull View itemView) {
super(itemView);
// 增加控件绑定的空判断
item_memo_id = itemView.findViewById(R.id.item_memo_id);
item_title = itemView.findViewById(R.id.item_title);
item_content = itemView.findViewById(R.id.item_content);
item_img = itemView.findViewById(R.id.item_image);
item_location = itemView.findViewById(R.id.item_location);
item_time = itemView.findViewById(R.id.item_time);
item_layout = itemView.findViewById(R.id.item_layout);
}
}
}
package com.example.labmemotest.bean;
public class MemoBean {
private String memoId; // 9位随机编号(memo_id)
private String title; // 备忘录标题
private String content; // 备忘录内容
private String location; // 备忘录地点
private String time; // 时间
// 构造方法(移除imgpath参数)
public MemoBean(String title, String content, String time, String location, String memoId) {
this.title = title;
this.content = content;
this.time = time;
this.location = location;
this.memoId = memoId;
}
// Getter和Setter方法(移除imgpath相关)
public String getMemoId() {
return memoId;
}
public void setMemoId(String memoId) {
this.memoId = memoId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
<?xml version = "1.0" encoding = "utf-8"?>
<LinearLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:tools = "http://schemas.android.com/tools"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:orientation = "vertical"
android:background = "@drawable/bgthree"
android:padding = "15dp"
tools:context = ".AddInfoActivity">
<LinearLayout
android:id="@+id/layout_id_selection"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:padding="5dp"
android:background="@drawable/edittext_bg"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择编号前缀"
android:textSize="12sp"
android:textStyle="bold"
android:textColor="#999999"
android:layout_marginBottom="6dp" />
<LinearLayout
android:id="@+id/container_prefix_groups"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
<EditText
android:id = "@+id/editText_title"
android:layout_width = "match_parent"
android:layout_height = "60dp"
android:layout_marginBottom = "12dp"
android:hint = "标题"
android:textStyle = "bold"
android:textColor = "#000000"
android:textSize = "22sp"
android:background = "@drawable/edittext_bg"
android:paddingHorizontal = "12dp"
android:paddingVertical = "8dp"
android:maxLines = "1"
android:singleLine = "true"/>
<EditText
android:id = "@+id/editText_content"
android:layout_width = "match_parent"
android:layout_height = "0dp"
android:layout_weight = "1"
android:layout_marginBottom = "12dp"
android:hint = "内容"
android:textStyle = "bold"
android:textColor = "#000000"
android:textSize = "18sp"
android:gravity = "top"
android:background = "@drawable/edittext_bg"
android:paddingHorizontal = "12dp"
android:paddingVertical = "10dp"
android:minLines = "3" />
<EditText
android:id = "@+id/editText_location"
android:layout_width = "match_parent"
android:layout_height = "50dp"
android:layout_marginBottom = "12dp"
android:hint = "地点(可选)尽可能详细"
android:textStyle = "bold"
android:textColor = "#000000"
android:textSize = "18sp"
android:background = "@drawable/edittext_bg"
android:paddingHorizontal = "12dp"
android:paddingVertical = "8dp"
android:maxLines = "1"
android:singleLine = "true"
android:inputType = "textPostalAddress" />
<TextView
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_marginBottom = "8dp"
android:text = "请选用下面的任一种方式,添加图片:"
android:textStyle = "bold"
android:textColor = "#333333"
android:textSize = "16sp"
android:gravity = "start" />
<LinearLayout
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_marginBottom = "12dp"
android:orientation = "horizontal"
android:gravity = "center">
<Button
android:id = "@+id/button_camera"
android:layout_width = "0dp"
android:layout_height = "50dp"
android:layout_weight = "1"
android:layout_marginRight = "10dp"
android:text = "拍照"
android:textStyle = "bold"
android:background = "@drawable/btnstyle"
android:textColor = "#000000"
android:textSize = "16sp"
android:paddingHorizontal = "8dp" />
<Button
android:id = "@+id/button_photo"
android:layout_width = "0dp"
android:layout_height = "50dp"
android:layout_weight = "1"
android:layout_marginLeft = "10dp"
android:text = "从图库中选择"
android:textStyle = "bold"
android:background = "@drawable/btnstyle"
android:textColor = "#000000"
android:textSize = "16sp"
android:paddingHorizontal = "8dp" />
</LinearLayout>
<!-- 移除原ImageView_preview,替换为水平滚动的预览容器 -->
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_marginBottom="15dp">
<LinearLayout
android:id="@+id/image_preview_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"/>
</HorizontalScrollView>
<!--<ImageView-->
<!--android:id = "@+id/imageView_preview"-->
<!--android:layout_width = "match_parent"-->
<!-- android:layout_height = "180dp"-->
<!-- android:layout_marginBottom = "15dp"-->
<!-- android:src = "@drawable/sunshine"-->
<!-- android:scaleType = "centerCrop"-->
<!-- android:background = "#F5F5F5" />-->
<Button
android:id = "@+id/button_save"
android:layout_width = "match_parent"
android:layout_height = "60dp"
android:text = "保存"
android:textStyle = "bold"
android:background = "@drawable/btnstyle"
android:textColor = "#000000"
android:textSize = "20sp"
android:paddingHorizontal = "8dp" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="设置自定义编号(最多6组)"
android:textSize="18sp"
android:textStyle="bold"
android:gravity="center"
android:padding="16dp" />
<LinearLayout
android:id="@+id/group1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="16dp"/>
<LinearLayout
android:id="@+id/group2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="16dp"/>
<LinearLayout
android:id="@+id/group3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="16dp"/>
<LinearLayout
android:id="@+id/group4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="16dp"/>
<LinearLayout
android:id="@+id/group5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="16dp"/>
<LinearLayout
android:id="@+id/group6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="16dp"/>
<Button
android:id="@+id/btn_save_config"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="保存配置"
android:textSize="18sp"
android:background="@drawable/btnstyle"
android:textColor="#000000" />
</LinearLayout>
</ScrollView>
根据以上内容,在不改变原有代码的基础上,修改完善,按照以下要求:我想重新设计一下在创建日志时生成组合编号,要求是:多组自定义编号(也就是设置几个多选,每个多选有10个选项,每个选项对应不同的内容和编号,内容是用户自定义的)+随机生成5位数编号共同组成一个memo_id。比如:我在第1次注册账号之后进入一个自定义编号的页面,设置6组自定义编号,供用户选择1组到6组均可;每组编号设置10个输入框,每个输入框对应0-9,用户可以根据自己的需要进行填写内容进行定义,填写多少个输入框就用多少个(最少填写1个,最多10个);用户最少填写1组自定义编号,最多填写6组;填写完成后点击保存后退出该页面。在创建日志时,生成的编号包括用户写日志时选择的选项加上5位随机数组合成一个完整的编号。(在main页面添加一个按钮原来跳转进入到自定义编号页面进行编辑操作,在日志创建页面只提供已经编辑好的多个选项框,用户设置了多少组自定义编号,就提供多少个选项框)