音乐播放器-任务

一、音乐播放器常见的操作

/*变量声明*/
private ImageButton playBtn = null;//播放、暂停
private ImageButton latestBtn = null;//上一首
private ImageButton nextButton = null;//下一首
private ImageButton forwardBtn = null;//快进
private ImageButton rewindBtn = null;//快退
private TextView playtime = null;//已播放时间
private TextView durationTime = null;//歌曲时间
private SeekBar seekbar = null;//歌曲进度
private Handler handler = null;//用于进度条
private Handler fHandler = null;//用于快进
private int currentPosition;//当前播放位置
 
/*获得列表传过来的数据*/
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.play);
    Intent intent = this.getIntent();
    Bundle bundle = intent.getExtras();
    _ids = bundle.getIntArray("_ids");    //获得保存音乐文件_ID的数组
    position = bundle.getInt("position"); //获得应该播放的音乐的号数,既播放第几首
        //代码未完,见下面的代码
}
 
/*初始化控件*/
playtime = (TextView)findViewById(R.id.playtime);         //显示已经播放的时间
durationTime = (TextView)findViewById(R.id.duration);     //显示歌曲总时间
playBtn = (ImageButton)findViewById(R.id.playBtn);       //开始播放、暂停播放按钮
latestBtn = (ImageButton)findViewById(R.id.latestBtn);   //播放上一首按钮
nextButton = (ImageButton)findViewById(R.id.nextBtn);    //播放下一首按钮
forwardBtn = (ImageButton)findViewById(R.id.forwardBtn); //快进按钮
rewindBtn = (ImageButton)findViewById(R.id.rewindBtn);   //快退按钮
seekbar = (SeekBar)findViewById(R.id.seekbar);           //播放进度条
 
/*定义各控件的回调函数*/
playBtn.setOnClickListener(new View.OnClickListener() { //点击“播放、暂停”按钮时回调
    @Override
    public void onClick(View v) {              
        if (mp.isPlaying()){                     //如果正在播放则暂停
            pause();
            playBtn.setBackgroundResource(
                 R.drawable.play_selecor);   //更改按键状态图标
        } else{                                  //如果没有播放则恢复播放
            play();
            playBtn.setBackgroundResource(
                R.drawable.pause_selecor);   //更改按键状态图标
                     
        }
    }
});
 
latestBtn.setOnClickListener(new View.OnClickListener() {//点击“播放上一首”按钮时回调          
    @Override
    public void onClick(View v) {
        int num = _ids.length;                  //获得音乐的数目
        if(position==0){                        //如果已经时第一首则播放最后一首
            position=num-1;                                    
        }else{                                  //否则播放上一首
            position-=1;
        }
        int pos = _ids[position];              //得到将要播放的音乐的_ID
        setup();                               //做播放前的准备工作
        play();                    //开始播放
    }
});
 
nextButton.setOnClickListener(new View.OnClickListener(){//点击“播放下一首”按钮时回调          
    @Override
    public void onClick(View v) {               
        int num = _ids.length;                 //获得音乐的数目
        if (position==num-1){                  //如果已经是最后一首,则播放第一首
            position=0;
        }else{
            position+=1;                  //否则播放下一首
        }
        int pos = _ids[position];             //得到将要播放的音乐的_ID
        setup();                              //做播放前的准备工作
        play();                               //开始播放
    }
});
 
forwardBtn.setOnTouchListener(new OnTouchListener() {    //点击“快进”按钮时回调
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                fHandler.post(forward); //此处使用handler对象更新进度条
                mp.pause();     //点击快进按钮时,音乐暂停播放                           
                break;
 
            case MotionEvent.ACTION_UP:
                fHandler.removeCallbacks(forward);         
                mp.start();     //松开快进按钮时,音乐暂恢复播放                          
                playBtn.setBackgroundResource(
                    R.drawable.pause_selecor);
                break;
        }
        return false;
    }
});
 
rewindBtn.setOnTouchListener(new OnTouchListener() {    //点击“快退”按钮时回调      
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:  
                fHandler.post(rewind);         
                mp.pause(); //点击快退按钮时,音乐暂暂停播放
                break;
 
            case MotionEvent.ACTION_UP:
                fHandler.removeCallbacks(rewind);
                mp.start(); //松开快退按钮时,音乐暂恢复播放
                playBtn.setBackgroundResource(
                    R.drawable.pause_selecor);
                break;
        }
        return false;
    }
});
 
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {         
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        mp.start();     //停止拖动进度条时,音乐开始播放
    }
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        mp.pause();     //开始拖动进度条时,音乐暂停播放
    }
             
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
        boolean fromUser) {
        if(fromUser){
            mp.seekTo(progress);    //当进度条的值改变时,音乐播放器从新的位置开始播放
        }
    }
});
 

二.android操作sdcard中的多媒体文件(一)——音乐列表的制作

最近做了一个android音乐播放器,个人感觉最难的就是“后台播放”以及有关“播放列表”的部分,但是总算是找到了实现的方式。不同的人实现 的方式可能不一样,这里我就分享一下自己对“播放列表”这个模块的一些实现方法,“后台播放”会在下一篇博文中进行介绍,希望大家也能分享一下自己的一些 思路。

     android使用ContentProvider来支持不同应用程序的数据共享,为了方便其他应用程序对sdcard中的数据进行操作,sdcard也 提供了ContentProvider接口,这里就以访问音频文件为例,视频以及图片的操作也类似,这里就不在赘述。

  访问sdcard中的音频文件的URI为MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,为了使播 放列表显示所以音乐文件的信息,这里需要查询sdcard里的音频文件,并把查询到的信息保存在Cursor中,具体代码如下:

<pre>Cursor c = this.getContentResolver().</pre>
<pre>query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,</pre>
/*这个字符串数组表示要查询的列*/
new String[]{MediaStore.Video.Media.TITLE//音乐名
MediaStore.Audio.Media.DURATION,            //音乐的总时间
MediaStore.Audio.Media.ARTIST,          //艺术家
MediaStore.Audio.Media._ID,             //id号
MediaStore.Audio.Media.DISPLAY_NAME,        //音乐文件名
MediaStore.Audio.Media.DATA         //音乐文件的路径
},
null,                      //查询条件,相当于sql中的where语句
null,                       //查询条件中使用到的数据
null);                     //查询结果的排序方式
   通过MediaStore.Audio.Media.XXX来访问音乐文件的一些信息,这里只列出了一部分,可以根据需要进行增添和删除。
    至此,Cursor c就已经保存了sdcard内所以音频文件的信息,下面的操作就是围绕这个Cursor展开的。
    首先定义三个数组:
    private int[] _ids;    //存放音乐文件的id数组
    private String[] _titles; //存放音乐文件的标题数组
    private String[] _path;   //存放音乐文件的路径
    
  _ids保存了所有音乐文件的_ID,用来确定到底要播放哪一首歌曲,_titles存放音乐名,用来显示在播放界面,而_path存放音乐文件的路径(删除文件时会用到)。
 
    
  接下来再定义一个变量,用来定位选择的是哪一首音乐:
  private int pos;
 接下来将音乐文件的信息存放在相应的数组中:  
 
    
c.moveToFirst();
_ids = new int[c.getCount()];
_titles = new String[c.getCount()];
_path = new String[c.getCount()];
for(int i=0;i<c.getCount();i++){
    _ids[i] = c.getInt(3);          
    _titles[i] = c.getString(0);
    _path[i] = c.getString(5).substring(4);
    c.moveToNext();
}        
 
    
有人可能会问为什么获取路径的格式是_path[i]=c.geString(5).substring(4)?因为MediaStore.Audio.Media.DATA
得到的内容格式为/mnt/sdcard/[子文件夹名/]音乐文件名,而我们想要得到的是/sdcard/[子文件夹名]音乐文件名,
所以要做相应的裁剪操作。

 接下来把Cursor中的信息显示到listview中:
 
    
MusicListAdapter adapter = new MusicListAdapter(this, c);
listview.setAdapter(adapter);
MusicListAdapter是一个自定义的Adapter,继承自BaseAdapter,这里只贴出代码,不做讲解。
 
    
 
package com.alex.video;
 
import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
 
public class MusicListAdapter extends BaseAdapter{
    private Context myCon;
    private Cursor myCur;
    private int pos=-1;
     
    public MusicListAdapter(Context con,Cursor cur){
        this.myCon = con;
        this.myCur = cur;
    }
     
    @Override
    public int getCount() {
         
        return this.myCur.getCount();
    }
 
    @Override
    public Object getItem(int position) {
         
        return position;
    }
 
    @Override
    public long getItemId(int position) {
         
        return position;
    }
 
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        convertView = LayoutInflater.from(myCon).inflate(R.layout.musiclist,
                null);
        myCur.moveToPosition(position);
        TextView videoTitle = (TextView)convertView.findViewById(R.id.musictitle);
        if (myCur.getString(0).length()>24){
            try {
                String musicTitle = bSubstring(myCur.getString(0).trim(),24);
                videoTitle.setText(musicTitle);
            } catch (Exception e) {
                 
                e.printStackTrace();
            }
        }else {
            videoTitle.setText(myCur.getString(0).trim());
        }
        TextView videoArtist = (TextView)convertView.findViewById(R.id.musicartist);
        if (myCur.getString(2).equals("<unknown>")){
            videoArtist.setText("未知艺术家");
        }else{
            videoArtist.setText(myCur.getString(2));
        }
        TextView videoTime = (TextView)convertView.findViewById(R.id.musictime);
        videoTime.setText(toTime(myCur.getInt(1)));
        ImageView videoItem = (ImageView)convertView.findViewById(R.id.musicitem);
        videoItem.setImageResource(R.drawable.item);
        return convertView;
    }
     
    /*时间格式转换*/
    public String toTime(int time) {
 
        time /= 1000;
        int minute = time / 60;
        int hour = minute / 60;
        int second = time % 60;
        minute %= 60;
        return String.format("%02d:%02d", minute, second);
    }
 
    /*字符串裁剪*/
    public static String bSubstring(String s, int length) throws Exception 
    
      
        byte[] bytes = s.getBytes("Unicode"); 
        int n = 0; // 表示当前的字节数 
        int i = 2; // 要截取的字节数,从第3个字节开始 
        for (; i < bytes.length && n < length; i++) 
        
            // 奇数位置,如3、5、7等,为UCS2编码中两个字节的第二个字节 
            if (i % 2 == 1) 
            
                n++; // 在UCS2第二个字节时n加1 
            
            else
            
                // 当UCS2编码的第一个字节不等于0时,该UCS2字符为汉字,一个汉字算两个字节 
                if (bytes[i] != 0) 
                
                    n++; 
                
            
        
        // 如果i为奇数时,处理成偶数 
        if (i % 2 == 1) 
      
        
            // 该UCS2字符是汉字时,去掉这个截一半的汉字 
            if (bytes[i - 1] != 0) 
                i = i - 1; 
            // 该UCS2字符是字母或数字,则保留该字符 
            else
                i = i + 1; 
        
      
        return new String(bytes, 0, i, "Unicode"); 
    
}

三、android操作sdcard中的多媒体文件(二)——音乐列表的更新

 在上一篇随笔中,我介绍了如何在程序中查询sdcard内的多媒体文件,并且显示到播放列表中,但是,如果在sdcard内删除、增加一些多媒体文件,如何让播放列表也更新呢,这里我分享一下自己在项目中的一些解决方法,希望对大家有所帮助。

 首先,我简单介绍一下android是如何扫描sdcard内的多媒体信息的,详细请阅读stay的博文:http://www.cnblogs.com/stay/articles/1957571.html
  当android的系统启动的时候,系统会自动扫描sdcard内的多媒 体文件,并把获得的信息保存在一个系统数据库中,以后在其他程序中如果想要访问多媒体文件的信息,其实就是在这个数据库中进行的,而不是直接去 sdcard中取,理解了这一点以后,问题也随着而来:如果我在开机状态下在sdcard内增加、删除一些多媒体文件,系统会不会自动扫描一次呢?答案是 否定的,也就是说,当你改变sdcard内的多媒体文件时,保存多媒体信息的系统数据库文件是不会动态更新的。
 
    
  那么如何让多媒体数据库中的数据更新呢?我们可以采用广播机制来实现:在应用程序中发送一个广播,让android系统扫描sdcard并更新多媒体数据库        
private void scanSdCard(){
        IntentFilter intentfilter = new IntentFilter( Intent.ACTION_MEDIA_SCANNER_STARTED);
        intentfilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
        intentfilter.addDataScheme("file");
        scanSdReceiver = new ScanSdReceiver();
        registerReceiver(scanSdReceiver, intentfilter);
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
                Uri.parse("file://" + Environment.getExternalStorageDirectory().getAbsolutePath()))); }
其中ScanSdReceiver是一个自定义的广播接收器,继承自 BroadCastReceiver,因为android系统开始扫描sdcard以及扫描完毕时都会发送一个系统广播来表示当前扫描的状态,这样我们就 可以很方便通过判断当前的扫描状态加一些自己的逻辑操作,
ScanSdReceiver的代码如下:
 其中ScanSdReceiver是一个自定义的广播接收器,继承自 BroadCastReceiver,因为android系统开始扫描sdcard以及扫描完毕时都会发送一个系统广播来表示当前扫描的状态,这样我们就 可以很方便通过判断当前的扫描状态加一些自己的逻辑操作,ScanSdReceiver的代码如下:
 
public class ScanSdReceiver extends BroadcastReceiver {
 
    private AlertDialog.Builder  builder = null;
    private AlertDialog ad = null;
    private int count1;
    private int count2;
    private int count;
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)){
            Cursor c1 = context.getContentResolver()
            .query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    new String[]{MediaStore.Audio.Media.TITLE,
                    MediaStore.Audio.Media.DURATION,
                    MediaStore.Audio.Media.ARTIST,
                    MediaStore.Audio.Media._ID,
                    MediaStore.Audio.Media.DISPLAY_NAME },
                    null, null, null);
            count1 = c1.getCount();
            System.out.println("count:"+count);
            builder = new AlertDialog.Builder(context);
            builder.setMessage("正在扫描存储卡...");
            ad = builder.create();
            ad.show();
             
        }else if(Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)){
            Cursor c2 = context.getContentResolver()
            .query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    new String[]{MediaStore.Audio.Media.TITLE,
                    MediaStore.Audio.Media.DURATION,
                    MediaStore.Audio.Media.ARTIST,
                    MediaStore.Audio.Media._ID,
                    MediaStore.Audio.Media.DISPLAY_NAME },
                    null, null, null);
            count2 = c2.getCount();
            count = count2-count1;
            ad.cancel();
            if (count>=0){
                Toast.makeText(context, "共增加" +
                        count + "首歌曲", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(context, "共减少" +
                        count + "首歌曲", Toast.LENGTH_LONG).show();
            }  
        }  
    }
}
 
 
 
    
  音乐播放器-任务
 
    
  音乐播放器-任务
 这里我们定义了两个Cursor对象,分别用来存储扫描前后的多媒体信息,并给出相应的提示。  
  以前有很多朋友问过我,为什么扫描以后播放列表中的数据条数没有发生相应 的改变。要实现播放列表在扫描后更新,必须重新读取多媒体信息到Cursor中,并且重新设置adapter,最后还要调用 XXXAdapter.notifyDataSetChanged()来通知UI更新。(可以参考第一张的内容)
  上面的操作都是手动在SDCARD中添加或着删除多媒体文件,下面介绍如何在列表中删除SDCARD中的多媒体文件。
  在上一篇随笔中,我们使用了系统提供的ContentProvider来查询sdcard中的多媒体文件,我们同样可以使用这个ContentProvider来进行删除操作: 
 
private void deleteMusic(int position){
    this.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
            MediaStore.Audio.Media._ID + "=" + _ids[position],
            null);
}

  其中“多媒体文件的ID”可以从_ids数组中取得(关于_ids数组请 参考第一张的内容)。这样,我们是否就已经从SDCARD中删除了指定_ID的多媒体文件了呢?  其实当你打开FileExplorer时会发现,原来的文件并没有被删除,— —!杯具,搞了半天文件还在,我第一次遇到这个问题的时候也是纠结了老半天。。。
为什么没有被删除,原因是上面的删除操作只是删除了系统多媒体数据库中的相应 记录,而并没有删除SDCAED中的文件(注意:多媒体信息数据库和SDCARD中的多媒体文件并不会自动保持同步),这个时候如果再次扫描 SDCARD,你会发现刚才从播放列表中删除的行会再次出现。
 
    
   其实要想真正的从SDCARD中删除多媒体文件并不难,可能有朋友会想 到这样的方法:遍历SDCARD中的多媒体文件,然后把想要删除的文件和其他文件逐一比较,找到文件路径,最后进行删除。这种方法是可以实现删除操作的, 不过效率很低,如果SDCARD中的文件夹以及文件很多,也不知道要用掉多少时间。。
 
    
  在上一张中我们从多媒体数据库中读出来一项很重要的信息:MediaStore.Audio.Media.DATA
 
    
并且取得里面的字串并存放在了_path数组中,最终的数据格式为:/SDCARD/[子文件夹名]文件名 ,又了这个路径,我们就可以很方便的从SDCARD中删除多媒体文件了
 
    
 
private void deleteMusicFile(int position){
    File file = new File(_path[position]);
    file.delete();
}
 
    
   同样,删除文件后要想播放列表同步更新,也必须执行刚才介绍的一系列操作。
最近在自己的音乐播放器中添加了一个下载网络歌曲的功能,虽然还没有做到边下边播放的功能,不过总算是开了一个头了,下载功搞定了,离目标也就不远了。

  android自带播放器支持“边下载边播放”的功能,当你使用系统浏览器点击一个“MP3的下载链接”时,它就会自动播放这首歌曲并保存到本地(不知道用第三方浏览器是否也如此,笔者认为应该是系统浏览器会自动识别MP3下载链接,并调用系统播放器来播放)。

  与这个过程类似,在笔者做的音乐播放器中,当用户选择“歌曲下载”时,会转到一个webview中,这里我将webview的初始url定向 到"htpp://www.top100.cn"(巨鲸音乐),当点击MP3的下载链接时,就会将音乐下载到sdcard的根目录。webview所在 activity的代码如下:

 
setContentView(R.layout.web);
web = (WebView)findViewById(R.id.web);
web.setWebViewClient(new DownLoadWebViewClient(this));
WebSettings s = web.getSettings();
s.setSaveFormData(false);
s.setSavePassword(false);
s.setUseWideViewPort(true);
s.setJavaScriptEnabled(true);
s.setLightTouchEnabled(true);
web.setWebChromeClient(new WebChromeClient() {
    public void onProgressChanged(WebView view, int progress) {
           //Activity和Webview根据加载程度决定进度条的进度大小
           //当加载到100%的时候 进度条自动消失
            context.setProgress(progress * 100);
    }
});
web.loadUrl("http://www.top100.cn/");
 
 

  web.setWebViewClient(new DownLoadWebViewClient(this));其中DownLoadWebViewClient就使我们下载MP3文件的关键,它继承自 WebViewClient,这里我们Override它的public boolean shouldOverrideUrlLoading(WebView view, String url)方法,在方法中我们判断点击的链接时否为“下载MP3文件”,如果成立,则启动一个service来下载mp3文件,代码如下:

 
public class DownLoadWebViewClient extends WebViewClient {
    private Context context;
    public DownLoadWebViewClient(Context context){
        this.context = context;
    }
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        Log.i("info", "open an url");
        String urlStr = "";                                 //存放解码后的url
        //如果是utf8编码
        if (isUtf8Url(url)){
            urlStr = Utf8URLdecode(url);
        //如果不是utf8编码
        } else {
            urlStr = URLDecoder.decode(url);
        }
        //如果链接是下载top100.cn中的mp3文件
        if (url.substring(url.length()-4).equals(".mp3")&&url.substring(7,10).equals("221")){
            Log.i("info", "mp3 file");
            String ss[] = urlStr.split("/");
            String musicName = ss[ss.length-1];             //得到音乐文件的全名(包括后缀)
            Log.i("info", "musicfile: " + musicName);
             
            //将下载链接和文件名传递给下载模块
            Intent intent = new Intent(context,DownLoadService.class);
            intent.putExtra("url", url);
            intent.putExtra("musicName", musicName);
            context.startService(intent);
        }
        return super.shouldOverrideUrlLoading(view, url);
    }

  这里略去了url解码的相关方法。其中DownLoadService用于下载MP3文件并在,它接收DownLoadWebViewClient传递来的url和音乐文件名,代码如下:

 
public class DownLoadService extends Service implements Runnable{   //实现Runable接口
     
    private String URL_str;                     //网络歌曲的路径
    private File download_file;                 //下载的文件
    private int total_read = 0;                 //已经下载文件的长度(以字节为单位)
    private int readLength = 0;                 //一次性下载的长度(以字节为单位)
    private int music_length = 0;                   //音乐文件的长度(以字节为单位)
    private boolean flag = false;                   //是否停止下载,停止下载为true
    private Thread downThread;                  //下载线程
    private String musicName;                   //下载的文件名
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
 
    @Override
    public void onCreate() {
        downThread = new Thread(this);          //初始化下载线程
        downThread.start();
    }
 
    @Override
    public void onStart(Intent intent, int startId) {
         URL_str = intent.getExtras().getString("url");     //获取下载链接的url
         musicName = intent.getExtras().getString("musicName");//获取下载的文件名
    }
     
    @Override
    public void onDestroy() {
        flag = true;                                //停止下载
    }
     
    //实现Run方法,进行歌曲的下载
    @Override
    public void run() {                                                        
        FileOutputStream fos = null;                //文件输出流
        FileInputStream fis = null;             //文件输出流
        InputStream is = null;                  //网络文件输入流
        URL url = null;
        try {
            url = new URL(URL_str);             //网络歌曲的url
            HttpURLConnection httpConnection = null;
            httpConnection = (HttpURLConnection)
            url.openConnection();               //打开网络连接
            download_file = new File(Environment.   //在sdcard根目录建立一个与要下载的文件的名字相同的文件
                    getExternalStorageDirectory()
                    + "/" + musicName);
            fos = new FileOutputStream(download_file, true);        //初始化文件输出流
            fis = new FileInputStream(download_file);               //初始化文件输入流
            total_read = fis.available();                       //初始化“已下载部分”的长度,此处应为0
            music_length = httpConnection.getContentLength();       //要下载的文件的总长度
             
            if (is == null) {                               //如果下载失败则打印日志,并返回
                Log.i("info", "donload failed...");
                return;
            }
             
            byte buf[] = new byte[1024];                      //定义下载缓冲区
            readLength = 0;                           //一次性下载的长度
            Log.i("info", "download start...");                    
             
            //向前台发送开始下载广播
            Intent startIntent = new Intent();
            startIntent.setAction("com.alex.downloadstart");
            sendBroadcast(startIntent);
             
            //如果读取网络文件的数据流成功,且用户没有选择停止下载,则开始下载文件
            while (readLength != -1  && !flag) {                   
                if((readLength = is.read(buf))>0){
                    fos.write(buf, 0, readLength);
                    total_read += readLength;           //已下载文件的长度增加
                }  
                if (total_read == music_length) {           //当已下载的长度等于网络文件的长度,则下载完成
                    flag = false;
                    Log.i("info", "download complete...");
                     
                    //向前台发送下载完成广播
                    Intent completeIntent = new Intent();
                    completeIntent.setAction("com.alex.downloadcompleted");
                    sendBroadcast(completeIntent);
                     
                    //关闭输入输出流
                    fos.close();
                    is.close();
                    fis.close();
                }
                Thread.sleep(50);                           //当前现在休眠50毫秒
                Log.i("info", "download process : "                 //打印下载进度
                        + ((total_read+0.0)/music_length*100+"").substring(0, 4)+"%");
            }
        } catch (Exception e) {
            Intent errorIntent = new Intent();
            errorIntent.setAction("com.alex.downloaderror");
            sendBroadcast(errorIntent);
            e.printStackTrace();
        }
    }
 
     
 
}

  这里有个小bug,如果下载同一首歌曲多次,程序不会多次新建文件,而将数据写入与之同名的文件中。

 
 

你可能感兴趣的:(播放器)