安卓核心技术高级——多媒体播放

简介

参考博客:https://blog.csdn.net/cbbbc/article/details/46789151

Android的多媒体框架包括支持播放多种常见的媒体类型,使您可以轻松地把音频、视频和图像集成到你的应用。你可以播放音频或视频媒体文件,这些文件是存储在你的应用程序的资源文件中的。应用程序的资源文件可以是文件系统中独立的文件,或通过网络连接获取的一个数据流,所有使用MediaPlayer APIS的资源文件。

注意:你只能在啊标准输出设备上播放音频数据。目前,标准输出设备是移动设备的扬声器或耳机,你不能再桃花音频调用期播放声音文件。

下面是Android框架中用于播放声音的类。

MediaPlayer:这个类主要用于播放声音和视频

AudioManager:这个类主要管理音频和音频输出设备

清单文件声明:

Internet许可-如果你是用的是基于网络内容的流媒体播放器,你的应用程序必须请求访问网络:

< uses-permission android:name="android.permission.INTERNET"/>

如果你的播放应用需要组织屏幕变暗或组织处理器睡眠,或使用MediaPlayer.setScreenOnWhilePlaying()或MediaPlayer.setWakeMode()方法,你必须请求此权限:

< uses-permission android:name="android.permission.WAKE_LOCK"/>

使用MediaPlayer

媒体框架最重要的组件之一是MediaPlayer类。此类的一个对象可以通过最少的设置来获取,解码和播放音频和视频。 它支持几种不同的媒体来源,如:

  • 本地资源
  • 内部URI,例如您可以从内容解析器获取的内部URI。
  • 外部网址(流媒体)
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

//    播放本地资源文件
    public void playFromRes(View view) {
        MediaPlayer mp = MediaPlayer.create(this,R.raw.m2);//做了mp.prepare();
        mp.start();
    }

//播放系统文件需要权限 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    public void playFromSys(View view) {
        MediaPlayer mp = new MediaPlayer();
        String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)+"/m2.mp3";
        try {
            mp.setDataSource(this, Uri.parse(path));//设置数据源
            mp.prepare();//同步执行
            mp.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

//播放网络文件,需要权限<uses-permission android:name="android.permission.INTERNET" />
    public void playFromInternet(View view) {
        String path = "http://wsaudio.bssdlbig.kugou.com/1904241105/KRFl0-837FZsule-bChmqQ/1556161531/bss/extname/wsaudio/9c148f1eda56b3a4fde051e431954962.mp3";
        MediaPlayer mp = new MediaPlayer();
        try {
            mp.setDataSource(this,Uri.parse(path));
            mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mp.start();
                }
            });
            mp.prepareAsync();//异步缓存
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用MediaPlayer

MediaPlayer可能消耗大量的系统资源。因此你应该总是采取一些额外的错事来确保在一个MediaPlayer实例上不会挂起太长的事件,当以用完MediaPlayer时,应该调用release()来保证任何分配给MediaPlayer的系统资源被正确地释放

简单的播放器实现案例

import android.media.MediaPlayer;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

//简单的播放器实现
public class MainActivity2 extends AppCompatActivity implements View.OnClickListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {

    private MediaPlayer mp;
    private int index = 0;//表示当前要播放的音乐的索引
    private ArrayList<String> musicList = new ArrayList<>();
    private Button button_prev,button_play,button_pause,button_next;
    private boolean isPause = true;//true表示暂停状态

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        initView();
        initMusic();
        mp = new MediaPlayer();
        mp.setOnPreparedListener(this);
        mp.setOnErrorListener(this);
        mp.setOnCompletionListener(this);
    }

    private void initView() {
        button_prev = (Button)findViewById(R.id.button_prev);
        button_play = (Button)findViewById(R.id.button_play);
        button_pause = (Button)findViewById(R.id.button_pause);
        button_next = (Button)findViewById(R.id.button_next);
        button_prev.setOnClickListener(this);
        button_play.setOnClickListener(this);
        button_pause.setOnClickListener(this);
        button_next.setOnClickListener(this);
    }

    private void initMusic(){
        String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath();
        musicList.add(root + File.separator + "m1.mp3");
        musicList.add(root + File.separator + "m2.mp3");
        musicList.add(root + File.separator + "m3.mp3");
        musicList.add(root + File.separator + "m4.mp3");
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.button_play:
                play();
                break;
            case R.id.button_pause:
                pause();
                break;
            case R.id.button_next:
                next();
                break;
            case R.id.button_prev:
                prev();
                break;
            default:
                break;
        }
    }

    //上一首
    private void prev() {
        if (index-1>=0){
            index--;
        }else {
            index = musicList.size()-1;
        }
        start();
    }

    //下一首
    private void next() {
        if (index+1<musicList.size()){
            index++;
        }else {
            index=0;
        }
        start();
    }

    //暂停
    private void pause() {
        if (mp.isPlaying()){
            mp.pause();
            isPause = true;
        }
    }

    //播放
    private void play() {
        if (!isPause){
            mp.start();
        }else {
            start();
        }
    }

    //重头开始播放音乐
    private void start(){
        if (index<musicList.size()){
            if (mp.isPlaying()) mp.stop();
            mp.reset();//重置
            String musicPath = musicList.get(index);
            try {
                mp.setDataSource(musicPath);
                mp.prepareAsync();
                isPause = false;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mp!=null){
            if (mp.isPlaying()) mp.stop();
            mp.release();
        }
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.start();
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        mp.reset();
        return true;
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        next();
    }
}

布局:

使用服务控制MediaPlayer

如果你希望你的媒体在你的应用不出现在屏幕上时仍能在后台播放——也就是,你希望当用户与其它应用交互时仍能继续播放,那么你必须启动一个Service并且通过它来控制MediaPlayer实例。

权限:
< uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

package com.example.mediaapplication;

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

import java.io.File;
import java.io.IOException;

public class MusicService extends Service implements MediaPlayer.OnPreparedListener {

    public static final String ACTION_PLAY = "com.example.ACTION_PLAY";
    public static final String ACTION_PAUSE = "com.example.ACTION_PAUSE";
    public static final String ACTION_EXIT = "com.example.ACTION_EXIT";
    private MediaPlayer mediaPlayer;
    public MusicService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnPreparedListener(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String action = intent.getAction();
        if (ACTION_PLAY.equals(action)){
            mediaPlayer.reset();
            try {
                mediaPlayer.setDataSource(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)+ File.separator+"m1.mp3");
                mediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else if (ACTION_PAUSE.equals(action)){
            if (mediaPlayer.isPlaying()) mediaPlayer.pause();
        }else if (ACTION_EXIT.equals(action)){
            if (mediaPlayer.isPlaying()) mediaPlayer.stop();
            mediaPlayer.release();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.start();
    }
}

清单文件:

<service android:name=".MusicService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.ACTION_PLAY"/>
                <action android:name="com.example.ACTION_PAUSE"/>
                <action android:name="com.example.ACTION_EXIT"/>
            </intent-filter>
        </service>

 布局:

 使用唤醒锁:

当你的MediaPlayer播放时,要保持CPU持续运行,在初始化MediaPlayer时需调用setWakeMode(),一旦你这样做了,MediaPlayer就会在播放时持有一个特定的锁,并在暂停或停止时释放它。

权限:   < uses-permission android:name="android.permission.WAKE_LOCK"/>

使用唤醒锁

在后台播放媒体的应用时,当你的service正在运行时,设备可能进入休眠,因为Android刺痛在休眠时会试着节省电能,系统会试着关闭电话的任何不必要的特性,包括CPU和WIFI,然而,如果你的service正在播放或接收音乐,你就想阻止系统干涉你的播放工作,为了在上述情况下保证你的service继续运行,你必须使用“wakelocks”。

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.os.IBinder;
import android.os.PowerManager;

import java.io.File;
import java.io.IOException;

public class MusicService extends Service implements MediaPlayer.OnPreparedListener {

    public static final String ACTION_PLAY = "com.example.ACTION_PLAY";
    public static final String ACTION_PAUSE = "com.example.ACTION_PAUSE";
    public static final String ACTION_EXIT = "com.example.ACTION_EXIT";
    private WifiManager.WifiLock lock;
    private MediaPlayer mediaPlayer;
    public MusicService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnPreparedListener(this);
        mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
        WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        lock = wifiManager.createWifiLock("mylock");
        lock.acquire();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String action = intent.getAction();
        if (ACTION_PLAY.equals(action)){
            mediaPlayer.reset();
            try {
                mediaPlayer.setDataSource(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)+ File.separator+"m1.mp3");
                mediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else if (ACTION_PAUSE.equals(action)){
            if (mediaPlayer.isPlaying()) mediaPlayer.pause();
        }else if (ACTION_EXIT.equals(action)){
            if (mediaPlayer.isPlaying()) mediaPlayer.stop();
            mediaPlayer.release();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        lock.release();
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.start();
    }
}

作为前台服务运行

修改Service中的以下内容

26以上版本需要加NotificationChannel,详见https://blog.csdn.net/weixin_40604111/article/details/78674563

@Override
    public void onCreate() {
        super.onCreate();
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnPreparedListener(this);
        mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
        WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        lock = wifiManager.createWifiLock("mylock");
        lock.acquire();
        notification();
    }


private void notification() {
        NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        Notification.Builder builder = null;
        if (Build.VERSION.SDK_INT >= 26) {
            String id = "channel_1";
            String description = "消息推送";
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel channel = new NotificationChannel(id, description, importance);
            manager.createNotificationChannel(channel);
            builder = new Notification.Builder(this,id);
        }else {
            builder = new Notification.Builder(this);
        }
        
        builder.setTicker("音乐播放器");
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setContentTitle("我的音乐播放器");
        builder.setContentInfo("正在播放");
        PendingIntent pi = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(pi);
        Notification notification = builder.build();
        startForeground(0, notification);
        manager.notify(0,notification);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopForeground(true);
        lock.release();
    }
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;

public class MainActivity3 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
    }

    public void play(View view) {
        Intent intent = new Intent(this,MusicService.class);
        intent.setAction(MusicService.ACTION_PLAY);
        startService(intent);
    }

    public void pause(View view) {
        Intent intent = new Intent(this,MusicService.class);
        intent.setAction(MusicService.ACTION_PAUSE);
        startService(intent);
    }

    public void stop(View view) {
        Intent intent = new Intent(this,MusicService.class);
        intent.setAction(MusicService.ACTION_EXIT);
        startService(intent);
    }
}

 

运行结果: 

 

处理音频焦点和AUDIO_BECOMING_NOISY意图

//MusicService.java
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.RequiresApi;

import java.io.File;
import java.io.IOException;

public class MusicService extends Service implements MediaPlayer.OnPreparedListener, AudioManager.OnAudioFocusChangeListener {

    public static final String ACTION_PLAY = "com.example.ACTION_PLAY";
    public static final String ACTION_PAUSE = "com.example.ACTION_PAUSE";
    public static final String ACTION_EXIT = "com.example.ACTION_EXIT";
    public static final String ACTION_STOP = "com.example.ACTION_STOP";
    private WifiManager.WifiLock lock;
    private MediaPlayer mediaPlayer;
    public MusicService() {
    }

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

        //获取自身的焦点
        AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);
        am.requestAudioFocus(this,AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN);

        mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnPreparedListener(this);

    }

    private void initMediaPlayer() {
        mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
        WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        lock = wifiManager.createWifiLock("mylock");
        lock.acquire();
        notification();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String action = intent.getAction();
        if (ACTION_PLAY.equals(action)){
            mediaPlayer.reset();
            try {
                mediaPlayer.setDataSource(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)+ File.separator+"m1.mp3");
                mediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else if (ACTION_PAUSE.equals(action)){
            if (mediaPlayer.isPlaying()) mediaPlayer.pause();
        }else if (ACTION_EXIT.equals(action)){
            if (mediaPlayer.isPlaying()) mediaPlayer.stop();
            mediaPlayer.release();
        }else if (ACTION_STOP.equals(action)){
            if (mediaPlayer.isPlaying()) mediaPlayer.stop();
        }
        return super.onStartCommand(intent, flags, startId);
    }


    private void notification() {
        NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        Notification.Builder builder = null;
        if (Build.VERSION.SDK_INT >= 26) {
            String id = "channel_1";
            String description = "消息推送";
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel channel = new NotificationChannel(id, description, importance);
            manager.createNotificationChannel(channel);
            builder = new Notification.Builder(this,id);
        }else {
            builder = new Notification.Builder(this);
        }

        builder.setTicker("音乐播放器");
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setContentTitle("我的音乐播放器");
        builder.setContentInfo("正在播放");
        PendingIntent pi = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(pi);
        Notification notification = builder.build();
        startForeground(0, notification);
        manager.notify(0,notification);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopForeground(true);
        lock.release();
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.start();
    }

    @Override
    public void onAudioFocusChange(int focusChange) {
        switch (focusChange){
            case AudioManager.AUDIOFOCUS_GAIN:
                //已获取焦点
                initMediaPlayer();
                mediaPlayer.setVolume(1.0f,1.0f);
                break;
            case AudioManager.AUDIOFOCUS_LOSS:
                //长期失去焦点
                if (mediaPlayer!=null){
                    if (mediaPlayer.isPlaying()) mediaPlayer.stop();
                    mediaPlayer.release();
                }
                break;
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                //失去了焦点,但很快会获得
                if (mediaPlayer!=null){
                    if (mediaPlayer.isPlaying()) mediaPlayer.stop();
                }
                break;
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                //允许低音量播放
                if (mediaPlayer.isPlaying()) mediaPlayer.setVolume(0.1f,0.1f);
                break;
        }
    }
}

 

<!--清单文件-->
        <service
            android:name=".MusicService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.ACTION_PLAY" />
                <action android:name="com.example.ACTION_PAUSE" />
                <action android:name="com.example.ACTION_EXIT" />
                <action android:name="com.example.ACTION_STOP" />
            </intent-filter>
        </service>
        <receiver android:name=".MusicIntentReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.media.AUDIO_BECOMING_NOISY"/>
            </intent-filter>
        </receiver>
//MusicIntentReceiver.java
public class MusicIntentReceiver extends BroadcastReceiver {

    private static final String action = "android.media.AUDIO_BECOMING_NOISY";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(action)){
            Intent intent1 = new Intent(MusicService.ACTION_STOP);
            context.startService(intent);
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
因为视频实在太大(>1G),所以删除,!!!注意!!!只有光盘,没有pdf,2012的书,批评没有pdf书的意见是可笑的, Android应用开发完全自学手册——核心技术、传感器、2D/3D、多媒体与典型案例 光盘 吴亚锋,于复兴 编著 人民邮电出版社 2012-3 本书共分21章,内容讲解上深入浅出,实例紧贴开发需求。在技术理论的讲解方面,《Android应用开发完全自学手册:核心技术、传感器、2D/3D、多媒体与典型案例》注重对实际动手能力和完全自学的指导,书中重点讲解了Android开发的核心知识及流行的应用技术,如游戏开发、2D应用、3D开发、动态壁纸、导航、传感器、OpenGL ES、多媒体、腾讯QQ客户端、贴图、渲染。在详细讲解技术研发的同时,在容易产生错误、不易理解的环节都配置了翔实的开发情景截图,并将重要的知识点、开发技巧以“小提示”、“程序注释”等活泼的形式呈现给读者。  书中案例均来自于笔者承接的实际开发项目,具有很高的商业价值。3大综合案例分别是休闲游戏——年年有鱼、艺术休闲——沙画涂鸦和V酷音乐盒。这些案例和示例充分体现了移动互联网应用创新精神,将很好地帮助初学者尽快融入实战角色。配书光盘赠送全部源程序和案例视频讲解。   本书适合Android初学者、Android从业人员,以及各培训机构和学校的教学用书。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值