The last time we talked about the realization of music playback, this time the most complicated progress bar and lyrics update. Because of the need to interact between the playing activity and the service being played, it involves the binding of the activity to the service and the transfer of the data after the binding, which requires familiarity with the service binding. The principle is not complicated. But the steps are a little cumbersome, and the code may be very confusing to paste.
The progress bar and lyrics put together to say better, or more chaotic. Progress bar Adjustment We all know, is the progress of the tune to where the song play to follow where, lyrics also have to follow where. First look at the binding code for the service in the Start button listener event that was seen in the previous article:
/ / Bind the playback service
bindService(intent, conn,BIND_AUTO_CREATE);
//Runnable object adds message queue, runs in the thread bound by the handler, used for lyrics update
Handler.post(updateTimeCallback);
Start = System.currentTimeMillis();
Bindservice (Intent, conn,bind_auto_create); The conn in is a callback interface after the binding service. Let's look at the code:
/**
* Passed into the callback interface in bindService()
*/
ServiceConnection conn = new ServiceConnection(){
@Override
Public void onServiceConnected(ComponentName arg0, IBinder binder) {//This method is called after the binding is successful.
PlayActivity.this.binder = (Binder)binder;
}
@Override
Public void onServiceDisconnected(ComponentName arg0) {
}
};
is actually a statement. The function is to assign the IBinder object reference returned by the playback service to play activity so that the activity can get the data returned by the services, and we are here to get the progress data that is playing at this point.
Handler.post (updatetimecallback); is to add a Runnable object to the queue. This runnable object updatetimecallback
is to implement the Code of the core implementation of the progress bar and the lyrics update, just before looking at this class. Let's look at the monitoring events for the progress bar:
/**
* After experimenting, the progress bar is mobilized before and after the transfer is merged into a way to achieve the update of the lyrics, which may be caused by the synchronization of resources between different threads.
* Before the progress bar is moved (change == false) and after the transfer (change == true), the two parts run in the thread of lyrics update.
* @author yan
*
*/
Class SeekBarListener implements OnSeekBarChangeListener{
@Override
Public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
Public void onStartTrackingTouch(SeekBar arg0) {
Log.d("yinan", "start--------"+seekBar.getProgress());
}
@Override
Public void onStopTrackingTouch(SeekBar arg0) {
If(stopMusic == false){
Change = true; / / progress bar progress changes. Send the changed progress to the playback service
Intent intent = new Intent();
intent.setClass(PlayActivity.this, PlayService.class);
intent.putExtra("progress", seekBar.getProgress());
startService(intent);
}else{
seekBar.setProgress(0);
}
}
}
After adjusting the position of the progress bar, the StartService (intent) mode is still used. Intent object that encapsulates the progress of the progress bar is passed to the service's Onstartcommand method for processing.
now take a look at the implementation of the core code runnable object updatetimecallback class:
/**
* Asynchronously adjust the progress bar position to match the song progress and display the lyrics class
* @author yinan
*
*/
Class UpdateTimeCallback implements Runnable{
Queue times = null;
Queue messages = null;
ArrayList<Queue> queues = null;
Public UpdateTimeCallback(ArrayList<Queue> queues){
Times = queues.get(0);
Messages = queues.get(1);
This.queues = queues;
}
/**
* The run method does not open child threads because there is no use of start. So open the child thread internally
*/
@Override
Public void run() {
Total = PlayService.totalLength;
If(change == true){
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeString("change");
Try {
Binder.transact(0, data, reply, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
//Run this sentence until Service returns
Float s = reply.readFloat();//s is the time progress of the song playing
Float f = s*100;
seekBar.setProgress((int)f);//converted to progress bar progress
/ / At this time the corresponding playback time point
Final long t = (long) (s*total);
Preparelrc(mp3Info.getLrcName());
Times = queues.get(0);
Messages = queues.get(1);
System.out.println("times"+times.size());
System.out.println("messages"+messages.size());
If(stopMusic == false){
New Thread(){
Public void run(){
While(nextTime < t){ // traverse the lyrics from the beginning, the time queue until the time point is greater than the current time
System.out.println("nextTime"+nextTime);//////////////////////////////////
Lyric = message;
If((times.size()>0)||messages.size()>0){
nextTime = (Long)times.poll();
Message = (String)messages.poll();
}else{
Lyric = null;
stopMusic = true;
}//Save the time point just above the current time, the closest lyrics
System.out.println("nextTime"+nextTime);
}
}
}.start();
System.out.println("lyric"+lyric);
If(lyric != null){
lrcText.setText(lyric);
}
}
}
If(!change){
nowTime = System.currentTimeMillis() - start;
seekBar.setProgress((int)(nowTime*100/total));
If(stopMusic == false){
New Thread(){
Public void run(){
While(nextTime < nowTime){ // traverse the lyrics from scratch. Time queue until the time point is less than the current time
System.out.println("nextTime"+nextTime);
Lyric = message; / / save the time point just above the current time of the last lyrics, that is, the closest to the current lyrics
If((times.size()>0)||messages.size()>0){
nextTime = (Long)times.poll();
Message = (String)messages.poll();
}else{
Lyric = null;
stopMusic = true;
}
}
}
}.start();
If(lyric != null){
lrcText.setText(lyric);
}
}
}
If(stopMusic == true){
handler.removeCallbacks(updateTimeCallback);
}
handler.postDelayed( updateTimeCallback, 200);//Run the thread every 20 milliseconds
}
}
This code is roughly when you get the data for the real-time progress of the songs returned by the service, adjust the position of the progress bar to the corresponding child's processing, and then update the lyrics to the appropriate section. because the progress bar to follow up in real time. AllThe Run method of the Updatetimecallback class is run every 200 milliseconds to get the return value in the service.
Here is the situation where the processing is divided into the progress bar has been changed and not changed in two cases, with the flag bit change (once the progress bar has been changed to run the changes to true that piece of code).
Threading is due to the time-consuming processing of lyrics. Not fit on the UI thread.
The detailed process is:
First, Parcel data = Parcel.obtain ();
Parcel reply = Parcel.obtain ();
Data.writestring ("Change");
Binder.transact (0, data, reply, 0);
Binder is the IBinder object that was previously bound to the service,binder.transact A Parcel object (incoming"Change" However, a flag is passed to the service, and then the service returns the song progress, which is received in float s = reply.readfloat (), and S is a percentage of the total progress of the current progress. Then you can set the progress bar position.
The lyrics update is then processed.
The first is to prepare the lyrics for processing,PREPARELRC (Mp3info.getlrcname ()), the LRC format lyrics in the time and the corresponding detailed lyrics split into two queues. (See the source code for detailed code) and then play the progress based on the songs returned by the service. Iterates over two queues. When there is a point in time that exceeds the corresponding point in time, the corresponding lyrics of that time Point are taken out and displayed on the activity.
The front always says that the service returns the song in real-time progress, and we look at the processing of the data return in the service.
When the progress bar is adjusted. Will enter the service's Onstartcommand method and enter into the following if statement:
if(intent.getIntExtra("progress", 0) != 0){///////////////////////
if(isPlay){
//进度条进度
int progress = intent.getIntExtra("progress", 0);
if(progress != 0)
//将音乐进度调整到相应位置
mediaPlayer.seekTo(progress*totalLength/100);
}
}
How does the service return the progress of the song in real time? There is a binder class in the service. is a subclass of IBinder:
/*
*Run after running binder.transact()
*/
Class FirstBinder extends Binder{
@Override
Protected boolean onTransact(int code, Parcel data, Parcel reply,
Int flags) throws RemoteException {
String str = data.readString();
Int currentPosition = mediaPlayer.getCurrentPosition();
Float s = (float)currentPosition/mediaPlayer.getDuration();
If(isPlay)
reply.writeFloat(s);
Return super.onTransact(code, data, reply, flags);
}
Yes, I do. It is the IBinder object that was obtained prior to the activity and service binding. whenever the activitybinder.transact (0, data, reply, 0); The service calls the Ontransact method. Load the acquired data into the parcel object reply and return the entire
MP 3 player This is the end of the story, it may be very messy. I hope it will be of help to you. SOURCE Download Link: http://download.csdn.net/detail/sinat_23092639/8933995
Android MP3 Player Development Example (3) progress bar and Lyrics update implementation