Permission 表 建表语句 ( 编号:20110621A1030 )

本文介绍如何在SQL Server中创建一个名为t_Permission的表,该表包含权限ID、组织ID、权限编号、权限名称等字段,并设置了默认的时间戳。


 

 

在 SQL Server 企业管理器中,右键单击表,选择 "编写表脚本为" > "Create 到" 。

package com.example.labmemotest; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.SearchView; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.StaggeredGridLayoutManager; import com.example.labmemotest.bean.MemoBean; import com.example.labmemotest.adapter.MemoAdapter; import com.example.labmemotest.db.labDbHelper; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private Button btn_add; private RecyclerView recy_view; private SearchView searchView; private labDbHelper mhelper; private SQLiteDatabase db; private List<MemoBean> allMemos = new ArrayList<>(); private MemoAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); btnonclicknext(); recyDisplay(); setupSearchListener(); Button btnSetup = findViewById(R.id.btn_setup_id); btnSetup.setOnClickListener(v -> { startActivity(new Intent(this, SetupCustomIdActivity.class)); }); } private void initView() { btn_add = findViewById(R.id.button_add); recy_view = findViewById(R.id.recy_view); searchView = findViewById(R.id.search_view); recy_view.setLayoutManager(new LinearLayoutManager(this)); mhelper = new labDbHelper(MainActivity.this); db = mhelper.getWritableDatabase(); } // 修复1:移除finish()调用,保留MainActivity在栈中 private void btnonclicknext() { btn_add.setOnClickListener(view -> { Intent intent = new Intent(MainActivity.this, AddInfoActivity.class); startActivity(intent); // 修复:移除 finish() 调用 }); } // 修复2:添加onResume生命周期方法,确保返回时刷新数据 @Override protected void onResume() { super.onResume(); recyDisplay(); // 每次返回MainActivity时刷新数据 } private void recyDisplay() { allMemos.clear(); Cursor cursor = db.rawQuery("select * from tb_memory", null); while (cursor.moveToNext()) { String mytitle = cursor.getString(cursor.getColumnIndex("title")); String mycontent = cursor.getString(cursor.getColumnIndex("content")); String mymtime = cursor.getString(cursor.getColumnIndex("mtime")); String mylocation = cursor.getString(cursor.getColumnIndex("location")); String mymemoId = cursor.getString(cursor.getColumnIndex("memo_id")); MemoBean memoBean = new MemoBean(mytitle, mycontent, mymtime, mylocation, mymemoId); allMemos.add(memoBean); } cursor.close(); adapter = new MemoAdapter(MainActivity.this, new ArrayList<>(allMemos)); StaggeredGridLayoutManager st = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); recy_view.setLayoutManager(st); recy_view.setAdapter(adapter); } private void setupSearchListener() { searchView.setQueryHint("搜索编号..."); searchView.setIconifiedByDefault(false); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { filterMemos(query); return true; } @Override public boolean onQueryTextChange(String newText) { filterMemos(newText); return true; } }); } private void filterMemos(String query) { List<MemoBean> filteredList = new ArrayList<>(); if (query == null || query.trim().isEmpty()) { filteredList.addAll(allMemos); } else { String lowerCaseQuery = query.toLowerCase().trim(); for (MemoBean memo : allMemos) { if (memo.getMemoId() != null && memo.getMemoId().contains(lowerCaseQuery)) { filteredList.add(memo); } } } adapter = new MemoAdapter(MainActivity.this, filteredList); recy_view.setAdapter(adapter); } } 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.TextView; 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; import androidx.appcompat.app.AlertDialog; 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 List<Spinner> optionSpinners = new ArrayList<>(); // 新增,修改 private Executor executor = Executors.newSingleThreadExecutor(); // 添加线程池 private boolean dbInitialized = false; // 跟踪数据库初始化状态 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_info); initView(); initDb(() -> { initLaunchers(); btnOnClick(); checkCustomConfig(); }); } private void checkCustomConfig() { if (!dbInitialized || db == null || !db.isOpen()) { Toast.makeText(this, "数据库未准备好", Toast.LENGTH_SHORT).show(); return; } executor.execute(() -> { Cursor cursor = null; try { cursor = db.rawQuery( "SELECT has_custom_config FROM tb_user_config WHERE user_id=?", new String[]{currentUserId} ); boolean hasConfig = false; if (cursor != null && cursor.moveToFirst()) { hasConfig = cursor.getInt(0) == 1; } if (!hasConfig) { runOnUiThread(() -> { new AlertDialog.Builder(AddInfoActivity.this) .setTitle("提示") .setMessage("您还未设置自定义编号,是否现在设置?") .setPositiveButton("去设置", (dialog, which) -> { startActivity(new Intent(AddInfoActivity.this, SetupCustomIdActivity.class)); // finish(); }) .setNegativeButton("取消", (dialog, which) -> finish()) .show(); }); } else { loadCustomIdSelectors(); // 加载用户配置的编号选择器 } } catch (Exception e) { Log.e("CheckConfig", "配置检查失败", e); runOnUiThread(() -> Toast.makeText(this, "配置检查失败: " + e.getMessage(), Toast.LENGTH_SHORT).show()); } finally { if (cursor != null && !cursor.isClosed()) { cursor.close(); } } }); } private void loadCustomIdSelectors() { runOnUiThread(() -> { if (containerPrefixGroups == null) return; containerPrefixGroups.removeAllViews(); optionSpinners.clear(); executor.execute(() -> { Map<Integer, List<CustomOption>> groupsMap = new LinkedHashMap<>(); 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, option_index", new String[]{currentUserId} ); while (cursor != null && cursor.moveToNext()) { int groupId = cursor.getInt(0); groupsMap.computeIfAbsent(groupId, k -> new ArrayList<>()) .add(new CustomOption( currentUserId, groupId, cursor.getInt(1), cursor.getString(2), cursor.getString(3) )); } runOnUiThread(() -> { for (int groupId = 1; groupId <= 6; groupId++) { if (groupsMap.containsKey(groupId)) { addSpinnerForGroup(groupsMap.get(groupId)); } } }); } catch (Exception e) { Log.e("LoadSelectors", "加载选择器失败", e); runOnUiThread(() -> Toast.makeText(this, "加载选择器失败", Toast.LENGTH_SHORT).show()); } finally { if (cursor != null && !cursor.isClosed()) { cursor.close(); } } }); }); } private void addSpinnerForGroup(List<CustomOption> options) { if (options == null || options.isEmpty()) return; LinearLayout row = new LinearLayout(this); row.setLayoutParams(new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT )); row.setOrientation(LinearLayout.HORIZONTAL); row.setPadding(0, 0, 0, 16); TextView label = new TextView(this); label.setText("组" + options.get(0).groupId + ":"); label.setTextSize(16); label.setTextColor(Color.BLACK); label.setLayoutParams(new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT )); row.addView(label); Spinner spinner = new Spinner(this); spinner.setLayoutParams(new LinearLayout.LayoutParams( 0, LinearLayout.LayoutParams.WRAP_CONTENT, 1 )); 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); optionSpinners.add(spinner); row.addView(spinner); containerPrefixGroups.addView(row); } private String generateMemoIdFromSelection() { if (optionSpinners == null || optionSpinners.isEmpty()) { return "MEM" + new Random().nextInt(100000); } StringBuilder prefix = new StringBuilder(); for (Spinner spinner : optionSpinners) { if (spinner != null && spinner.getSelectedItem() != null) { CustomOption selected = (CustomOption) spinner.getSelectedItem(); prefix.append(selected.codeChar); } } Random random = new Random(); String suffix = String.format(Locale.US, "%05d", random.nextInt(100000)); return prefix.toString() + suffix; } 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); containerPrefixGroups = findViewById(R.id.container_prefix_groups); } // 修复数据库初始化,添加完成回调 private void initDb(Runnable onComplete) { executor.execute(() -> { try { mhelper = new labDbHelper(AddInfoActivity.this); db = mhelper.getWritableDatabase(); dbInitialized = true; Log.d("DbInit", "数据库初始化成功"); } catch (Exception e) { Log.e("DbInit", "数据库初始化失败", e); dbInitialized = false; runOnUiThread(() -> Toast.makeText(this, "数据库初始化失败", Toast.LENGTH_SHORT).show()); } finally { runOnUiThread(() -> { if (onComplete != null) { onComplete.run(); } }); } }); } 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(); } } } // 保存按钮点击事件(添加数据库状态检查) private void btnSave() { // 确保数据库可用 if (!dbInitialized || db == null || !db.isOpen()) { Toast.makeText(this, "数据库未准备好,请稍后重试", Toast.LENGTH_SHORT).show(); initDb(() -> btnSave()); // 重新初始化后递归调用 return; } String title = edit_title.getText().toString().trim(); String content = edit_content.getText().toString().trim(); String location = edit_location.getText().toString().trim(); // 生成唯一ID String uniqueMemoId = generateMemoIdFromSelection(); if (uniqueMemoId == null || uniqueMemoId.isEmpty()) { Toast.makeText(this, "无法生成有效ID", Toast.LENGTH_SHORT).show(); return; } // 验证输入 if (title.isEmpty()) { Toast.makeText(this, "请输入标题", Toast.LENGTH_SHORT).show(); return; } SQLiteDatabase transactionDb = null; try { // 开始事务 transactionDb = mhelper.getWritableDatabase(); transactionDb.beginTransaction(); // 格式化当前时间 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 = transactionDb.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); transactionDb.insert("tb_image", null, imageValues); } // 提交事务 transactionDb.setTransactionSuccessful(); Toast.makeText(this, "保存成功,包含 " + imagePaths.size() + " 张图片", Toast.LENGTH_SHORT).show(); // // 延迟返回主页面 // handler.postDelayed(() -> { // startActivity(new Intent(AddInfoActivity.this, MainActivity.class)); // finish(); // }, 1000); handler.postDelayed(() -> 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 (transactionDb != null) { try { transactionDb.endTransaction(); } catch (Exception e) { Log.e("TransactionEnd", "事务结束失败", 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(); // 清理资源 closeDatabase(); } // 封装数据库关闭逻辑 private void closeDatabase() { try { if (db != null && db.isOpen()) { db.close(); Log.d("DbClose", "数据库已关闭"); } if (mhelper != null) { mhelper.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.content.ContentValues; 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[][] optionInputs = new EditText[6][10]; private Button btnSave; private labDbHelper dbHelper; private SQLiteDatabase db; private String currentUserId = "USER001"; // 实际应从登录系统获取 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_setup_custom_id); dbHelper = new labDbHelper(this); db = dbHelper.getWritableDatabase(); initUI(); loadExistingConfig(); } private void initUI() { int[] groupLayoutIds = { R.id.group1, R.id.group2, R.id.group3, R.id.group4, R.id.group5, R.id.group6 }; // 初始化输入框 for (int groupIdx = 0; groupIdx < 6; groupIdx++) { LinearLayout groupLayout = findViewById(groupLayoutIds[groupIdx]); for (int optionIdx = 0; optionIdx < 10; optionIdx++) { EditText et = new EditText(this); et.setHint("组" + (groupIdx+1) + " - 选项" + (optionIdx)); et.setTextSize(14); et.setPadding(16, 12, 16, 12); et.setBackgroundResource(R.drawable.edittext_bg); groupLayout.addView(et); optionInputs[groupIdx][optionIdx] = et; } } btnSave = findViewById(R.id.btn_save_config); btnSave.setOnClickListener(v -> saveConfiguration()); } private void loadExistingConfig() { Cursor cursor = db.rawQuery( "SELECT group_id, option_index, display_text FROM tb_custom_config WHERE user_id=?", new String[]{currentUserId} ); while (cursor.moveToNext()) { int groupId = cursor.getInt(0); int optionIdx = cursor.getInt(1); String text = cursor.getString(2); if (groupId >= 1 && groupId <= 6 && optionIdx >= 0 && optionIdx < 10) { optionInputs[groupId-1][optionIdx].setText(text); } } cursor.close(); } private void saveConfiguration() { // 删除旧配置 db.delete("tb_custom_config", "user_id=?", new String[]{currentUserId}); boolean hasValidGroup = false; for (int groupIdx = 0; groupIdx < 6; groupIdx++) { boolean groupHasOptions = false; for (int optionIdx = 0; optionIdx < 10; optionIdx++) { String text = optionInputs[groupIdx][optionIdx].getText().toString().trim(); if (!text.isEmpty()) { // 自动生成选项代码 (A-Z) String codeChar = String.valueOf((char) ('A' + groupIdx)); insertOption(currentUserId, groupIdx + 1, optionIdx, text, codeChar); groupHasOptions = true; } } if (groupHasOptions) hasValidGroup = true; } if (!hasValidGroup) { Toast.makeText(this, "请至少填写一组编号选项!", Toast.LENGTH_SHORT).show(); return; } // 标记用户已完成配置 ContentValues configValues = new ContentValues(); configValues.put("user_id", currentUserId); configValues.put("has_custom_config", 1); db.insertWithOnConflict("tb_user_config", null, configValues, SQLiteDatabase.CONFLICT_REPLACE); Toast.makeText(this, "配置保存成功!", Toast.LENGTH_SHORT).show(); finish(); } private void insertOption(String userId, int groupId, int optionIndex, String displayText, String codeChar) { ContentValues values = new ContentValues(); values.put("user_id", userId); values.put("group_id", groupId); values.put("option_index", optionIndex); values.put("display_text", displayText); values.put("code_char", codeChar); db.insert("tb_custom_config", null, values); } } 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); // 添加用户配置 String createUserConfigTable = "CREATE TABLE tb_user_config (" + "user_id TEXT PRIMARY KEY," + "has_custom_config INTEGER DEFAULT 0)"; db.execSQL(createUserConfigTable); 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 < 5) { 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 (...)"); // 添加用户配置 db.execSQL("CREATE TABLE IF NOT EXISTS tb_user_config (" + "user_id TEXT PRIMARY KEY," + "has_custom_config INTEGER DEFAULT 0)"); Log.d(TAG, "数据库升级到版本5,支持多图存储"); } catch (Exception e) { Log.e(TAG, "数据库升级失败:" + e.getMessage(), e); } } } }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; } }// 文件路径: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); } } } 问题:在main页面点击日志创页面时程序直接闪退,另外取消用户进行日志创时的提示自定义编号功能。请综合代码进行分析,进行改正修复和完善,标明修改后的代码以及修改代码的位置(旧代码和需要替换的新代码进行明确标注);在不改变原有代码的基础上,完善输出完整代码。
最新发布
09-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值