使用MediaPlayer播放音频文件

MediaPlayer是一个支持音频及视频文件播放的Android类,可播放不同来源(本地或网络流媒体)、多种格式(如WAV、MP3、Ogg Vorbis、MPEG-4以及3GPP)的多媒体文件。

新建音视频播放、暂停和停止封装类

package com.huangfei.hellomoon;

import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;

/**
 * 
 * @author huangfeihong 音视频播放、暂停和停止封装类
 */
public class AudioPlayer {

    private MediaPlayer mPlayer;

    /**
     * 暂停
     */
    public void pause() {
        if (mPlayer != null) {
            mPlayer.pause();
        }
    }

    /**
     * 停止
     */
    public void stop() {
        if (mPlayer != null) {
            /**
             * MediaPlayer.release()方法可销毁MediaPlayer的实例。销毁是“停止”的一种具有攻击意味的说法,
             * 但我们有充足的理由使用销毁一词。
             * 除非调用MediaPlayer.release()方法,否则MediaPlayer将一直占用着音频解码硬件及其它系统资源
             * 。而这些资源是由所有应用共享的。
             * MediaPlayer有一个stop()方法。该方法可使MediaPlayer实例进入停止状态,等需要时再重新启动
             * 。不过,对于简单的音频播放应用,建议 使用release()方法销毁实例,并在需要时进行重见。基于以上原因,有一个简单可循的规则:
             * 只保留一个MediaPlayer实例,保留时长即音频文件 播放的时长。
             */
            mPlayer.release();
            mPlayer = null;
        }
    }

    /**
     * 播放
     */
    public void paly(Context c) {
        /**
         * 开头就调用stop()方法,可避免用户多次单机Play按钮创建多个MediaPlayer实例的情况发生。
         */
        stop();

        /**
         * 音频文件放在res/raw目录下。目录raw负责存放那些不需要Android编译系统特别处理的各类文件。
         */
        mPlayer = MediaPlayer.create(c, R.raw.one_small_step);
        mPlayer.setOnCompletionListener(new OnCompletionListener() {

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

        mPlayer.start();
    }
}

创建播放音频的Fragment

package com.huangfei.hellomoon;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class HelloMoonFragment extends Fragment {
    private AudioPlayer mPlayer = new AudioPlayer();
    private Button mPlayButton;
    private Button mStopButton;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /**
         * 当旋转设备后,音频播放会停止,该如何保证音频一直播放?
         * 调用Fragment.setRetainInstance(true)方法可保留fragment。
         * 
         * 当设备旋转时,FragmentManager会检查每个fragment的retainInstance属性值。如果属性值为false(初始默认值),
         * FragmentManager会立即销毁该fragment实例。随后,为适应新的设备配置,新的activity的新FragmentManager会创建
         * 一个新的fragment及其视图。如属性值为true,则该fragment的视图立即被销毁,但fragment本身不会被销毁。为适应新的设备配置,
         * 当新的activity创建后,新的FragmentManager会找到被保留的fragment,并重新创建它的视图。
         * 
         * 只有当activity因设备配置发生改变被销毁时,fragment才会短暂的处于被保留状态。如果activity是因操作系统需要回收内存而被销毁,
         * 则所有被保留的fragment也会被随之销毁。
         * 
         * 如果activity或fragment中有需要长久保存的东西,则应覆盖onSaveInstanceState(Bundle)方法,将其保存下来。这样,由于同activity记录的生命周期保持了同步,后续可在需要时对其进行回复。
         */
        setRetainInstance(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_hello_moon, container,
                false);
        mPlayButton = (Button) view.findViewById(R.id.hellomoon_palyButton);
        mPlayButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                mPlayer.paly(getActivity());
            }
        });
        mStopButton = (Button) view.findViewById(R.id.hellomoon_stopButton);
        mStopButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                mPlayer.stop();
            }
        });

        return view;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        /**
         * 调用AudioPlayer.stop()方法,以避免MediaPlayer的不停播放。该Fragment被销毁后,MediaPlayer仍可不停地播放,
         * 这是因为MediaPlayer运行在一个不同的线程上。
         */
        mPlayer.stop();
    }
}
<?xml version="1.0" encoding="utf-8"?>
<!-- TableLayout使用起来和LinearLayout差不多。联合使用TableLayout和TableRow,可更容易地布置形成排列整齐的视图。 -->
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:contentDescription="@string/hellomoon_image_description"
        android:scaleType="centerInside"
        android:src="@drawable/armstrong_on_moon" />

    <!--
         TableRow组件无需声明高度和宽度的属性定义。实际上,它使用的是TableLayout的高度和宽度属性定义及其所有其他属性定义。
         TableRow子组件的行为方式类似于表里的单元格。
    -->

    <TableRow
        android:layout_weight="0"
        android:gravity="center|bottom" >

        <Button
            android:id="@+id/hellomoon_palyButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hellomoon_play" />

        <Button
            android:id="@+id/hellomoon_stopButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hellomoon_stop" />
    </TableRow>

</TableLayout>

创建托管Fragment的Activity

package com.huangfei.hellomoon;

import android.os.Bundle;
import android.app.Activity;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;

public class HelloMoonActivity extends FragmentActivity {

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

}
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/helloMoonFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.huangfei.hellomoon.HelloMoonFragment" />

<!-- 使用布局fragment,即在fragment元素节点中指定fragment的类。在Activity调用setContentView(...)方法,并实例化布局时,发现了fragment元素。
     于是FragmentManager接着就创建了指定Fragment的一个实例,并将其添加到fragment对列中。
      使用如此简单的方式托管fragment,同时也失去了只有显示地使用FragmentManager才能获得的灵活性与掌控能力。
     1、可覆盖fragment的生命周期方法,以响应各种事件。但无法控制调用这些方法的时机。
     2、无法提交移除、替换、分离布局fragment的事务。activity被创建后,即无法做出任何改变。
     3、无法附加argument给布局fragment。附加argument必须在fragment创建后并被添加给FragmentManager之前完成。如果使用布局fragment,这些事件何时发生,我们无从得知。-->

代码地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值