diff --git a/app/src/main/java/com/sound/prankparty/Activity/NewRecordActivity.java b/app/src/main/java/com/sound/prankparty/Activity/NewRecordActivity.java index 6050086..cd01ece 100644 --- a/app/src/main/java/com/sound/prankparty/Activity/NewRecordActivity.java +++ b/app/src/main/java/com/sound/prankparty/Activity/NewRecordActivity.java @@ -28,15 +28,6 @@ public class NewRecordActivity extends AppCompatActivity { private long startTime; private MediaRecorder mediaRecorder; private File outputFile; - private Runnable updateTimeTask = new Runnable() { - @Override - public void run() { - long currentTime = System.currentTimeMillis(); - long elapsedTime = currentTime - startTime; - binding.newRecordTime.setText(formatTime(elapsedTime)); - handler.postDelayed(this, 1000); - } - }; @Override protected void onCreate(Bundle savedInstanceState) { @@ -55,7 +46,7 @@ public class NewRecordActivity extends AppCompatActivity { } }); - binding.newRecordBack.setOnClickListener(v -> finish()); + binding.newRecordBack.setOnClickListener(v -> onBackPressed()); } private void toggleRecording() { @@ -69,6 +60,17 @@ public class NewRecordActivity extends AppCompatActivity { isStarted = !isStarted; // 切换录音状态 } + //每个一秒更新显示录音时长 + private Runnable updateTimeTask = new Runnable() { + @Override + public void run() { + long currentTime = System.currentTimeMillis(); + long elapsedTime = currentTime - startTime; + binding.newRecordTime.setText(formatTime(elapsedTime)); + handler.postDelayed(this, 1000); + } + }; + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); @@ -137,9 +139,40 @@ public class NewRecordActivity extends AppCompatActivity { return String.format("%02d:%02d:%02d", hours, minutes, seconds); } + @Override + public void onBackPressed() { + if (isStarted) { + // 停止录音并释放MediaRecorder + if (mediaRecorder != null) { + mediaRecorder.stop(); + mediaRecorder.release(); + mediaRecorder = null; + } + // 删除录音文件 + deleteRecordingFile(); + } + finish(); + super.onBackPressed(); + } + + private void deleteRecordingFile() { + if (outputFile != null && outputFile.exists()) { + boolean deleted = outputFile.delete(); + } + } + @Override protected void onDestroy() { super.onDestroy(); handler.removeCallbacks(updateTimeTask); + if (isStarted) { + // 停止录音并释放MediaRecorder + if (mediaRecorder != null) { + mediaRecorder.stop(); + mediaRecorder.release(); + mediaRecorder = null; + } + deleteRecordingFile(); + } } } diff --git a/app/src/main/java/com/sound/prankparty/Activity/SaveRecordActivity.java b/app/src/main/java/com/sound/prankparty/Activity/SaveRecordActivity.java index baefed1..c31acfd 100644 --- a/app/src/main/java/com/sound/prankparty/Activity/SaveRecordActivity.java +++ b/app/src/main/java/com/sound/prankparty/Activity/SaveRecordActivity.java @@ -1,5 +1,6 @@ package com.sound.prankparty.Activity; +import android.annotation.SuppressLint; import android.content.Intent; import android.media.MediaPlayer; import android.os.Bundle; @@ -11,6 +12,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Toast; +import androidx.activity.OnBackPressedCallback; import androidx.appcompat.app.AppCompatActivity; import com.sound.prankparty.R; @@ -19,6 +21,7 @@ import com.sound.prankparty.Room.SaveSounds; import com.sound.prankparty.Room.SaveSoundsDao; import com.sound.prankparty.databinding.ActivitySaveRecordBinding; +import java.io.File; import java.io.IOException; import java.text.DateFormatSymbols; import java.text.SimpleDateFormat; @@ -67,7 +70,16 @@ public class SaveRecordActivity extends AppCompatActivity { // 设置焦点变化监听器 binding.saveRecordName.setOnFocusChangeListener((v, hasFocus) -> binding.saveRecordName.setCursorVisible(hasFocus)); - binding.saveRecordBack.setOnClickListener(v -> finish()); + binding.saveRecordBack.setOnClickListener(v -> handleBackPressed()); + + // 添加 OnBackPressedCallback 来处理返回操作 + getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + // 调用相同的处理逻辑 + handleBackPressed(); + } + }); // 处理全局点击事件 binding.main.setOnClickListener(v -> { @@ -87,7 +99,8 @@ public class SaveRecordActivity extends AppCompatActivity { binding.saveRecordSave.setOnClickListener(v -> { inputText = binding.saveRecordName.getText().toString(); - if (inputText == null || inputText.trim().isEmpty()) { + //检测是否输入为空字符串 + if (inputText.trim().isEmpty()) { Toast.makeText(getApplicationContext(), "名称不能为空", Toast.LENGTH_SHORT).show(); return; } @@ -107,6 +120,19 @@ public class SaveRecordActivity extends AppCompatActivity { }); } + public void handleBackPressed() { + // 删除录音文件 + deleteRecordingFile(); + finish(); + } + + private void deleteRecordingFile() { + File file = new File(audioFilePath); + if (file.exists()) { + boolean deleted = file.delete(); + } + } + private void clearFocusFromAllChildren(ViewGroup parent) { for (int i = 0; i < parent.getChildCount(); i++) { View child = parent.getChildAt(i); @@ -180,8 +206,10 @@ public class SaveRecordActivity extends AppCompatActivity { mediaPlayer.release(); mediaPlayer = null; } + deleteRecordingFile(); } + @SuppressLint("DefaultLocale") private String formatTime(int duration) { int seconds = (duration / 1000) % 60; int minutes = (duration / (1000 * 60)) % 60; diff --git a/app/src/main/java/com/sound/prankparty/Adapter/AirHornRecyclerViewAdapter.java b/app/src/main/java/com/sound/prankparty/Adapter/AirHornRecyclerViewAdapter.java index 8fefef6..f324cfe 100644 --- a/app/src/main/java/com/sound/prankparty/Adapter/AirHornRecyclerViewAdapter.java +++ b/app/src/main/java/com/sound/prankparty/Adapter/AirHornRecyclerViewAdapter.java @@ -15,8 +15,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.bitmap.CenterCrop; -import com.bumptech.glide.load.resource.bitmap.RoundedCorners; -import com.bumptech.glide.request.RequestOptions; import com.sound.MainApplication; import com.sound.prankparty.Activity.PlaySoundActivity; import com.sound.prankparty.JSON.SoundItem; @@ -26,9 +24,9 @@ import java.util.List; public class AirHornRecyclerViewAdapter extends RecyclerView.Adapter { - private Context context; - private List soundItemList; - private int color; + private final Context context; + private final List soundItemList; + private final int color; public AirHornRecyclerViewAdapter(Context context, List soundItemList,int color) { this.context = context; @@ -64,25 +62,22 @@ public class AirHornRecyclerViewAdapter extends RecyclerView.Adapter { - Intent intent = new Intent(context, PlaySoundActivity.class); - intent.putExtra("1234", soundItem); - context.startActivity(intent); - }); - } + holder.imageView.setOnClickListener(v -> { + Intent intent = new Intent(context, PlaySoundActivity.class); + intent.putExtra("1234", soundItem); + context.startActivity(intent); + }); } @@ -91,7 +86,7 @@ public class AirHornRecyclerViewAdapter extends RecyclerView.Adapter newFavoriteSoundsList) { - DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new FavoriteSoundsDiffCallback(favoriteSoundsList, newFavoriteSoundsList)); - favoriteSoundsList.clear(); - favoriteSoundsList.addAll(newFavoriteSoundsList); - diffResult.dispatchUpdatesTo(this); - } - @NonNull @Override public FavoriteRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -76,7 +69,7 @@ public class FavoriteRecyclerViewAdapter extends RecyclerView.Adapter newFavoriteSoundsList) { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new FavoriteSoundsDiffCallback(favoriteSoundsList, newFavoriteSoundsList)); + favoriteSoundsList.clear(); + favoriteSoundsList.addAll(newFavoriteSoundsList); + diffResult.dispatchUpdatesTo(this); + } + @Override public int getItemCount() { return favoriteSoundsList != null ? favoriteSoundsList.size() : 0; } - static class FavoriteRecyclerViewHolder extends RecyclerView.ViewHolder { + public static class FavoriteRecyclerViewHolder extends RecyclerView.ViewHolder { ImageView imageView; TextView textView; diff --git a/app/src/main/java/com/sound/prankparty/Adapter/RadioRecyclerViewAdapter.java b/app/src/main/java/com/sound/prankparty/Adapter/RadioRecyclerViewAdapter.java index 8adbb16..02fc07c 100644 --- a/app/src/main/java/com/sound/prankparty/Adapter/RadioRecyclerViewAdapter.java +++ b/app/src/main/java/com/sound/prankparty/Adapter/RadioRecyclerViewAdapter.java @@ -112,7 +112,7 @@ public class RadioRecyclerViewAdapter extends RecyclerView.Adapter { - SaveSounds sound = saveSoundsList.get(position); - saveSoundsDao.deleteSound(sound); - requireActivity().runOnUiThread(() -> { - refreshData(); - }); - }).start(); - } - - private void showCustomBottomSheetDialog() { BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(requireContext()); View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_dialog, null); @@ -148,8 +138,8 @@ public class RadioFragment extends Fragment { bottomSheetDialog.show(); } - // 处理权限请求结果 + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); @@ -161,8 +151,8 @@ public class RadioFragment extends Fragment { } } } - // 打开音频选择器 + private void openAudioPicker() { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); // 改为 ACTION_OPEN_DOCUMENT intent.setType("audio/*"); // 设置 MIME 类型为音频 @@ -170,8 +160,8 @@ public class RadioFragment extends Fragment { startActivityForResult(intent, REQUEST_CODE_PICK_AUDIO); } - // 处理 Activity 结果 + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); @@ -188,13 +178,23 @@ public class RadioFragment extends Fragment { } // 获取文件的最后修改时间 - long lastModifiedTime = getLastModifiedTime(requireContext(),audioUri); + long lastModifiedTime = getLastModifiedTime(requireContext(), audioUri); String[] lastModifiedDateTime = getDateTimeFromLastModified(lastModifiedTime); long finalDuration = duration; + new Thread(() -> { try { - saveSoundsDao.insertSound(new SaveSounds(fileName, audioUri.toString(), lastModifiedDateTime[0], lastModifiedDateTime[1], formatDuration(finalDuration))); + // 在插入数据库前检查该 URI 是否已经存在 + int count = saveSoundsDao.countSoundsByUri(audioUri.toString()); + if (count > 0) { + // 在主线程中显示文件已经存在的提示 + requireActivity().runOnUiThread(() -> + Toast.makeText(requireContext(), "该文件已经导入过,不能重复导入", Toast.LENGTH_LONG).show()); + } else { + // 插入新记录 + saveSoundsDao.insertSound(new SaveSounds(fileName, audioUri.toString(), lastModifiedDateTime[0], lastModifiedDateTime[1], formatDuration(finalDuration))); + } } catch (Exception e) { e.printStackTrace(); // 在主线程中显示错误信息 @@ -207,6 +207,7 @@ public class RadioFragment extends Fragment { } // 获取文件名 + private String getFileName(Uri uri) { String result = null; if (Objects.equals(uri.getScheme(), "content")) { @@ -229,8 +230,8 @@ public class RadioFragment extends Fragment { } return result; } - // 获取音频时长 + private long getAudioDuration(Uri uri) throws IOException { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { @@ -244,15 +245,15 @@ public class RadioFragment extends Fragment { retriever.release(); } } - // 格式化时长 + private String formatDuration(long duration) { long minutes = (duration / 1000) / 60; long seconds = (duration / 1000) % 60; return String.format(Locale.getDefault(), "%d:%02d", minutes, seconds); } - //获取最后修改时间 + public long getLastModifiedTime(Context context, Uri uri) { long lastModifiedTime = 0; @@ -290,6 +291,42 @@ public class RadioFragment extends Fragment { return new String[]{date, time}; } + public void deleteItem(int position) { + new Thread(() -> { + // 获取要删除的音频对象 + SaveSounds sound = saveSoundsList.get(position); + String filePath = sound.getPath(); + + // 删除数据库中的收藏记录 + FavoriteSounds favoriteSound = favoriteSoundsDao.getByPath(filePath); + if (favoriteSound != null) { + favoriteSoundsDao.delete(favoriteSound); + } + + // 删除数据库中的音频记录 + saveSoundsDao.deleteSound(sound); + + // 删除文件系统中的实际录音文件 + File file = new File(filePath); + if (file.exists()) { + boolean deleted = file.delete(); + if (deleted) { + // 如果文件成功删除,可以在这里执行其他操作,比如记录日志 + Log.d("DeleteItem", "录音文件已删除: " + filePath); + } else { + // 如果文件删除失败,可以在这里处理 + Log.e("DeleteItem", "删除录音文件失败: " + filePath); + } + } else { + // 如果文件不存在,可以在这里处理 + Log.w("DeleteItem", "录音文件不存在: " + filePath); + } + + // 在主线程中刷新UI + requireActivity().runOnUiThread(this::refreshData); + }).start(); + } + // 刷新数据 public void refreshData() { new Thread(() -> { diff --git a/app/src/main/java/com/sound/prankparty/Fragment/SoundFragment.java b/app/src/main/java/com/sound/prankparty/Fragment/SoundFragment.java index cae777e..cadc870 100644 --- a/app/src/main/java/com/sound/prankparty/Fragment/SoundFragment.java +++ b/app/src/main/java/com/sound/prankparty/Fragment/SoundFragment.java @@ -64,6 +64,7 @@ public class SoundFragment extends Fragment { View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.setting_dialog, null); // 禁止点击其他页面取消 bottomSheetDialog.setCanceledOnTouchOutside(false); + TextView version = dialogView.findViewById(R.id.version_number); //更新版本号 diff --git a/app/src/main/java/com/sound/prankparty/MainApplication.java b/app/src/main/java/com/sound/prankparty/MainApplication.java new file mode 100644 index 0000000..44edc16 --- /dev/null +++ b/app/src/main/java/com/sound/prankparty/MainApplication.java @@ -0,0 +1,33 @@ +package com.sound; + +import android.app.Application; +import android.content.Context; + +public class MainApplication extends Application { + /** + * 全局的上下文 + */ + private static Context mContext; + + @Override + public void onCreate() { + super.onCreate(); + //获取应用的上下文并赋值给 mContext + mContext = getApplicationContext(); + } + + /** + * 获取context + * @return + */ + public static Context getContext(){ + return mContext; + } + + //重写 onLowMemory 方法,在系统内存不足时调用。这里只是调用了父类的 onLowMemory 方法,没有做其他处理 + @Override + public void onLowMemory() { + super.onLowMemory(); + } + +} diff --git a/app/src/main/java/com/sound/prankparty/Room/SaveSoundsDao.java b/app/src/main/java/com/sound/prankparty/Room/SaveSoundsDao.java index 05f440b..8f8b31f 100644 --- a/app/src/main/java/com/sound/prankparty/Room/SaveSoundsDao.java +++ b/app/src/main/java/com/sound/prankparty/Room/SaveSoundsDao.java @@ -12,6 +12,9 @@ public interface SaveSoundsDao { @Insert void insertSound(SaveSounds sound); + @Query("SELECT COUNT(*) FROM save_sounds WHERE path = :uri") + int countSoundsByUri(String uri); + @Query("SELECT * FROM save_sounds") List getAllSounds(); diff --git a/app/src/main/java/com/sound/prankparty/SecondFragment/RadioFragment.java b/app/src/main/java/com/sound/prankparty/SecondFragment/RadioFragment.java index 34a69fd..599527c 100644 --- a/app/src/main/java/com/sound/prankparty/SecondFragment/RadioFragment.java +++ b/app/src/main/java/com/sound/prankparty/SecondFragment/RadioFragment.java @@ -83,7 +83,7 @@ public class RadioFragment extends Fragment { recyclerView.setAdapter(radioRecyclerViewAdapter); // 初始化 MyItemTouchHelperCallback - myItemTouchHelperCallback = new MyItemTouchHelperCallback(); + myItemTouchHelperCallback = new MyItemTouchHelperCallback(this); itemTouchHelper = new ItemTouchHelper(myItemTouchHelperCallback); itemTouchHelper.attachToRecyclerView(recyclerView); diff --git a/app/src/main/java/com/sound/prankparty/Utils/FavoriteSoundsViewModel.java b/app/src/main/java/com/sound/prankparty/Utils/FavoriteSoundsViewModel.java index 3f824c3..9d2b04d 100644 --- a/app/src/main/java/com/sound/prankparty/Utils/FavoriteSoundsViewModel.java +++ b/app/src/main/java/com/sound/prankparty/Utils/FavoriteSoundsViewModel.java @@ -25,10 +25,6 @@ public class FavoriteSoundsViewModel extends AndroidViewModel { public LiveData> getFavoriteSoundsLiveData() { return favoriteSoundsLiveData; } - - public void refreshData() { - // 这里不需要做任何事情,因为 LiveData 会自动更新 - } }