1.拔插u盘的播放记忆
对于音乐应用来说拔插U盘会收到来自TW服务发送的0x9e1f拔插数据 其中msg.arg2数据0为拔出,1为插入, 当收到0时并且确认当前正在播放的文件为插拔的U盘时,会stopMusic,并且清空临时播放列表
代码语言:javascript复制if(msg.arg2 == 0) {
mTW.mPlaylistRecord.clearRecord();
stopMusic();
}
而此时的播放信息(进度,播放路径等)并未置为初始状态 所以当插入U盘时, 如果判断之前的播放路径为插入的U盘路径 则根据播放路径找到临时播放列表 然后直接进行播放即可
代码语言:javascript复制mTW.loadFile(mContext,mTW.mPlaylistRecord, mTW.mCurrentPath);
mTW.toRPlaylist(mTW.mCurrentIndex);
if(!isPlaying() && (mTW.getService() == TWMusic.ACTIVITY_RUSEME)) {
if(prepare(mTW.mCurrentAPath) == 0 && !isPlaying()) {
seekTo(mTW.mCurrentPos);
playMusic();
}
duck(false);
}
只要注意这种状态下播放进度的更新mCurrentPos值,不要置为0,即可保证记忆播放 还有一点要注意的是,有的平台插入U盘时,会连续发送0和1过来,需要修改为插入U盘只发送1,否则会导致播放记忆异常
2.断ACC启动的播放记忆
音乐关于播放状态的记忆形式,目前是以file文件存储的方式,这样做可以保证其他应用可以调用到保存的文件,例如主界面 保存在以下时机时更新
播放新的文件
方控停止
程序完全销毁
音乐界面退出 保存的逻辑为
代码语言:javascript复制try {
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter("/data/tw/music"));
bw.write(mCurrentAPath);
bw.write('n');
bw.write(Integer.toString(mCurrentIndex));
bw.write('n');
bw.write(Integer.toString(mCurrentPos));
XTLog.i(mCurrentPos);
bw.write('n');
bw.write(Integer.toString(mShuffle));
bw.write('n');
bw.write(Integer.toString(mRepeat));
bw.write('n');
bw.flush();
mTW.write(0x9f1a,1,0,"sync");
} catch (Exception e) {
XTLog.i();
new File("/data/tw/music").delete();
} finally {
if(bw != null) {
bw.close();
bw = null;
}
}
FileUtils.setPermissions("/data/tw/music", 0666, -1, -1);
} catch (Exception e) {
Log.i(TAG, "" e.toString());
}
保存的位置为
代码语言:javascript复制/data/tw/music
读取的方式为TWUtils走open,也就是应用初始化的时候读取保存的播放信息更新 然后应用在走onresume的生命周期时进行记忆播放
代码语言:javascript复制if (!isPlaying() && mTW.mSource == 0x03){
if(prepare(mTW.mCurrentAPath) == 0) {
seekTo(mTW.mCurrentPos);
playMusic();
}
}
3.退出进入音乐的播放记忆
先介绍音乐的view层与mode层的绑定逻辑 首先要明确mode是单例的,当音乐activirty启动和音乐服务启动时,都会绑定这个mode
代码语言:javascript复制private void BindView(){
mModel.bindMsuiclView(this,mContext);
}
public void onCreate(){
BindView();
}
mode对应的处理是添加到一个view集合中
代码语言:javascript复制@Override
public void bindMsuiclView(MusicModelView musicPresenter,Context context) {
if (musicModelViews.size() == 0){
this.mContext = context;
onCreate();
}
if (!musicModelViews.contains(musicPresenter)){
musicModelViews.add(musicPresenter);
}
}
当音乐activity和音乐服务都退出时, 会解绑各自的对象
代码语言:javascript复制public void onDestroy() {
unBindView();
}
private void unBindView(){
mModel.unBindMsuiclView(this);
}
view集合也会对应remove对应的对象
代码语言:javascript复制@Override
public void unBindMsuiclView(MusicModelView musicPresenter) {
if (musicModelViews.contains(musicPresenter)){
musicModelViews.remove(musicPresenter);
}
if (musicModelViews.size()==0){
onDestory();
}
saveData();
}
当没有view绑定mode时(musicModelViews.size()==0)mode才会自毁回收 所以当音乐activity返回退出时,其实mode对象处于被音乐服务持有运行的状态 而根据服务的生存特性,当activity销毁时服务其实还在在后台运行,
代码语言:javascript复制@Override
protected void onDestroy() {
mPresenter.onPause();
mPresenter.musicPause();
mPresenter.onDestroy();
音乐activity退出时,只做暂停和解绑处理,此时播放器仅仅是暂停状态 所以当音乐activity重新启动时,走到onresume时,会恢复退出之前的播放状态,并更新播放信息。
4.启动360状态的播放记忆
正常情况下,非断电重启时,机器会根据模式恢复程序运行,而针对一些带DVR和360的平台,例如T5,TS10, 有强制启动DVR/360的启动方式,当跟音乐同时启动时,根据机器性能和状态,有可能会导致音乐播放异常问题。 所以这时候,音乐这边是建议当判断要启动360时,音乐只以启动服务的方式运行在后台 具体的操作放在TW服务中携带一个Extra启动音乐服务
代码语言:javascript复制startServiceAPK("com.tw.music","com.tw.music.MusicService","resume");
...
private void startServiceAPK(String pkg, String cls, String cmd) {
try {
Intent it = new Intent();
it.setComponent(new ComponentName(pkg, cls));
it.putExtra("cmd", cmd);
startService(it);
} catch (Exception e) {
}
}
音乐服务会自启播放
代码语言:javascript复制else if ("resume".equals(cmd)){
if (!mMusicInfo.isPlaying()){
mPresenter.musicPlay();
}
}