package com.example.labmemotest;
import androidx.appcompat.app.AppCompatActivity;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.LinearLayout;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import com.bumptech.glide.Glide;
import com.example.labmemotest.db.labDbHelper; // 确保路径正确
// 详情页面
public class DetailActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); // 获取传递的数据 Bundle bundle = getIntent().getExtras(); if (bundle != null) { String memo_id = bundle.getString("memo_id"); String title = bundle.getString("title"); String content = bundle.getString("content"); String imgpath = bundle.getString("imgpath"); // 兼容旧逻辑 String time = bundle.getString("time"); String location = bundle.getString("location"); // 显示编号 TextView memo_idTextView = findViewById(R.id.detail_memo_id); memo_idTextView.setText("编号:" + memo_id); // 显示标题 TextView titleTextView = findViewById(R.id.detail_title); titleTextView.setText(title); // 显示地点 TextView locationTextView = findViewById(R.id.detail_location); if (location != null && !location.isEmpty()) { locationTextView.setText("地点:" + location); } else { locationTextView.setText("地点:未设置"); } // 显示内容 TextView contentTextView = findViewById(R.id.detail_content); contentTextView.setText(content); // 显示时间 TextView timeTextView = findViewById(R.id.detail_time); timeTextView.setText(time); // 显示所有图片 LinearLayout imagesContainer = findViewById(R.id.detail_images_container); labDbHelper dbHelper = new labDbHelper(this); SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = db.query( "tb_image", new String[]{"imgpath"}, "memo_id = ?", new String[]{memo_id}, null, null, null ); if (cursor == null) { Log.e("DetailActivity", "查询图片失败,Cursor 为 null"); return; } try { while (cursor.moveToNext()) { try { String imgPath = cursor.getString(cursor.getColumnIndexOrThrow("imgpath")); Log.d("DetailActivity", "图片路径: " + imgPath); // ✅ 自定义判断是否为合法的 content:// 或 file:// URI Uri uri; try { uri = Uri.parse(imgPath); } catch (Exception e) { Log.e("DetailActivity", "URI 解析失败: " + imgPath, e); continue; } // ✅ 判断协议类型(手动实现替代 UriUtils) boolean isValidUri = isContentUri(uri) || isFileUri(uri); Log.d("DetailActivity", "URI 类型检查: " + (isValidUri ? "有效" : "无效")); ImageView imageView = new ImageView(this); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, 600 ); params.bottomMargin = 16; 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); imagesContainer.addView(imageView); } catch (Exception e) { Log.e("DetailActivity", "处理单个图片时出错", e); addErrorImage(imagesContainer); // 添加错误提示图 } } } finally { cursor.close(); db.close(); } } } // ✅ 手动实现:判断是否为 content:// URI private boolean isContentUri(Uri uri) { return "content".equals(uri.getScheme()); } // ✅ 手动实现:判断是否为 file:// URI private boolean isFileUri(Uri uri) { return "file".equals(uri.getScheme()); } // ✅ 辅助方法:添加错误图片占位符 private void addErrorImage(LinearLayout container) { ImageView errorView = new ImageView(this); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, 600 ); params.bottomMargin = 16; errorView.setLayoutParams(params); errorView.setScaleType(ImageView.ScaleType.CENTER); errorView.setBackgroundColor(Color.parseColor("#FFEBEE")); // 浅红背景 errorView.setImageResource(R.drawable.ic_error_image); // 替换为你自己的图标 container.addView(errorView); }
}
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; }
}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))"; 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 < 3) { 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))"); Log.d(TAG, "数据库升级到版本3,支持多图存储"); } catch (Exception e) { Log.e(TAG, "数据库升级失败:" + e.getMessage(), e); } } }
}
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 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;
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; 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); // 1.绑定控件 initView(); // 2.对按钮添加单击事件 btnonclicknext(); // 3.添加从数据库获取数据并显示到RecyclerView的功能 recyDisplay(); // 新增:设置搜索监听 setupSearchListener(); } // 1.绑定控件 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(); } // 2.对按钮添加单击事件 private void btnonclicknext() { btn_add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 单击后跳转到下一页 Intent intent = new Intent(MainActivity.this, AddInfoActivity.class); startActivity(intent); finish(); } }); } // 3.从数据库获取数据,显示到RecyclerView 控件中 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 myimgpath = cursor.getString(cursor.getColumnIndex("imgpath")); 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.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.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.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.blankj.utilcode.util.UriUtils;
import com.bumptech.glide.Glide;
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.List;
import java.util.Random;
//日志创建页面
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 imagePaths = new ArrayList<>(); // 存储图片Uri字符串
private Handler handler = new Handler(Looper.getMainLooper()); // 添加Handler
private ActivityResultLauncher<Intent> cameraLauncher; private ActivityResultLauncher<Intent> galleryLauncher; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_info); initLaunchers(); initView(); initDb(); // 确保数据库先初始化 btnOnClick(); } private void initLaunchers() { // 相机返回结果处理 cameraLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK) { // 相机图片用FileProvider生成的Uri存储 Uri imageUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", new File(tmp_path)); imagePaths.add(imageUri.toString()); // 存储Uri字符串 updateImagePreviews(); } } ); // 相册返回结果处理 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 imageUri = data.getClipData().getItemAt(i).getUri(); imagePaths.add(imageUri.toString()); // 直接存储Uri } } else if (data.getData() != null) { Uri imageUri = data.getData(); imagePaths.add(imageUri.toString()); } updateImagePreviews(); } catch (Exception e) { Log.e("GalleryError", "相册选择失败", e); Toast.makeText(this, "图片选择失败", 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); } 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 13+) private void checkCameraPermission() { List<String> permissions = new ArrayList<>(); if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { permissions.add(Manifest.permission.CAMERA); } // Android 13+ 不需要WRITE_EXTERNAL_STORAGE,用分区存储 if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } if (!permissions.isEmpty()) { ActivityCompat.requestPermissions(this, permissions.toArray(new String[0]), 100); } else { openCamera(); } } // 检查相册权限(适配Android 13+) private void checkGalleryPermission() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_MEDIA_IMAGES}, 200); } else { openGallery(); } } else { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 200); } else { openGallery(); } } } private void openCamera() { try { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String randtime = sdf.format(date); File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File imgfile = new File(storageDir, "image" + randtime + ".jpg"); tmp_path = imgfile.getAbsolutePath(); Uri photoURI = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", imgfile); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); cameraLauncher.launch(intent); } catch (Exception e) { Log.e("CameraError", "相机打开失败", e); Toast.makeText(this, "无法打开相机", Toast.LENGTH_SHORT).show(); } } private void openGallery() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); galleryLauncher.launch(intent); } private void updateImagePreviews() { previewContainer.removeAllViews(); for (String uriString : imagePaths) { try { ImageView imageView = new ImageView(this); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( 300, 300, 1.0f ); params.setMargins(8, 8, 8, 8); imageView.setLayoutParams(params); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setBackgroundColor(Color.parseColor("#F5F5F5")); Glide.with(this).load(Uri.parse(uriString)).into(imageView); // 直接加载Uri previewContainer.addView(imageView); } catch (Exception e) { Log.e("PreviewError", "图片预览失败", e); } } } // 生成唯一ID(添加数据库操作异常捕获) private String generateUniqueMemoId() { if (db == null || !db.isOpen()) { initDb(); // 重新初始化数据库 } Random random = new Random(); String memoId; while (true) { long randomNum = 100000000L + random.nextLong() % 900000000L; if (randomNum < 0) randomNum = -randomNum; memoId = String.valueOf(randomNum); try (Cursor cursor = db.query( // 自动关闭cursor "tb_memory", new String[]{"memo_id"}, "memo_id = ?", new String[]{memoId}, null, null, null )) { if (!cursor.moveToNext()) { break; } } catch (Exception e) { Log.e("GenerateIdError", "ID生成失败", e); Toast.makeText(this, "编号生成失败", Toast.LENGTH_SHORT).show(); return ""; // 异常时返回空 } } return memoId; } private void btnSave() { String title = edit_title.getText().toString().trim(); String content = edit_content.getText().toString().trim(); String location = edit_location.getText().toString().trim(); if (title.isEmpty()) { Toast.makeText(this, "请输入标题", Toast.LENGTH_SHORT).show(); return; } if (db == null || !db.isOpen()) { Toast.makeText(this, "数据库未初始化", Toast.LENGTH_SHORT).show(); return; } String uniqueMemoId = generateUniqueMemoId(); if (uniqueMemoId.isEmpty()) { return; // ID生成失败直接返回 } try { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); 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 uriString : imagePaths) { ContentValues imageValues = new ContentValues(); imageValues.put("memo_id", uniqueMemoId); imageValues.put("imgpath", uriString); // 存储Uri字符串 db.insert("tb_image", null, imageValues); } // 关闭数据库 if (db != null && db.isOpen()) { db.close(); } Toast.makeText(this, "保存成功(" + imagePaths.size() + "张图片)", Toast.LENGTH_SHORT).show(); // 使用Handler延迟启动主活动,避免数据库操作冲突 handler.postDelayed(() -> { startActivity(new Intent(AddInfoActivity.this, MainActivity.class)); finish(); }, 500); } else { Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { Log.e("SaveError", "保存失败", e); Toast.makeText(this, "保存失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 100) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { openCamera(); } else { Toast.makeText(this, "需要相机权限才能拍照", Toast.LENGTH_SHORT).show(); } } else if (requestCode == 200) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { openGallery(); } else { Toast.makeText(this, "需要相册权限才能选择图片", Toast.LENGTH_SHORT).show(); } } } @Override public void onBackPressed() { // 关闭数据库 if (db != null && db.isOpen()) { db.close(); } startActivity(new Intent(AddInfoActivity.this, MainActivity.class)); finish(); } @Override protected void onDestroy() { super.onDestroy(); // 确保数据库已关闭 if (db != null && db.isOpen()) { try { db.close(); } catch (Exception e) { Log.e("DestroyError", "关闭数据库失败", e); } } }
}阅读以上多个代码,分析在子项控件详情页面里图片无法正常显示的问题,以及日志创建页面提取权限后依然无法拍照的问题,分析解决并给出具体解决方案和代码
最新发布