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

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

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

import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {

    SeekBar musicProgBar;
    Handler progBarHandler = null;
    Runnable r = null;
    private MP3Service.MyBinder myService = null;
    TextView progressText = null;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        musicProgBar = findViewById(R.id.musicProgressBar);
        progressText = findViewById(R.id.progressText);
        final ListView lv = (ListView) findViewById(R.id.musicList);
        Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                null,
                MediaStore.Audio.Media.IS_MUSIC + "!= 0",
                null,
                null);

        progBarHandler = new Handler();
        final int progBarDelay = 1000; // delay for the handler, making it repeat itself only every 1000 miliseconds (1 second)

        lv.setAdapter(new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_1,
                cursor,
                new String[] { MediaStore.Audio.Media.DATA},
                new int[] { android.R.id.text1 }));

        Intent tempIntent = new Intent(this, MP3Service.class);
        startService(tempIntent);
        bindService(tempIntent, serviceConnection, 0);

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> myAdapter,
                                    View myView,
                                    int myItemInt,
                                    long myLong) {
                Cursor c = (Cursor) lv.getItemAtPosition(myItemInt);
                String uri = c.getString(c.getColumnIndex(MediaStore.Audio.Media.DATA));
                Log.d("g53mdp", uri);

                if (myService.fetchPlayerState() != MP3Player.MP3PlayerState.STOPPED)
                    myService.stopMusic();

                myService.loadMusic(uri);
                myService.playMusic();
                musicProgBar.setMax(myService.fetchDuration()); // set the max value of the seekbar to be the duration of the song
                r = new Runnable()
                {
                    @Override
                    public void run()
                    {
                        int tempInt = myService.fetchProgress();
                        Log.d("progress ticking", tempInt + " " + musicProgBar.getProgress());
                        musicProgBar.setProgress(tempInt); // sets the current progress of the seekbar to be the progress of the song
                        long minutes = TimeUnit.MILLISECONDS.toMinutes(tempInt);
                        long seconds = TimeUnit.MILLISECONDS.toSeconds(tempInt);
                        if (seconds >= 60)
                            seconds = seconds - 60;
                        String tempString = minutes + ":" + seconds;
                        progressText.setText(tempString);
                        progBarHandler.postDelayed(this, progBarDelay);
                        if (musicProgBar.getProgress() == myService.fetchDuration())
                            progBarHandler.removeCallbacks(this);
                    }
                };
                progBarHandler.post(r);
            }});
    }

    private ServiceConnection serviceConnection = new ServiceConnection()
    {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            myService = (MP3Service.MyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name)
        {
            myService = null;
        }
    };

    public void playButClicked(View view)
    {
        myService.playMusic();
    }

    public void pauseButClicked(View view)
    {
        myService.pauseMusic();
    }

    public void stopButClicked(View view)
    {
        myService.stopMusic();
    }

    @Override
    protected void onDestroy()
    {
        unbindService(serviceConnection);
        progBarHandler.removeCallbacks(r);
        super.onDestroy();
    }
}

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

r = new Runnable()
                {
                    @Override
                    public void run()
                    {
                        int tempInt = myService.fetchProgress();
                        Log.d("progress ticking", tempInt + " " + musicProgBar.getProgress());
                        musicProgBar.setProgress(tempInt); // sets the current progress of the seekbar to be the progress of the song
                        long minutes = TimeUnit.MILLISECONDS.toMinutes(tempInt);
                        long seconds = TimeUnit.MILLISECONDS.toSeconds(tempInt);
                        if (seconds >= 60)
                            seconds = seconds % 60;
                        String tempString = minutes + ":" + seconds;
                        progressText.setText(tempString);
                        progBarHandler.postDelayed(this, progBarDelay);
                        if (musicProgBar.getProgress() == myService.fetchDuration())
                            progBarHandler.removeCallbacks(this);
                    }
                };
                progBarHandler.post(r);
            }});

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

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

public class MP3Service extends Service
{
    public static MP3Service instance = null; // implementing singleton by instantiating a reference to the instance
    private final String SERVICE_ID = "100"; // id for the service
    public static boolean isRunning = false; //
    NotificationManager notificationManager = null;
    int notificationID = 001;
    private final IBinder binder = new MyBinder();
    MP3Player mainPlayer;

    @Nullable
    @Override
    public IBinder onBind(Intent intent)
    {
        return binder;
    }

    @Override
    public void onRebind(Intent intent)
    {
        // TODO: implement Rebind for screen orientation change
    }

    @Override
    public void onCreate()
    {
        instance = this;
        isRunning = true;
        notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        mainPlayer = new MP3Player();
        super.onCreate();
        Handler handler = new Handler();
    }

    @Override
    public void onDestroy()
    {
        isRunning = false;
        instance = null;
        notificationManager.cancel(notificationID);
    }

    public void createNotification() 
    {
        CharSequence name = "MP3 Notification";
        String description = "Displays a notification when a song is playing";
        int importance = NotificationManager.IMPORTANCE_DEFAULT;
        NotificationChannel channel = new NotificationChannel(SERVICE_ID, name, importance);
        channel.setDescription(description);
        notificationManager.createNotificationChannel(channel);

        Intent intent = new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        // when the user clicks the notification, this will bring them to the activity
        PendingIntent navToMainActivity = PendingIntent.getActivity(this, 0, intent, 0);

        // sets up the info and details for the notification
        final NotificationCompat.Builder mNotification = new NotificationCompat.Builder(this, SERVICE_ID)
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentTitle("MP3 Player")
                .setContentText("Playing music")
                .setContentIntent(navToMainActivity)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT);

        startForeground(notificationID, mNotification.build());
    }

    public void removeNotification()
    {
        stopForeground(false);
        notificationManager.cancelAll();
    }

    public class MyBinder extends Binder
    {
        public void loadMusic(String filePath)
        {
            mainPlayer.load(filePath);
        }

        public void playMusic()
        {
            mainPlayer.play();
            createNotification();
        }

        public void pauseMusic()
        {
            mainPlayer.pause();
            removeNotification();
        }

        public void stopMusic()
        {
            mainPlayer.stop();
            removeNotification();
        }

        public MP3Player.MP3PlayerState fetchPlayerState()
        {
            return mainPlayer.getState();
        }

        public int fetchDuration()
        {
            return mainPlayer.getDuration();
        }

        public int fetchProgress()
        {
            return mainPlayer.getProgress();
        }
    }
}

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

ltqd579y

ltqd579y1#

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

oxcyiej7

oxcyiej72#

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

Runnable r = new Runnable()
{
    @Override
    public void run()
    {
        if (musicProgBar.getProgress() == myService.fetchProgress() && myService.fetchProgress() != 0)
            Log.d("audio", "over");
        else {
            int tempInt = myService.fetchProgress();
            long minutes = TimeUnit.MILLISECONDS.toMinutes(tempInt);
            long seconds = TimeUnit.MILLISECONDS.toSeconds(tempInt);
            if (seconds >= 60)
                seconds = seconds % 60;
            String tempString = minutes + ":" + seconds;
            progressText.setText(tempString);
            musicProgBar.setProgress(tempInt); // sets the current progress of the seekbar to be the progress of the song
            progBarHandler.postDelayed(this, progBarDelay);
        }
    }
};

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

相关问题