Medie nusic

本文介绍了一个基于Android平台的音乐服务应用开发案例,包括音乐服务组件的设计与实现、音乐播放控制及进度更新等功能。

zhu main : 


package com.lyz.news.day33nusic;


import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;

public class MainActivity extends Activity {

    /**
     * 安卓api  Handler就要求消息队列应该写成 static了这样我们才能在service服务里才能发信息,
     * bundle.putInt("duration",duration);
     * bundle.putInt("currentPosition",currentPosition);
     */
    static Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
//                我们把消息取出来
            Bundle bundle = msg.getData();
//            //当前进度
            int duration = bundle.getInt("duration");
            //当前进度
            //   通过key我们拿到value currentPosition 最大进度
            int currentPostition = bundle.getInt("currentPosition");
//            我们需要在这里使用SeekBar sb, 所以需要把sb设置为静态,否则访问不到;
            //刷新进度条;
            sb.setMax(duration);//主要这两个API setMax音乐的最大长度,setProgress 当前音乐
            sb.setProgress(currentPostition);


        }
    };

    MusicInterface mi;
    private MyserviceConn conn;
    private Intent intent;
    private static SeekBar sb;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //设置一下SeekBar,因为我们要SeekBar设置当前进度,
        sb = (SeekBar) findViewById(R.id.sb);
        /**
         * 和触摸一样也是:触摸是一个方法有三种状态 触摸按下 ,抬起, 移动
         * 这个是分为3个方法:触摸按下 ,抬起, 移动
         *用着3个那个ne ?
         * 我们只要在用户改变进度 ,抬起手结束哪一刹那,改变就可以了
         */

        sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override//进度移动
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                Log.i("MainActivity", "触摸移动!!!");

            }

            //开始追踪'
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                Log.i("MainActivity", "触摸按了!!!");
            }

            //停止追踪'触摸 ,谁触发这个方法就传谁进来
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                Log.i("MainActivity", "触摸松开!!!!!!");

                int progress = seekBar.getProgress();
                //改变播放进度
                mi.seekTo(progress);
            }
        });
        intent = new Intent(MainActivity.this, MusicService.class);
        startService(intent);//start 设置服务

/**
 * 这里如果你要是就用一次,没有解绑就可以使用匿名内部类,new Myserivce ()
 * 还可以给他调出来搞
 */
//       bindService(intent,new MyserviceConn(),BIND_AUTO_CREATE);

        conn = new MyserviceConn();

        bindService(intent, conn, BIND_ABOVE_CLIENT);//然后绑定

    }

    public void play(View v) {
        mi.play();
    }

    public void pause(View v) {
        mi.pause();
    }

    public void continuePlay(View v) {
        mi.continuePlay();
    }

    public void exit(View v) {

//        解除绑定
        unbindService(conn);
//关闭服务
        stopService(intent);
        finish();

    }


    private class MyserviceConn implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //这是本地服务,所以不需要aidl,直接用接口强转
            mi = (MusicInterface) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}
Service:

package com.lyz.news.day33nusic;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by Administrator on 2015/9/20.
 */
public class MusicService extends Service {

    MediaPlayer player;
    private Timer timer;

    @Override//暂停
    public IBinder onBind(Intent intent) {
        return new MusicController();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //初始化创建一个MediaPlayer对象
        player = new MediaPlayer();
        //我 在这不小心写一个,导致资源初始化就被null所以报错空指针,
//        player=null;



    }

    @Override
    public void onDestroy() {
        super.onDestroy();

//        关闭音乐,但现在基本不用了
        player.stop();
//        释放所有资源,在c语言的角度,player已经不存在了,想再播放必须从新new了
        player.release();
        //停掉计时器
        if (timer != null) {
            timer.cancel();
            timer = null;
        }

    }


    class MusicController extends Binder implements MusicInterface {


        @Override
        public void play() {
            MusicService.this.play();
        }

        @Override
        public void pause() {
            //        MusicService.this 代表当前这个类的对象。方法来在内部类调用本类的方法
            MusicService.this.pause();
        }

        @Override
        public void continuePlay() {
            MusicService.this.continuePlay();
        }

        @Override
        public void seekTo(int progress) {

         player.seekTo(progress);

        }
    }

            //改变当前播放进度,视频居然在()随便想传什么,就传了个什么,因为这个是service里的方法我们想让他在Mainactvity里被调用只能给他到中间人里
            public void seekTo(int progress){
                player.seekTo(progress);
            }


    //播放音乐
    public void play() {
//        必须重置,重置后就可以加载数据,和调用方法
        player.reset();
        try {
            //这个资源,可能是不存在,可能是无法加载,所以必须try cath
            player.setDataSource("sdcard/qw.mp3");
            //设置网络资源
//            player.setDataSource("http://192.168.1.101:8080/examples/qy.mp3 ");

//            准备,加载资源,是同步,对于本地什么的可以,但是音乐太大了,无法确定是否加载完,网络要用异步,因为必须要在子线程,加载;
//            player.prepare();
//          播放,网络音乐
//            player.start();
            //网络异步
            player.prepareAsync();
            //设置一个播放监听,监听一下他是否加载完了,加载完了,让他进入下面的方法,因为你直接start不知道是否加载完了,所以必须用回调
            player.setOnPreparedListener( new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
//                    能进到这里说明已经加载完了
                    player.start();
                    addTimer();
                }
            });


        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    //    暂停
    public void pause() {
        player.pause();
    }

    //再次播放,继续播放
    public void continuePlay() {
        player.start();
    }

    public void addTimer() {
//        timer==null 我们就new一个
        if (timer == null) {


            timer = new Timer();
            /**
             * timer可以设置 你执行 子线程  的时间;所以叫做计时器
             * 我们开了一个子线程让获取的  歌曲的总时长   歌曲的总进度
             * 不断的变化,半秒一更新
             *
             *
             * long per period 默认是毫秒 执行间隔 设置1000 视频荷给的是500??为什么 就是让他1秒执行一次run()
             我需要传递给SeekBar ,需要在子线更新UI 所以用消息队列;
             */

            timer.schedule(new TimerTask() {//schedule
                @Override
                public void run() {
                    //             获取   歌曲的总时长
                    int duration = player.getDuration();
                    //                获取歌曲的进度
                    int currentPosition = player.getCurrentPosition();

                    //创建消息
                    Message msg = MainActivity.handler.obtainMessage();
                    /**
                     以前我用obj来装消息,但是obj值能装一个内容;
                     *但是我们能把2个数据定义成一个数组,或是集合啊
                     *
                     * 通过我们的消息发送给我们的主线程
                     */
                    //把  歌曲的总时长, 获取歌曲的进度 封装到Bundle
                    Bundle bundle = new Bundle();
                    bundle.putInt("duration", duration);
                    bundle.putInt("currentPosition", currentPosition);
                    //   setData              Bundle 里的数据塞到消息对象
                    msg.setData(bundle);


                    //不要直接发送空信息,我们要携带数据,我们数据send发送到 handler那边去
                    MainActivity.handler.sendMessage(msg);

                }
                //            开始计时任务后的5毫秒中,第一执行run方法,以后每500毫秒执行一次run方法来获取进度
            }, 5, 500);

        }
    }
}
interface:


package com.lyz.news.day33nusic;

/**
 * Created by Administrator on 2015/9/20.
 */
public interface MusicInterface {

   void  play();
    void pause();

    void continuePlay(  );
     void seekTo(int progress);

}


记得要在清单文件里 设置 服务;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值