package com.example.labmemotest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.example.labmemotest.db.labDbHelper;
import java.io.File;
import java.io.FileNotFoundException;
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 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);
imagesContainer.removeAllViews();
loadImages(memo_id, imagesContainer);
}
}
private void loadImages(String memo_id, LinearLayout container) {
labDbHelper dbHelper = new labDbHelper(this);
SQLiteDatabase db = dbHelper.getWritableDatabase();
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()) {
String imgPath = cursor.getString(cursor.getColumnIndexOrThrow("imgpath"));
Log.d("DetailActivity", "图片路径: " + imgPath);
try {
Uri uri = handleImageUri(imgPath, db);
addImageView(uri, container);
} catch (Exception e) {
Log.e("ImageLoad", "图片加载错误: " + imgPath, e);
addErrorImage(container, "加载失败: " + e.getMessage());
}
}
} finally {
cursor.close();
db.close();
}
}
private Uri handleImageUri(String imgPath, SQLiteDatabase db) throws FileNotFoundException {
Uri uri;
// 如果是文件路径,转换为content URI
if (imgPath.startsWith("/")) {
File file = new File(imgPath);
if (file.exists()) {
uri = FileProvider.getUriForFile(
this,
getPackageName() + ".fileprovider",
file
);
// 更新数据库中的路径
ContentValues values = new ContentValues();
values.put("imgpath", uri.toString());
db.update("tb_image", values, "imgpath = ?", new String[]{imgPath});
} else {
throw new FileNotFoundException("文件不存在: " + imgPath);
}
} else {
uri = Uri.parse(imgPath);
}
// 添加持久化权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getContentResolver().takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
} else {
grantUriPermission(getPackageName(), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
return uri;
}
private void addImageView(Uri uri, LinearLayout container) {
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)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(
@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource
) {
Log.e("GlideError", "加载失败: " + model, e);
return false;
}
@Override
public boolean onResourceReady(
Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource
) {
return false;
}
})
.into(imageView);
container.addView(imageView);
}
private void addErrorImage(LinearLayout container, String errorMsg) {
TextView errorView = new TextView(this);
errorView.setText(errorMsg);
errorView.setTextColor(Color.RED);
errorView.setPadding(16, 16, 16, 16);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.bottomMargin = 16;
container.addView(errorView, params);
}
}
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.ContentResolver;
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.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.example.labmemotest.db.labDbHelper;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
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<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;
@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) {
File imgFile = new File(tmp_path);
if (imgFile.exists()) {
Uri imageUri = FileProvider.getUriForFile(
this,
getPackageName() + ".fileprovider",
imgFile
);
// 添加持久化权限
getContentResolver().takePersistableUriPermission(
imageUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
imagePaths.add(imageUri.toString());
updateImagePreviews();
} 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();
// 添加持久化权限
getContentResolver().takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
imagePaths.add(uri.toString());
}
} else if (data.getData() != null) {
Uri uri = data.getData();
getContentResolver().takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
imagePaths.add(uri.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());
}
// 修复的相机权限检查
private void checkCameraPermission() {
List<String> permissionsNeeded = new ArrayList<>();
// 相机权限是必须的
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.CAMERA);
}
// Android 13+ 需要READ_MEDIA_IMAGES权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.READ_MEDIA_IMAGES);
}
}
// 旧版本需要WRITE_EXTERNAL_STORAGE权限
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
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 13+ 需要READ_MEDIA_IMAGES权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES)
!= PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.READ_MEDIA_IMAGES);
}
}
// 旧版本需要READ_EXTERNAL_STORAGE权限
else {
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
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);
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();
}
}
}
// 生成唯一备忘录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 (Cursor cursor = db.query(
"tb_memory",
new String[]{"memo_id"},
"memo_id = ?",
new String[]{memoId},
null, null, null
)) {
if (cursor.getCount() > 0) {
idExists = true;
}
} 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;
}
// 保存按钮点击事件
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;
}
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();
// 延迟返回主页面
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_LONG).show();
} finally {
// 确保关闭数据库
if (db != null && db.isOpen()) {
db.close();
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_CODE) {
boolean allPermissionsGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allPermissionsGranted = false;
break;
}
}
if (allPermissionsGranted) {
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();
}
}
在以上原有代码的基础上,按照上述你的回答修改完善输出完整代码