使用动态“时间”值

时间:2015-08-21 01:11:55

标签: java

Google Play:

上查看我的应用
  

代码已更新为使用答案提供的建议,但仍然遇到一些问题......

我在服务中使用BroadCast Receiver从Spotify(外部应用程序)获取元数据。但是,Spotify的独特之处在于它发送了以下意图操作:

  1. metadatachanged ,其中包含歌曲的艺术家,曲目,长度等。
  2. playbackstatechanged ,其中包含“播放”的布尔值和歌曲中当前位置的整数值。
  3. 但是,我遇到了一些问题。我写了以下代码:

    public class BackgroundService extends Service {
    
    AudioManager am;
    int positionInMs;
    double eps = 5000;
    
    String trackId = null;
    String lastTrackId = null;
    int lastPlayTime = 0;
    int addSeconds = 0;
    int trackLengthInSec = 0;
    boolean playing = false;
    boolean timerStarted = false;
    
    void startTimer(){
        timerStarted = true;
        new Timer(true).scheduleAtFixedRate(
                new TimerTask() {
                    @Override
                    public void run() {
                        if(playing) {
                            if(lastTrackId == null) {
    
                                lastTrackId = trackId;
    
                            }else if (!lastTrackId.equals(trackId)) {
    
                                addSeconds = 1;
                                playing = true;
                                lastPlayTime = positionInMs;
                                // Track changed. Reset counter.
    
                            }else{
    
                                addSeconds++; // Increment counter.
    
                            }
    
                            checkMuteStatus(trackLengthInSec, lastPlayTime + addSeconds * 1000 // multiply by 1000 as we're counting in seconds
                            );
                        }
    
                        Log.e("-------:", "Last Play Time: " + String.valueOf(lastPlayTime));
                        Log.e("-------:", "Track Length: " + String.valueOf(trackLengthInSec));
                        Log.e("-------:", "Current Position: " + String.valueOf(lastPlayTime + addSeconds * 1000));
    
                    }
                },
                1000, // Wait a second before first run
                1000 // Runs every second
        );
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
    
        am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
    
        IntentFilter filter;
        filter = new IntentFilter();
        filter.addAction("com.spotify.music.playbackstatechanged");
        filter.addAction("com.spotify.music.metadatachanged");
        filter.addAction("com.spotify.music.queuechanged");
    
        Notification notification = new Notification();
        startForeground(1, notification);
        registerReceiver(receiver, filter);
    
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    
        return super.onStartCommand(intent, flags, startId);
    }
    
    private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) throws NullPointerException {
    
            long timeSentInMs = intent.getLongExtra("timeSent", 0L);
    
            String action = intent.getAction();
    
            if (action.equals(BroadcastTypes.METADATA_CHANGED)) {
    
                trackId = intent.getStringExtra("id");
                String artistName = intent.getStringExtra("artist");
                String albumName = intent.getStringExtra("album");
                String trackName = intent.getStringExtra("track");
                trackLengthInSec = intent.getIntExtra("length", 0);
    
                Log.e("STATUS:", trackName);
                Log.e("STATUS:", artistName);
                Log.e("STATUS:", albumName);
                Log.e("STATUS:", "TRACK LENGTH: " + String.valueOf(trackLengthInSec));
                Log.e("STATUS:", trackId);
    
                Log.e("STATUS:", "POSITION: " + String.valueOf(positionInMs));
    
                if(!timerStarted) {
    
                    startTimer();
    
                }
    
    
    
    
                //---------------------- IF PAUSED OR SONG CHANGED---------------------
    
            } else if (action.equals(BroadcastTypes.PLAYBACK_STATE_CHANGED)) {
    
                playing = intent.getBooleanExtra("playing", false);
                positionInMs = intent.getIntExtra("playbackPosition", 0);
    
                lastPlayTime = positionInMs;
                addSeconds = 0; // Reset counter as we've now got the current position.
    
                if(!timerStarted) {
    
                    startTimer();
    
                }
    
            }
    
        }
    
    };
    
        void checkMuteStatus(double trackLength, double currentTime) {
    
            if (Math.abs(trackLength - currentTime) < eps) {
    
                mute(am);
                Log.e("STATUS:", "MUTED");
                addSeconds = 0;
                lastPlayTime = 0;
    
    
            } else {
    
                unMute(am);
                Log.e("STATUS:", "NOT MUTED");
    
    
            }
    
        }
    
    
    
    
    @Override
    public void onDestroy() {
        super.onDestroy();
    
        Log.e("STATUS:", "In onDestroy");
    
        unregisterReceiver(receiver);
    }
    
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    
    static final class BroadcastTypes {
        static final String SPOTIFY_PACKAGE = "com.spotify.music";
        static final String PLAYBACK_STATE_CHANGED = SPOTIFY_PACKAGE + ".playbackstatechanged";
        static final String METADATA_CHANGED = SPOTIFY_PACKAGE + ".metadatachanged";
    }
    
    public void mute(AudioManager audioManager){
    
        audioManager.setStreamMute(audioManager.STREAM_SYSTEM, true);
        audioManager.setStreamMute(AudioManager.STREAM_NOTIFICATION, true);
        audioManager.setStreamMute(AudioManager.STREAM_ALARM, true);
        audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
        audioManager.setStreamMute(AudioManager.STREAM_RING, true);
    
    }
    
    public void unMute(AudioManager audioManager){
    
        audioManager.setStreamMute(audioManager.STREAM_SYSTEM,false);
        audioManager.setStreamMute(AudioManager.STREAM_NOTIFICATION, false);
        audioManager.setStreamMute(AudioManager.STREAM_ALARM, false);
        audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false);
        audioManager.setStreamMute(AudioManager.STREAM_RING, false);
    
    }
    
    
    }
    

    这一切在获取数据等方面都非常有效。

    基本上,当从歌曲中当前播放时间减去的歌曲长度小于某个数字时,我试图将用户的手机静音。这基本上允许我在广告播放时将设备静音,并在启动新歌时取消静音。我遇到的唯一问题是我只能在播放状态改变时访问歌曲中的当前位置。这实际上意味着为了让我的应用程序检查是否应该静音设备,必须首先暂停Spotify,以便更新当前播放时间。

    所以我的问题是,如何让我当前的播放时间保持最新,以便我的静音功能能够正常工作?有没有办法可以实现一种“定时器”,它在我收到当前播放时间的值后开始播放,然后增加时间直到下一次更新?

1 个答案:

答案 0 :(得分:1)

你可以开始播放歌曲时每秒执行的timer,然后用它来跟踪自那以后经过的秒数。

private final BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) throws NullPointerException {
        long timeSentInMs = intent.getLongExtra("timeSent", 0L);
        String action = intent.getAction();     

        if (action.equals(BroadcastTypes.METADATA_CHANGED)) {

             trackId = intent.getStringExtra("id");

             String artistName = intent.getStringExtra("artist");
             String albumName = intent.getStringExtra("album");
             String trackName = intent.getStringExtra("track");

             trackLengthInSec = intent.getIntExtra("length", 0);

             Log.e("STATUS:", trackName);
             Log.e("STATUS:", artistName);
             Log.e("STATUS:", albumName);
             Log.e("STATUS:", "TRACK LENGTH: " + String.valueOf(trackLengthInSec));
             Log.e("STATUS:", trackId);

             Log.e("STATUS:", "POSITION: " + String.valueOf(positionInMs));

             // the new track id is always updated just before the next song is played
             // so we can safely assume that the ad has finished playing and it's time to unmute
             unMute(am);

             // reset & resume the timer                 
             lastPlayTime = 0; 
             addSeconds = 0;
             currentlyAdPlaying = false;


             if(!timerStarted)
                startTimer();

            //---------------------- IF PAUSED OR SONG CHANGED---------------------

        } else if (action.equals(BroadcastTypes.PLAYBACK_STATE_CHANGED)) {
            playing = intent.getBooleanExtra("playing", false);
            positionInMs = intent.getIntExtra("playbackPosition", 0);

            // this is just needed to correct an eventually existing offset from the real time. 
            lastPlayTime = positionInMs;
            addSeconds = 0; // Reset counter as we've now got the current position.

            checkMuteStatus(trackLengthInSec, positionInMs);


        }
    }

};


String trackId = null;
String lastTrackId = null;
int lastPlayTime = 0;
int addSeconds = 0;
int trackLengthInSec = 0;
boolean playing = false;
boolean timerStarted = false;
boolean currentlyAdPlaying = true;

void startTimer(){   
    timerStarted = true;
    new Timer(true).scheduleAtFixedRate(
        new TimerTask() {
            @Override
            public void run() { 
                if(playing && !currentlyAdPlaying) {
                    if(lastTrackId == null)
                        lastTrackId = trackId;

                    if(lastTrackId != trackId){
                        lastTrackId = trackId;                      
                        addSeconds = 1; // Track changed. Reset counter.
                    } else {                            
                        addSeconds++; // Increment counter.
                    }

                    checkMuteStatus(
                        trackLengthInSec,
                        lastPlayTime + addSeconds * 1000
                    );
                }
            }
        }, 
        1000, // Wait a second before first run
        1000 // Runs every second
    );
}

void checkMuteStatus(double trackLength, double currentTime) {

    // trackLength is in seconds, but currentTime in MS. 
    // So we should be changing trackLength to MS as well, right?
    trackLength *= 1000;

    if (Math.abs(trackLength - currentTime) < eps) {

        mute(am);            
        Log.e("STATUS:", "MUTED");

        // pause the timer, for an ad is playing.
        currentlyAdPlaying = true;

    } else {

        unMute(am);
        Log.e("STATUS:", "NOT MUTED");


    }

}

基本上,计时器每秒运行一次(从广告播放完毕开始),然后只要歌曲没有暂停就递增计数器。在到达歌曲结束时,计时器暂停,因为下一个广告将播放。广告播放完毕后,计时器将重置并再次恢复。 使用这种方法,您可能会在半秒左右的时间内关闭,如果需要,可以考虑减少计时器间隔以获得更高的分辨率(不要忘记调整乘数)。

<小时/> 修改
上面的代码没有注意到用户改变了曲目中段歌曲,因为在那种情况下没有发送广播。解决方法可能是使用notifications添加静音按钮(例如,与FLAG_NO_CLEARFLAG_ONGOING_EVENT结合使用。)