java—当重复处理程序遇到某个条件时,如何结束它?

pnwntuvh  于 2021-07-06  发布在  Java
关注(0)|答案(2)|浏览(433)

我正在制作一个应用程序来播放设备存储器中的音频文件,我有一个seek条,它每秒钟检查音频文件的进度(播放了多长时间),并相应地更新seekbar。
音频通过在前台运行的服务播放,并显示音频正在播放的通知。
当音频结束时,我注意到处理程序仍在循环中,我想在音频结束后结束处理程序。
我目前尝试的是从处理程序运行的runnable内部结束处理程序,因为我不确定如何结束它。
主活动,在这里我从listview处理onclick,在这里您可以选择一个音频文件,还可以处理seekbar更新。

  1. import androidx.appcompat.app.AppCompatActivity;
  2. import android.content.ComponentName;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.content.ServiceConnection;
  6. import android.database.Cursor;
  7. import android.os.Bundle;
  8. import android.os.Handler;
  9. import android.os.IBinder;
  10. import android.provider.MediaStore;
  11. import android.util.Log;
  12. import android.view.View;
  13. import android.widget.AdapterView;
  14. import android.widget.ListView;
  15. import android.widget.SeekBar;
  16. import android.widget.SimpleCursorAdapter;
  17. import android.widget.TextView;
  18. import java.util.concurrent.TimeUnit;
  19. public class MainActivity extends AppCompatActivity {
  20. SeekBar musicProgBar;
  21. Handler progBarHandler = null;
  22. Runnable r = null;
  23. private MP3Service.MyBinder myService = null;
  24. TextView progressText = null;
  25. @Override
  26. protected void onCreate(Bundle savedInstanceState)
  27. {
  28. super.onCreate(savedInstanceState);
  29. setContentView(R.layout.activity_main);
  30. musicProgBar = findViewById(R.id.musicProgressBar);
  31. progressText = findViewById(R.id.progressText);
  32. final ListView lv = (ListView) findViewById(R.id.musicList);
  33. Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
  34. null,
  35. MediaStore.Audio.Media.IS_MUSIC + "!= 0",
  36. null,
  37. null);
  38. progBarHandler = new Handler();
  39. final int progBarDelay = 1000; // delay for the handler, making it repeat itself only every 1000 miliseconds (1 second)
  40. lv.setAdapter(new SimpleCursorAdapter(this,
  41. android.R.layout.simple_list_item_1,
  42. cursor,
  43. new String[] { MediaStore.Audio.Media.DATA},
  44. new int[] { android.R.id.text1 }));
  45. Intent tempIntent = new Intent(this, MP3Service.class);
  46. startService(tempIntent);
  47. bindService(tempIntent, serviceConnection, 0);
  48. lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  49. public void onItemClick(AdapterView<?> myAdapter,
  50. View myView,
  51. int myItemInt,
  52. long myLong) {
  53. Cursor c = (Cursor) lv.getItemAtPosition(myItemInt);
  54. String uri = c.getString(c.getColumnIndex(MediaStore.Audio.Media.DATA));
  55. Log.d("g53mdp", uri);
  56. if (myService.fetchPlayerState() != MP3Player.MP3PlayerState.STOPPED)
  57. myService.stopMusic();
  58. myService.loadMusic(uri);
  59. myService.playMusic();
  60. musicProgBar.setMax(myService.fetchDuration()); // set the max value of the seekbar to be the duration of the song
  61. r = new Runnable()
  62. {
  63. @Override
  64. public void run()
  65. {
  66. int tempInt = myService.fetchProgress();
  67. Log.d("progress ticking", tempInt + " " + musicProgBar.getProgress());
  68. musicProgBar.setProgress(tempInt); // sets the current progress of the seekbar to be the progress of the song
  69. long minutes = TimeUnit.MILLISECONDS.toMinutes(tempInt);
  70. long seconds = TimeUnit.MILLISECONDS.toSeconds(tempInt);
  71. if (seconds >= 60)
  72. seconds = seconds - 60;
  73. String tempString = minutes + ":" + seconds;
  74. progressText.setText(tempString);
  75. progBarHandler.postDelayed(this, progBarDelay);
  76. if (musicProgBar.getProgress() == myService.fetchDuration())
  77. progBarHandler.removeCallbacks(this);
  78. }
  79. };
  80. progBarHandler.post(r);
  81. }});
  82. }
  83. private ServiceConnection serviceConnection = new ServiceConnection()
  84. {
  85. @Override
  86. public void onServiceConnected(ComponentName name, IBinder service)
  87. {
  88. myService = (MP3Service.MyBinder) service;
  89. }
  90. @Override
  91. public void onServiceDisconnected(ComponentName name)
  92. {
  93. myService = null;
  94. }
  95. };
  96. public void playButClicked(View view)
  97. {
  98. myService.playMusic();
  99. }
  100. public void pauseButClicked(View view)
  101. {
  102. myService.pauseMusic();
  103. }
  104. public void stopButClicked(View view)
  105. {
  106. myService.stopMusic();
  107. }
  108. @Override
  109. protected void onDestroy()
  110. {
  111. unbindService(serviceConnection);
  112. progBarHandler.removeCallbacks(r);
  113. super.onDestroy();
  114. }
  115. }

奇怪的是,在ondestroy()中,我确实使用removecallbacks来结束处理程序,而且效果很好。我知道它在runnable r中调用removecallbacks,这是通过调试和日志记录确认的。还尝试了实现一个方法,该方法专门用于删除处理程序并调用它,但运气不好。还尝试使用return。
我正在挣扎的部分是

  1. r = new Runnable()
  2. {
  3. @Override
  4. public void run()
  5. {
  6. int tempInt = myService.fetchProgress();
  7. Log.d("progress ticking", tempInt + " " + musicProgBar.getProgress());
  8. musicProgBar.setProgress(tempInt); // sets the current progress of the seekbar to be the progress of the song
  9. long minutes = TimeUnit.MILLISECONDS.toMinutes(tempInt);
  10. long seconds = TimeUnit.MILLISECONDS.toSeconds(tempInt);
  11. if (seconds >= 60)
  12. seconds = seconds % 60;
  13. String tempString = minutes + ":" + seconds;
  14. progressText.setText(tempString);
  15. progBarHandler.postDelayed(this, progBarDelay);
  16. if (musicProgBar.getProgress() == myService.fetchDuration())
  17. progBarHandler.removeCallbacks(this);
  18. }
  19. };
  20. progBarHandler.post(r);
  21. }});

处理音乐播放器和播放音乐的服务

  1. import android.app.Notification;
  2. import android.app.NotificationChannel;
  3. import android.app.NotificationManager;
  4. import android.app.PendingIntent;
  5. import android.app.Service;
  6. import android.content.Intent;
  7. import android.os.Binder;
  8. import android.os.Build;
  9. import android.os.Handler;
  10. import android.os.IBinder;
  11. import android.util.Log;
  12. import androidx.annotation.Nullable;
  13. import androidx.core.app.NotificationCompat;
  14. public class MP3Service extends Service
  15. {
  16. public static MP3Service instance = null; // implementing singleton by instantiating a reference to the instance
  17. private final String SERVICE_ID = "100"; // id for the service
  18. public static boolean isRunning = false; //
  19. NotificationManager notificationManager = null;
  20. int notificationID = 001;
  21. private final IBinder binder = new MyBinder();
  22. MP3Player mainPlayer;
  23. @Nullable
  24. @Override
  25. public IBinder onBind(Intent intent)
  26. {
  27. return binder;
  28. }
  29. @Override
  30. public void onRebind(Intent intent)
  31. {
  32. // TODO: implement Rebind for screen orientation change
  33. }
  34. @Override
  35. public void onCreate()
  36. {
  37. instance = this;
  38. isRunning = true;
  39. notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
  40. mainPlayer = new MP3Player();
  41. super.onCreate();
  42. Handler handler = new Handler();
  43. }
  44. @Override
  45. public void onDestroy()
  46. {
  47. isRunning = false;
  48. instance = null;
  49. notificationManager.cancel(notificationID);
  50. }
  51. public void createNotification()
  52. {
  53. CharSequence name = "MP3 Notification";
  54. String description = "Displays a notification when a song is playing";
  55. int importance = NotificationManager.IMPORTANCE_DEFAULT;
  56. NotificationChannel channel = new NotificationChannel(SERVICE_ID, name, importance);
  57. channel.setDescription(description);
  58. notificationManager.createNotificationChannel(channel);
  59. Intent intent = new Intent(this, MainActivity.class);
  60. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
  61. // when the user clicks the notification, this will bring them to the activity
  62. PendingIntent navToMainActivity = PendingIntent.getActivity(this, 0, intent, 0);
  63. // sets up the info and details for the notification
  64. final NotificationCompat.Builder mNotification = new NotificationCompat.Builder(this, SERVICE_ID)
  65. .setSmallIcon(R.drawable.ic_launcher_background)
  66. .setContentTitle("MP3 Player")
  67. .setContentText("Playing music")
  68. .setContentIntent(navToMainActivity)
  69. .setPriority(NotificationCompat.PRIORITY_DEFAULT);
  70. startForeground(notificationID, mNotification.build());
  71. }
  72. public void removeNotification()
  73. {
  74. stopForeground(false);
  75. notificationManager.cancelAll();
  76. }
  77. public class MyBinder extends Binder
  78. {
  79. public void loadMusic(String filePath)
  80. {
  81. mainPlayer.load(filePath);
  82. }
  83. public void playMusic()
  84. {
  85. mainPlayer.play();
  86. createNotification();
  87. }
  88. public void pauseMusic()
  89. {
  90. mainPlayer.pause();
  91. removeNotification();
  92. }
  93. public void stopMusic()
  94. {
  95. mainPlayer.stop();
  96. removeNotification();
  97. }
  98. public MP3Player.MP3PlayerState fetchPlayerState()
  99. {
  100. return mainPlayer.getState();
  101. }
  102. public int fetchDuration()
  103. {
  104. return mainPlayer.getDuration();
  105. }
  106. public int fetchProgress()
  107. {
  108. return mainPlayer.getProgress();
  109. }
  110. }
  111. }

提前感谢您的帮助,如有需要,我很乐意提供更多信息
编辑:将runnable之外的progbarhandler.postdelay()更改为简单的progbarhandler.post()

ltqd579y

ltqd579y1#

我认为您未能停止处理程序的唯一原因是不断调用 progBarHandler.postDelayed(this, progBarDelay); ,您需要检查它为什么仍在运行。

oxcyiej7

oxcyiej72#

通过向runnable引入不同类型的if语句,成功地使其工作,如

  1. Runnable r = new Runnable()
  2. {
  3. @Override
  4. public void run()
  5. {
  6. if (musicProgBar.getProgress() == myService.fetchProgress() && myService.fetchProgress() != 0)
  7. Log.d("audio", "over");
  8. else {
  9. int tempInt = myService.fetchProgress();
  10. long minutes = TimeUnit.MILLISECONDS.toMinutes(tempInt);
  11. long seconds = TimeUnit.MILLISECONDS.toSeconds(tempInt);
  12. if (seconds >= 60)
  13. seconds = seconds % 60;
  14. String tempString = minutes + ":" + seconds;
  15. progressText.setText(tempString);
  16. musicProgBar.setProgress(tempInt); // sets the current progress of the seekbar to be the progress of the song
  17. progBarHandler.postDelayed(this, progBarDelay);
  18. }
  19. }
  20. };

出于某种原因,使用.fetchduration()和.fetchprogress()似乎永远不会互相均衡,因此更改if语句是有效的。

展开查看全部

相关问题