zoukankan      html  css  js  c++  java
  • 音乐播放器-任务

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

    /*变量声明*/
    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,如果下载同一首歌曲多次,程序不会多次新建文件,而将数据写入与之同名的文件中。

     
     
  • 相关阅读:
    Android&Handler2
    ACM&数字阶梯求和(大数问题)
    Android&MyThread
    【转】 《基于MFC的OpenGL编程》Part 15 Selection
    【转】 《基于MFC的OpenGL编程》Part 12 Creating and Using Display Lists
    【转】《基于MFC的OpenGL编程》Part 16 Reflection
    【转】 《基于MFC的OpenGL编程》Part 8 Colors
    【转】 《基于MFC的OpenGL编程》Part 14 Quadrics
    开发不同语言版本的C#程序
    基于ADS40的线阵摄影测量及数据处理
  • 原文地址:https://www.cnblogs.com/200911/p/3332506.html
Copyright © 2011-2022 走看看