android 音乐播放器小案例

时间:2022-08-13 10:13:30

案例主目的是为了复习一下Service服务 Handler消息机制 学习一下mediaplayer类 和了解自定义控件

MainAcitivity.java

package com.alleged.musicPlay;

import android.support.v7.app.ActionBarActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class MainActivity extends ActionBarActivity {
    private musicPlayer player;//接口
    private Context context;
    private Myconn conn;
    private static SeekBar seekbar;
    public static Handler handler = new Handler(){
        //当接受到消息时
        public void handleMessage(android.os.Message msg){
            Bundle data = msg.getData();
            //获取当前进度和总进度

            int drua = data.getInt("drua");
            int currentposition = data.getInt("currentposition");
            //设置进度条
            seekbar.setMax(drua);
            seekbar.setProgress(currentposition);
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 开启服务,暴露出播放 暂停 继续播放三个方法 使用handler消息机制把当前位置和总的位置返回回来
        // 先调用startservice 方法开启服务 保证服务在后台长期运行
        Intent intent = new Intent(this, musicService.class);
        //开启服务执行oncreate方法
        startService(intent);
        //自定义类实现serviceconnection接口
        conn = new Myconn();
        //绑定服务
        bindService(intent, conn, BIND_AUTO_CREATE);

        seekbar = (SeekBar) findViewById(R.id.palySeekbar);
        //对进度条设置拖拽变化事件监听
        seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {


            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                // TODO Auto-generated method stub

            }
            //停止拖拽
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                //设置播放的位置 
                player.SeekBar(seekBar.getProgress());
            }

        });

    }

    public void musicplay(View v) {
        player.musicPlay();
    }

    public void musicpause(View v) {
        player.musicpause();
    }

    public void musiccontinue(View v) {
        player.musicContinue();
    }

    // 当Activity销毁的时候调用
    @Override
    protected void onDestroy() {
        // 在Activity销毁的时候 取消绑定服务
        unbindService(conn);
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    public class Myconn implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 获取我们定义的中间人对象
            player = (musicPlayer) service;

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub

        }

    }
}

musicPlay接口(主要是为了暴露出服务中的方法)

package com.alleged.musicPlay;

public interface musicPlayer {
    public void musicPlay();
    public void musicpause();
    public void musicContinue();
    public void SeekBar(int position);
}

musicService服务

package com.alleged.musicPlay;

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

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

public class musicService extends Service {
    // 服务中创建mediaplayer类对象,对多媒体播放进行控制和设置
    private MediaPlayer mediaPlayer;

    @Override
    public IBinder onBind(Intent intent) {
        return new myBinder();
    }

    // 服务第一次开启的是调用
    @Override
    public void onCreate() {

        // [1]初始化mediaplayer
        mediaPlayer = new MediaPlayer();
        super.onCreate();
    }

    //设置音乐的播放位置
    public void SeekToPosition(int position){
        mediaPlayer.seekTo(position);
    }
    // 当服务销毁的时候调用
    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    public void mplay() {
        System.out.println("音乐开始播放");

        try{
            mediaPlayer.reset();
            //设置播放的歌曲的位置 
            mediaPlayer.setDataSource("/mnt/sdcard/Denitia and Sene - Casanova.mp3");
            //准备播放
            mediaPlayer.prepare();
            //开始播放
            mediaPlayer.start();
            updateSeekBar();
        }catch(Exception e){
            e.printStackTrace();
        }

    }
    private void updateSeekBar() {
        //获取当前歌曲的长度
        final int drua = mediaPlayer.getDuration();
        //定时器每一秒更新一次当前位置
        final Timer time = new Timer();
        final TimerTask task = new TimerTask(){

            //次线程复写run方法
            @Override
            public void run() {
                //获取当前歌曲的进度
                int currentposition = mediaPlayer.getCurrentPosition();

                //使用消息队列更新位置信息
                Message msg = new Message();
                Bundle bundle = new Bundle();
                bundle.putInt("drua", drua);
                bundle.putInt("currentposition", currentposition);
                msg.setData(bundle);
                MainActivity.handler.sendMessage(msg);
            }

        };
        //300毫秒后 每隔1秒钟获取一次当前歌曲的进度
        time.schedule(task, 300, 1000);
        //当歌曲播放完成的时候 把timer 和task 取消 
        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

            @Override
            public void onCompletion(MediaPlayer mp) {
                System.out.println("歌曲播放完毕");
                task.cancel();
                time.cancel();

            }
        });
    }

    public void mpause() {
        System.out.println("音乐暂停了");
        mediaPlayer.pause();

    }

    public void mcontinue() {
        System.out.println("音乐继续播放了");
        mediaPlayer.start();
    }

    public void mseekbar(int position) {
        //滚动条拖拽
        mediaPlayer.seekTo(position);

    }
    public class myBinder extends Binder implements musicPlayer{

        @Override
        public void musicPlay() {
            mplay();
        }

        @Override
        public void musicpause() {
            mpause();

        }

        @Override
        public void musicContinue() {
            mcontinue();

        }

        @Override
        public void SeekBar(int position) {
            mseekbar(position);

        }

    }

}

自定义控件实现圆形图片(网上copy过来的代码地址http://blog.csdn.net/alan_biao/article/details/17379925

package com.alleged.musicPlay;

import com.alleged.musicPlay.*;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.util.AttributeSet;
import android.widget.ImageView;

public class CircleImageView extends ImageView {

    private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;

    private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
    private static final int COLORDRAWABLE_DIMENSION = 2;

    private static final int DEFAULT_BORDER_WIDTH = 0;
    private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
    private static final boolean DEFAULT_BORDER_OVERLAY = false;

    private final RectF mDrawableRect = new RectF();
    private final RectF mBorderRect = new RectF();

    private final Matrix mShaderMatrix = new Matrix();
    private final Paint mBitmapPaint = new Paint();
    private final Paint mBorderPaint = new Paint();

    private int mBorderColor = DEFAULT_BORDER_COLOR;
    private int mBorderWidth = DEFAULT_BORDER_WIDTH;

    private Bitmap mBitmap;
    private BitmapShader mBitmapShader;
    private int mBitmapWidth;
    private int mBitmapHeight;

    private float mDrawableRadius;
    private float mBorderRadius;

    private ColorFilter mColorFilter;

    private boolean mReady;
    private boolean mSetupPending;
    private boolean mBorderOverlay;

    public CircleImageView(Context context) {
        super(context);

        init();
    }

    public CircleImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);

        a.recycle();

        init();
    }

    private void init() {
        super.setScaleType(SCALE_TYPE);
        mReady = true;

        if (mSetupPending) {
            setup();
            mSetupPending = false;
        }
    }

    @Override
    public ScaleType getScaleType() {
        return SCALE_TYPE;
    }

    @Override
    public void setScaleType(ScaleType scaleType) {
        if (scaleType != SCALE_TYPE) {
            throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
        }
    }

    @Override
    public void setAdjustViewBounds(boolean adjustViewBounds) {
        if (adjustViewBounds) {
            throw new IllegalArgumentException("adjustViewBounds not supported.");
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (getDrawable() == null) {
            return;
        }

        canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
        if (mBorderWidth != 0) {
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        setup();
    }

    public int getBorderColor() {
        return mBorderColor;
    }

    public void setBorderColor(int borderColor) {
        if (borderColor == mBorderColor) {
            return;
        }

        mBorderColor = borderColor;
        mBorderPaint.setColor(mBorderColor);
        invalidate();
    }

    public void setBorderColorResource(@ColorRes int borderColorRes) {
        setBorderColor(getContext().getResources().getColor(borderColorRes));
    }

    public int getBorderWidth() {
        return mBorderWidth;
    }

    public void setBorderWidth(int borderWidth) {
        if (borderWidth == mBorderWidth) {
            return;
        }

        mBorderWidth = borderWidth;
        setup();
    }

    public boolean isBorderOverlay() {
        return mBorderOverlay;
    }

    public void setBorderOverlay(boolean borderOverlay) {
        if (borderOverlay == mBorderOverlay) {
            return;
        }

        mBorderOverlay = borderOverlay;
        setup();
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        mBitmap = bm;
        setup();
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        mBitmap = getBitmapFromDrawable(drawable);
        setup();
    }

    @Override
    public void setImageResource(@DrawableRes int resId) {
        super.setImageResource(resId);
        mBitmap = getBitmapFromDrawable(getDrawable());
        setup();
    }

    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        mBitmap = getBitmapFromDrawable(getDrawable());
        setup();
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        if (cf == mColorFilter) {
            return;
        }

        mColorFilter = cf;
        mBitmapPaint.setColorFilter(mColorFilter);
        invalidate();
    }

    private Bitmap getBitmapFromDrawable(Drawable drawable) {
        if (drawable == null) {
            return null;
        }

        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        try {
            Bitmap bitmap;

            if (drawable instanceof ColorDrawable) {
                bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
            } else {
                bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
            }

            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return bitmap;
        } catch (OutOfMemoryError e) {
            return null;
        }
    }

    private void setup() {
        if (!mReady) {
            mSetupPending = true;
            return;
        }

        if (mBitmap == null) {
            return;
        }

        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        mBitmapPaint.setAntiAlias(true);
        mBitmapPaint.setShader(mBitmapShader);

        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setColor(mBorderColor);
        mBorderPaint.setStrokeWidth(mBorderWidth);

        mBitmapHeight = mBitmap.getHeight();
        mBitmapWidth = mBitmap.getWidth();

        mBorderRect.set(0, 0, getWidth(), getHeight());
        mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2);

        mDrawableRect.set(mBorderRect);
        if (!mBorderOverlay) {
            mDrawableRect.inset(mBorderWidth, mBorderWidth);
        }
        mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2);

        updateShaderMatrix();
        invalidate();
    }

    private void updateShaderMatrix() {
        float scale;
        float dx = 0;
        float dy = 0;

        mShaderMatrix.set(null);

        if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
            scale = mDrawableRect.height() / (float) mBitmapHeight;
            dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
        } else {
            scale = mDrawableRect.width() / (float) mBitmapWidth;
            dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
        }

        mShaderMatrix.setScale(scale, scale);
        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);

        mBitmapShader.setLocalMatrix(mShaderMatrix);
    }

}

使用了服务一定要在xml文件中配置一下

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.alleged.musicPlay" android:versionCode="1" android:versionName="1.0" >


    <uses-sdk  android:minSdkVersion="8" android:targetSdkVersion="21" />

    <application  android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" >
        <activity  android:name=".MainActivity" android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name="com.alleged.musicPlay.musicService"></service>
    </application>

</manifest>

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res/com.alleged.musicPlay" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical|center_horizontal" android:orientation="vertical" tools:context="com.alleged.musicPlay.MainActivity" >

    <com.alleged.musicPlay.CircleImageView  android:id="@+id/roundImageView" android:layout_width="200dp" android:layout_height="200dp" android:layout_centerInParent="true" android:src="@drawable/pre19" />

    <LinearLayout  android:id="@+id/button_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:orientation="horizontal" >

        <Button  android:id="@+id/play" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_weight="1" android:gravity="center_horizontal|center_vertical" android:text="播放" android:textSize="15sp" android:onClick="musicplay" >
        </Button>

        <Button  android:id="@+id/wait" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_weight="1" android:gravity="center_horizontal|center_vertical" android:text="暂停" android:textSize="15sp" android:onClick="musicpause" >
        </Button>

        <Button  android:id="@+id/replay" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_weight="1" android:gravity="center_horizontal|center_vertical" android:text="继续播放" android:textSize="15sp" android:onClick="musiccontinue" >
        </Button>
    </LinearLayout>
    <LinearLayout android:id="@+id/seekbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:orientation="horizontal" >

        <SeekBar  android:id="@+id/palySeekbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" />
    </LinearLayout>

</LinearLayout>

结果如下android 音乐播放器小案例