Android学习_Mars老师之Mp3视频开发

实现的功能:开发一个可以播放音乐并同步显示歌词文件的APP.

成果展示:

成果展示

总体设计图:

总体设计图

实现流程图

实现流程图

代码展示:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.mp3player">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Mp3Player"
        tools:targetApi="31">

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name=".Mp3ListActivity"
            tools:ignore="Instantiatable"
            android:label="@string/app_name" />

        <activity
            android:name=".PlayerActivity"
            tools:ignore="DuplicateActivity,Instantiatable"
            android:label="@string/app_name" />

        <activity
            android:name=".LocalMp3ListActivity"
            tools:ignore="DuplicateActivity,Instantiatable"
            android:label="@string/app_name" />

        <service android:name="com.example.service.DownloadService" />

    </application>

    <uses-permission android:name="android.permission.INTERNET"
        tools:ignore="ManifestOrder" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />

</manifest>

MainActivity:

监听到用户点击Menu---->弹出选项框“Update”、“About”按钮---->onOptionsItemSelected()监听到用户点击更新按钮后调用updateListView()下载Mp3文件,采用SAX解析器解析文件生成一个Mp3Info对象,通过buildSimpleAdapter()将mp3文件的名字和大小返回给TextView显示。onListItemClick()监听用户点击哪个mp3文件,开启下载文件服务DownloadService。

package com.example.mp3player;

import androidx.appcompat.app.AppCompatActivity;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import com.example.download.HttpDownloader;
import com.example.model.Mp3Info;
import com.example.service.DownloadService;
import com.example.xml.Mp3ListContentHandler;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

public class MainActivity extends ListActivity {
    private static final int UPDATE = 1;
    private static final int ABOUT = 2;
    private List<Mp3Info> mp3Infos = null;
    //after user click Menu button ,the function is called,so wo can monitor in this function
    @Override
    public boolean onCreateOptionsMenu(Menu menu){
        //Distinguish Button of Update and About
        menu.add(0,UPDATE,1,"update list");
        menu.add(0,ABOUT,2,"about");
        return super.onCreateOptionsMenu(menu);
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item){
        //user click Update button
        if(item.getItemId() == UPDATE){
            updateListView();
        }else if(item.getItemId() == ABOUT){
            //user click button about
        }
        System.out.println("itemId----->"+item.getItemId());
        return super.onOptionsItemSelected(item);
    }
    //The smaller the function,the better!  because Strongly Reusability
    //function of downloading xml
    private String downloadXml(String urlStr){
        HttpDownloader httpDownloader = new HttpDownloader();
        String result = httpDownloader.download(urlStr);
        return result;
    }
    //Convert an xml file into an array of object
    private List<Mp3Info> parse(String xmlStr){
        /*
            use SAX parser to parse xml document
            SAXParserFactory.newInstance():get an SAXParserFactory new instance。
         */
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        //define an arraylist of mp3Info
        List<Mp3Info> infos = new ArrayList<Mp3Info>();
        try{
            /*
                saxParserFactory是一个SAX解析器,用于解析xml文档
                newSAXParser将解析器工厂实例化
                getXMLReader()生成一个解析器实例
             */
            XMLReader xmlReader = saxParserFactory.newSAXParser().getXMLReader();
            //定义一个将xml转换成Mp3Info对象数组的生成器
            Mp3ListContentHandler mp3ListContentHandler = new Mp3ListContentHandler(infos);
            //解析器实例捆绑生成器
            xmlReader.setContentHandler(mp3ListContentHandler);
            //将xml文件转换成一个Java可以处理的InputStream流
            xmlReader.parse(new InputSource(new StringReader(xmlStr)));
            //Iterator跌倒infos的数据
            for(Iterator iterator = infos.iterator();iterator.hasNext();){
                Mp3Info mp3Info = (Mp3Info) iterator.next();
                System.out.println(mp3Info);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return infos;
    }

    private SimpleAdapter buildSimpleAdapter(List<Mp3Info> mp3Infos){
        List<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
        //iterate mp3Infos and assign to TextView to show to user
        for(Iterator iterator= mp3Infos.iterator();iterator.hasNext();){
            Mp3Info mp3Info = (Mp3Info) iterator.next();
            HashMap<String ,String> map = new HashMap<String,String>();
            map.put("mp3_name",mp3Info.getMp3Name());
            map.put("mp3_size",mp3Info.getMp3Size());
            list.add(map);
        }

        //create an simpleAdapter object
        SimpleAdapter simpleAdapter = new SimpleAdapter(this,list,R.layout.mp3info_item,new String[]{"mp3_name","mp3_size"},new int[]{R.id.mp3_name,R.id.mp3_size});
        return simpleAdapter;
    }

    private void updateListView(){
        //download mp3 information xml file
        String xml = downloadXml("http://192.168.1.34:8081/MP3/resources.xml");
        //analysis xml file ane put the consequence in the Object mp3Info,last add Object in the List
        List<Mp3Info> mp3Infos = parse(xml);
        //generate Object of List ,put mp3Info Object in the List according to standard "SimpleAdapter"
        SimpleAdapter simpleAdapter = buildSimpleAdapter(mp3Infos);
        //set simpleAdapter into ListActivity
        setListAdapter(simpleAdapter);
    }

    //after you click the activity file button ,the function is called ,you can know which textview is clicked and then you can download it.
    protected void onListItemClick(ListView l, View v, int position, long id){
        //position specifies which mp3Info object is called
        Mp3Info mp3Info = mp3Infos.get(position);

        //use service to download file in network
        Intent intent = new Intent();
        intent.putExtra("mp3Info",mp3Info);
        intent.setClass(MainActivity.this, DownloadService.class);
        startService(intent);

        super.onListItemClick(l,v,position,id);
    }

}

DownloadService

创建一个Mp3Info实体对象,接受从MainActivity中传来的数据,DownloadThread 方法开启新线程调用HttpDownloader 下载文件。并根据HttpDownloader.download()返回结果采用Notification方式提示用户文件下载情况

package com.example.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import androidx.annotation.Nullable;

import com.example.download.HttpDownloader;
import com.example.model.Mp3Info;


public class DownloadService extends Service {

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //acquire which file or mp3Info Object is clicked ,then we can call DownloadThread function.
        Mp3Info mp3Info = (Mp3Info) intent.getSerializableExtra("mp3Info");
        DownloadThread downloadThread = new DownloadThread(mp3Info);
        Thread thread = new Thread(downloadThread);
        thread.start();
        return super.onStartCommand(intent, flags, startId);
    }

    //download specified(mp3Info appointed) files in a thread over the network
    //create a new thread.
    class DownloadThread implements Runnable{
        private Mp3Info mp3Info = null;
        public DownloadThread(Mp3Info mp3Info) {
            this.mp3Info = mp3Info;
        }
        public void run(){
            String mp3Url = "http://192.168.1.34:8081/MP3"+mp3Info.getMp3Name();
            HttpDownloader httpDownloader = new HttpDownloader();
            String result = httpDownloader.download(mp3Url);
            int resultInt = Integer.parseInt(result);
            //notify user the consequence of downloading file
            String resultMessage = null;
            if(resultInt == -1){
                resultMessage = "download file failed";
            }else if(resultInt == 0){
                resultMessage = "file existed,can't download repeatly";
            }else if(resultInt == 1){
                resultMessage = "file download successsfully";
            }
        }
    }
}

Mp3Info

package com.example.model;

import java.io.Serializable;

public class Mp3Info implements Serializable {
    private String id;
    private String mp3Name;
    private String mp3Size;
    private String lrcName;
    private String lrcSize;

    public Mp3Info() {
        super();
    }

    @Override
    public String toString() {
        return "Mp3Info{" +
                "id='" + id + '\'' +
                ", mp3Name='" + mp3Name + '\'' +
                ", mp3Size='" + mp3Size + '\'' +
                ", lrcName='" + lrcName + '\'' +
                ", lrcSize='" + lrcSize + '\'' +
                '}';
    }

    public Mp3Info(String id, String mp3Name, String mp3Size, String lrcName, String lrcSize) {
        super();
        this.id = id;
        this.mp3Name = mp3Name;
        this.mp3Size = mp3Size;
        this.lrcName = lrcName;
        this.lrcSize = lrcSize;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setMp3Name(String mp3Name) {
        this.mp3Name = mp3Name;
    }

    public void setMp3Size(String mp3Size) {
        this.mp3Size = mp3Size;
    }

    public void setLrcName(String lrcName) {
        this.lrcName = lrcName;
    }

    public void setLrcSize(String lrcSize) {
        this.lrcSize = lrcSize;
    }


    public String getId() {
        return id;
    }

    public String getMp3Name() {
        return mp3Name;
    }

    public String getMp3Size() {
        return mp3Size;
    }

    public String getLrcName() {
        return lrcName;
    }

    public String getLrcSize() {
        return lrcSize;
    }
}

HttpDownloader

package com.example.download;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class HttpDownloader {
    public String download(String urlStr){
        StringBuffer sb = new StringBuffer();
        String line = null;
        BufferedReader buffer = null;
        try{
            //创建一个url对象
            URL url = new URL(urlStr);
            //创建一个http连接
            HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
            //使用io流读取数据
            buffer = new BufferedReader(new InputStreamReader((urlConn.getInputStream())));
            while((line = buffer.readLine()) != null){
                sb.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try{
                buffer.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}

Mp3ListActivity

采用tabHost布局显示远程文件和本地文件,点击“remote”按钮,选择文件下载,即可在“local”按钮下的页面中查看到下载的文件。页面布局采用layout.mp3_list_activity。

package com.example.mp3player;

import android.app.TabActivity;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TabHost;

public class Mp3ListActivity extends TabActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mp3_list_activity);
        //obtain a TabHost object
        TabHost tabHost = getTabHost();
        //generate a Intent object and point to MainActivity
        Intent remoteIntent = new Intent();
        remoteIntent.setClass(this,MainActivity.class);
        //generate TabSpec object ,it assign a page includes Remote button and file list
        TabHost.TabSpec remoteSpec = tabHost.newTabSpec("Reomte");
        //define the remote button text and image form android library
        Resources res = getResources();
        remoteSpec.setIndicator("Remote",res.getDrawable(android.R.drawable.stat_sys_download));
        //set remoteSpec object text and picture
        remoteSpec.setContent(remoteIntent);
        //add remoteSpec in tabHost
        tabHost.addTab(remoteSpec);

        Intent localIntent = new Intent();
        localIntent.setClass(this,LocalMp3ListActivity.class);
        TabHost.TabSpec localSpec = tabHost.newTabSpec("Local");
        localSpec.setIndicator("Local",res.getDrawable(android.R.drawable.stat_sys_download));
        localSpec.setContent(localIntent);
        tabHost.addTab(localSpec);
    }
}

LocalMp3ListActivity

读取到下载的文件的名字和尺寸,显示在页面上,监听点击事件。如果监听到用户点击某文件,调用PlayerActivity播放音乐。

package com.example.mp3player;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import com.example.model.Mp3Info;
import com.example.utils.FileUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

public class LocalMp3ListActivity extends ListActivity {
    private List<Mp3Info> mp3Infos = null;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.local_mp3_list_activity);
    }
    @Override
    protected void onResume() {
        FileUtils fileUtils = new FileUtils();
        List<Mp3Info> mp3Infos = fileUtils.getMp3File("mp3/");
        List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
        for (Iterator iterator = mp3Infos.iterator(); iterator.hasNext(); ) {
            Mp3Info mp3Info = (Mp3Info) iterator.next();
            HashMap<String, String> map = new HashMap<String, String>();
            map.put("mp3_name", mp3Info.getMp3Name());
            map.put("mp3_size", mp3Info.getMp3Size());
            list.add(map);
        }

        SimpleAdapter simpleAdapter = new SimpleAdapter(this, list, R.layout.mp3info_item, new String[]{"mp3_name", "mp3_size"}, new int[]{R.id.mp3_name, R.id.mp3_size});
        setListAdapter(simpleAdapter);
        super.onResume();
    }

    protected void onListItemClick(ListView l, View v, int position, long id){
        if(mp3Infos != null){
            Mp3Info mp3Info = mp3Infos.get(position);
            Intent intent = new Intent();
            intent.putExtra("mp3Info",mp3Info);
            intent.setClass(this,PlayerActivity.class);
            startActivity(intent);
        }
    }
}

FileUtils

package com.example.utils;

import android.os.Environment;

import com.example.model.Mp3Info;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

public class FileUtils {
    private String SDCardRoot;

    //get Directory of external device
    public FileUtils(){
        SDCardRoot = Environment.getExternalStorageDirectory().getAbsolutePath();
    }

    //create document in SDCard
    //function file.seperator is equal to '/'
    public File createFileInSDCard(String fileName, String dir) throws IOException {
        File file = new File(SDCardRoot+dir+File.separator+fileName);
        file.createNewFile();
        return file;
    }

    //create folder in SDCard
    public File createSDDir(String dir){
        File dirFile = new File(SDCardRoot+dir+File.separator);
        dirFile.mkdir();
        return dirFile;
    }
    //check whether the file exists on the sd card
    public boolean isFileExist(String fileName,String dir){
        File file = new File(SDCardRoot+dir+File.separator+fileName);
        return file.exists();
    }
    //write datas from InputStream in sd card
    public File write2SDFromInput(String path, String fileName, InputStream input){
        File file = null;
        OutputStream output = null;
        try{
            createSDDir(path);
            file = createFileInSDCard(fileName,path);
            output = new FileOutputStream(file);
            byte buffer[] = new byte[4*1024];
            int temp;
            while((temp = input.read(buffer)) != -1){
                output.write(buffer,0,temp);
            }
            output.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                output.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return file;
    }
    //read files name and size
    public List<Mp3Info> getMp3File(String path){
        List<Mp3Info> mp3InfoList = new ArrayList<Mp3Info>();
        File file = new File(SDCardRoot+File.separator+path);
        //traverse directory
        File[] files = file.listFiles();
        for(int i=0;i<files.length;i++){
            if(files[i].getName().endsWith("mp3")){
                Mp3Info mp3Info = new Mp3Info();
                mp3Info.setMp3Name(files[i].getName());
                mp3Info.setMp3Size(files[i].length()+"");
                mp3InfoList.add(mp3Info);
            }
        }
        return mp3InfoList;
    }
}

PlayerActivity

创建播放、暂停、停止三个按钮;如果监听到调用PlayService 服务,并开启线程更新歌词文件。

package com.example.mp3player;

import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;

import com.example.lrc.LrcProcess;
import com.example.model.AppConstant;
import com.example.model.Mp3Info;
import com.example.service.PlayService;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Queue;

public class PlayerActivity extends Activity {
    private ImageButton beginButton = null;
    private ImageButton pauseButton = null;
    private ImageButton stopButton = null;
    private MediaPlayer mediaPlayer = null;
    private boolean isPlaying = false;
    private boolean isPause = false;
    private  boolean isReleased = false;
    private Mp3Info mp3Info = null;

    private Handler handler = new Handler();
    private UpdateTimeCallback updateTimeCallback = null;
    private long begin = 0;
    private long nextTimeMill = 0;
    private long currentTimeMill = 0;
    private String message = null;
    private long pauseTimeMills = 0;
    private ArrayList<Queue> queues = null;
    private TextView lrcTextView = null;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.player);
        Intent intent = new Intent();
        mp3Info = (Mp3Info) intent.getSerializableExtra("mp3Info");

        beginButton = (ImageButton) findViewById(R.id.begin);
        pauseButton = (ImageButton) findViewById(R.id.pause);
        stopButton = (ImageButton) findViewById(R.id.stop);
        lrcTextView = (TextView) findViewById(R.id.lrcText);

        beginButton.setOnClickListener(new beginButtonListener());
        pauseButton.setOnClickListener(new pauseButtonListener());
        stopButton.setOnClickListener(new stopButtonListener());

    }
    class beginButtonListener implements View.OnClickListener{
        @Override
        public void onClick(View v){
            //用于使用Service播放Mp3音乐
            Intent intent = new Intent();
            intent.setClass(PlayerActivity.this,PlayService.class);
            intent.putExtra("mp3Info",mp3Info);
            intent.putExtra("MSG",AppConstant.PlayMsg.PLAY_MSG);
            //读取lrc文件
            prepareLrc(mp3Info.getLrcName());
            //启动service
            startService(intent);
            //begin当前毫秒数
            begin = System.currentTimeMillis();
            //延后5s执行updateTimeCallback函数
            handler.postDelayed(updateTimeCallback,5);
            isPlaying = true;
        }
    }
    class pauseButtonListener implements View.OnClickListener{
        @Override
        public void onClick(View v){
            Intent intent = new Intent();
            intent.setClass(PlayerActivity.this, PlayService.class);
            intent.putExtra("MSG", AppConstant.PlayMsg.PAUSE_MSG);
            startService(intent);
            if(isPlaying){
                handler.removeCallbacks(updateTimeCallback);
                pauseTimeMills = System.currentTimeMillis();
            }else {
                handler.postDelayed(updateTimeCallback,5);
                begin = System.currentTimeMillis() - pauseTimeMills+begin;
            }
            isPlaying = isPlaying ? false : true;
        }
    }
    class stopButtonListener implements View.OnClickListener{
        @Override
        public void onClick(View v){
            //通知Service停止播放Mp3文件
            Intent intent = new Intent();
            intent.setClass(PlayerActivity.this,PlayService.class);
            intent.putExtra("MSG",AppConstant.PlayMsg.STOP_MSG);
            startService(intent);
            //从handler中移除updateTimeCallback--->更新lyric函数。
            handler.removeCallbacks(updateTimeCallback);
        }
    }

    //更新歌词文件
    class UpdateTimeCallback implements Runnable{
        ArrayList<Queue> queues = null;
        Queue times = null;
        Queue messages = null;
        public UpdateTimeCallback(ArrayList<Queue> queues){
            this.queues = queues;
            times = queues.get(0);
            messages = queues.get(1);
        }

        @Override
        public void run() {
            //计算开始播放到现在的时长,以毫秒为单位。
            long offset = System.currentTimeMillis()-begin;
            System.out.println(offset);
            //currentTimeMill == 0---->第一次调用UpdateTimeCallback函数
            if(currentTimeMill == 0){
                nextTimeMill = (Long)times.poll();
                message = (String) messages.poll();
            }
            //现在时间已经大于下一次要播放音乐的时间了,把下一次要重新的时间点和歌词信息保存起来
            if(offset >= nextTimeMill){
                lrcTextView.setText(message);
                message = (String)messages.poll();
                nextTimeMill = (Long)times.poll();
            }
            currentTimeMill = currentTimeMill + 10;
            //每隔10ms检查当前时间是否超过要重现加载歌词的时间
            handler.postDelayed(updateTimeCallback,10);
        }
    }
    //acquire lyric file information by lyric file name.
    private void prepareLrc(String lrcName){
        try{
            InputStream inputStream = new FileInputStream(Environment.getExternalStorageDirectory().getAbsolutePath());
            LrcProcess lrcProcess = new LrcProcess();
            //obtain lyric by inputStream.
            //得到事件队列和歌词队列  
            queues = lrcProcess.process(inputStream);
            updateTimeCallback = new UpdateTimeCallback(queues);
            begin = 0;
            currentTimeMill = 0;
            nextTimeMill = 0;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

PlayService

package com.example.service;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;

import androidx.annotation.Nullable;

import com.example.model.AppConstant;
import com.example.model.Mp3Info;
import com.example.mp3player.PlayerActivity;

import java.io.File;

public class PlayService extends Service {
    private MediaPlayer mediaPlayer = null;
    private boolean isPlaying = false;
    private boolean isPause = false;
    private  boolean isReleased = false;

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

    public int onStartCommand(Intent intent,int flags,int startId){
        Mp3Info mp3Info = (Mp3Info) intent.getSerializableExtra("mp3Info");
        int MSG = intent.getIntExtra("MSG",0);
        if(mp3Info != null){
            if(MSG == AppConstant.PlayMsg.PLAY_MSG){
                play(mp3Info);
            }
        }else{
            if(MSG == AppConstant.PlayMsg.PAUSE_MSG){
                pause();
            }else if(MSG == AppConstant.PlayMsg.STOP_MSG){
                stop();
            }
        }
        return super.onStartCommand(intent,flags,startId);
    }

    private void play(Mp3Info mp3Info){
        String path = getMp3Path(mp3Info);
        //function uri.parese compulsive require having prefix "file://"
        mediaPlayer = MediaPlayer.create(this, Uri.parse("file://"+path));
        //turn off looply playing music
        mediaPlayer.setLooping(false);
        //begin playing music
        mediaPlayer.start();
        isPlaying = true;
        isPause = false;
    }
    private void pause(){
        //if we don't know whether mediaPlayer equals to null,we will meet problem of null pointer exception after we directly used it.
        if(mediaPlayer != null){
            if(!isReleased){
                if(!isPause){
                    //state is playing music,click the pause button,we will pause the music.
                    mediaPlayer.pause();
                    isPause = true;
                    isPlaying = false;
                }else{
                    //state is pausing,click the pause button,we will play the music.
                    mediaPlayer.start();
                    isPause = false;
                    isPlaying = true;
                }
            }
        }
    }
    private void stop(){
        if(mediaPlayer != null){
            if(isPlaying){
                if(!isReleased){
                    mediaPlayer.stop();
                    //release all resources mediaPlayer used
                    mediaPlayer.release();
                    isReleased = true;
                }
                isPlaying = false;
            }
        }
    }
    //acquire mp3Path
    private String getMp3Path(Mp3Info mp3Info){
        String SDCardRoot  = Environment.getExternalStorageDirectory().getAbsolutePath();
        String path = SDCardRoot+ File.separator+"mp3/"+File.separator+mp3Info.getMp3Name();
        return path;
    }
}

LrcProcess

package com.example.lrc;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LrcProcess {
    public ArrayList<Queue> process(InputStream inputStream){
        //time list
        Queue<Long> timeMills = new LinkedList<Long>();
        //message list
        Queue<String> messages = new LinkedList<>();
        ArrayList<Queue> queues = new ArrayList<Queue>();
        try{
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String temp = null;
            int i = 0;
            Pattern p = Pattern.compile("\\[([^\\]]+)\\]");
            String result = null;
            boolean b = true;
            while((temp = bufferedReader.readLine()) != null){
                i++;
                Matcher m = p.matcher(temp);
                if(m.find()){
                    if(result != null){
                        messages.add(result);
                    }
                    String timeStr = m.group();
                    Long timeMill = time2Long(timeStr.substring(1,timeStr.length()-1));
                    if(b){
                        timeMills.offer(timeMill);
                    }
                    String msg = temp.substring(10);
                    result = ""+msg+"\n";
                }else{
                    result = result+temp+"\n";
                }
                messages.add(result);
                queues.add(timeMills);
                queues.add(messages);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return queues;
    }
    //turn time to millisecond
    public Long time2Long(String timeStr){
        String s[]= timeStr.split(":");
        int min = Integer.parseInt(s[0]);
        String ss[] = s[1].split("\\.");
        int sec = Integer.parseInt(ss[0]);
        int mill = Integer.parseInt(ss[1]);
        return min * 60 * 100 + sec * 1000 + mill * 10L;
    }
}

AppConstant

package com.example.model;

public interface AppConstant {
    public class PlayMsg{
        public static final int PLAY_MSG = 1;
        public static final int PAUSE_MSG = 2;
        public static final int STOP_MSG = 3;
    }
    public class URL{
        public static final String BASE_URL = "http://192.168.1.34:8081/MP3/";
    }
}

Mp3ListContentHandler

package com.example.xml;

import com.example.model.Mp3Info;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import java.util.List;
//读取xml文件并生成一个对象数组
public class Mp3ListContentHandler extends DefaultHandler {
    private List<Mp3Info> infos = null;

    public Mp3ListContentHandler(List<Mp3Info> infos) {
        this.infos = infos;
    }

    private Mp3Info mp3Info = null;
    private String tagName = null;
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
            this.tagName = localName;
            //以resource为节点设置成一个Mp3Info对象
            if(tagName.equals("resource")){
                mp3Info = new Mp3Info();
            }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if(qName.equals("resource")){
            infos.add(mp3Info);
        }
        tagName = "";
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        String temp = new String(ch,start,length);
        if(tagName.equals("id")){
            mp3Info.setId(temp);
        }else if(tagName.equals("mp3.name")){
            mp3Info.setMp3Name(temp);
        }else if(tagName.equals("mp3.size")){
            mp3Info.setMp3Size(temp);
        }else if(tagName.equals("lrc.name")){
            mp3Info.setLrcName(temp);
        }else if(tagName.equals("lrc.size")){
            mp3Info.setLrcSize(temp);
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:id="@+id/listLinearLayout"
        android:orientation="vertical"
        android:width="fill_parent"
        android:height="wrap_content">
        <!--suppress AndroidDomInspection -->
        <ListView android:id="@id/android:list"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:drawSelectorOnTop="false"
            android:scrollbars="vertical"/>
    </LinearLayout>
</LinearLayout>

local_mp3_list_activity.xml

<TabHost
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/tabhost">
    <LinearLayout android:orientation="vertical"
        android:layout_width="fill_parent"
        android:lauout_height="wrap_content"
        android:padding="5dip">
        <TabWidget
            android:id="@+id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"/>
        <FrameLayout
            android:id="@+id/tabContent"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:padding="5dip"/>
    </LinearLayout>
</TabHost>

mp3_list_activity.xml

<TabHost
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/tabhost">
    <LinearLayout android:orientation="vertical"
        android:layout_width="fill_parent"
        android:lauout_height="wrap_content"
        android:padding="5dip">
        <TabWidget
            android:id="@+id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"/>
        <FrameLayout
            android:id="@+id/tabContent"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:padding="5dip"/>
    </LinearLayout>
</TabHost>

mp3info_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal"
    android:paddingLeft="10dip"
    android:paddingRight="10dip"
    android:paddingTop="1dip"
    android:paddingBottom="1dip">

    <TextView
        android:id="@+id/mp3_name"
        android:layout_height="30dip"
        android:layout_width="180dip"
        android:textSize="10pt"/>
    <TextView
        android:id="@+id/mp3_size"
        android:layout_height="30dip"
        android:layout_width="180dip"
        android:textSize="10pt"/>
</LinearLayout>

player.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:padding="10dip">
    <ImageButton
        android:id="@+id/begin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/begin"/>
    <ImageButton
        android:id="@+id/pause"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/pause"/>
    <ImageButton
        android:id="@+id/stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/stop"/>
    <TextView
        android:id="@+id/lrcText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值