导读
1.录音播放及动态权限申请
2.语音聊天室案例
录音播放及动态权限申请
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.recordvoicedemo">
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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" tools:context="com.example.recordvoicedemo.MainActivity">
<Button
android:id="@+id/record_btn"
android:layout_width="0dp" android:layout_height="wrap_content"
android:text="准备说话" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintVertical_bias="1.0" />
</android.support.constraint.ConstraintLayout>
MainActivity.java
package com.example.recordvoicedemo;
import android.Manifest;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.File;
//按下按钮,开始录制(文本会变为”请大声说话“)
//松开按钮,停止录制(文本复原),播放刚刚录制的声音
public class MainActivity extends AppCompatActivity {
private Button recordBtn;
private MediaRecorder recorder; //录音
private MediaPlayer player; //播放声音
private File voiceFile;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initPermission();
recordBtn = (Button) findViewById(R.id.record_btn);
recordBtn.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
try {
//录音
recorder = new MediaRecorder();
//设置声音来源
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置声音格式,MPEG_4:音频、视频的标准格式
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
//设置声音编码
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
//准备文件用于承载录制的声音
voiceFile = File.createTempFile("myvoice", "mp3");
//设置声音的输出录音为刚刚准备好的文件所在的位置
recorder.setOutputFile(voiceFile.getAbsolutePath());
//准备
recorder.prepare();
//开始录制
recorder.start();
recordBtn.setText("请大声说话...");
}catch (Exception e){
e.printStackTrace();
}
return false;
}
});
recordBtn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
//手指按下
if(granted != PackageManager.PERMISSION_GRANTED){
Toast.makeText(MainActivity.this,"您不具备录制音频的权限",Toast.LENGTH_SHORT).show();
return true;
}
}
if(granted == PackageManager.PERMISSION_GRANTED &&motionEvent.getAction() == MotionEvent.ACTION_UP){
//手指松开,停止录音并播放
recorder.stop(); //停止
recorder.release(); //释放资源
recordBtn.setText("准备录音");
try {
//初始化
player = new MediaPlayer();
//设置播放源
player.setDataSource(voiceFile.getAbsolutePath());
//准备
player.prepare();
//开始播放
player.start();
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
//停止播放,释放资源,删除录音文件
player.stop();
player.release();
voiceFile.delete();
}
});
}catch (Exception e){
e.printStackTrace();
}
}
return false;
}
});
}
private void initPermission() {
//检查程序是否拥有这个权限
// ContextCompat.checkSelfPermission()
//请求权限
// ActivityCompat.requestPermissions();
//是否要像用户解释请求权限的行为
// ActivityCompat.shouldShowRequestPermissionRationale()
//1.获取程序是否具备该项权限
//如果是6.0一下的手机,该方法的返回值会始终为PERMISSION_GRANTED
//因此你并不需要动态申请权限,直接做你想做的
//如果是6.0以上的手机,情况就分为两种
//如果是noramal权限,该方法的返回值会始终为PERMISSION_GRANTED
//如果是dangerous权限,动态请求
int permission = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
Log.e("TAG","是否具备这项权限:" + permission);
// PackageManager.PERMISSION_GRANTED //权限被授予
// PackageManager.PERMISSION_DENIED //权限被拒绝
//2.判断,如果不具备权限,则申请权限
if(permission != PackageManager.PERMISSION_GRANTED ) {
//第一次运行时返回值为false
boolean should = ActivityCompat.
shouldShowRequestPermissionRationale(this,Manifest.permission.RECORD_AUDIO);
Log.e("TAG","是否需要向用户解释:" + should);
if(should){
explainDialog();
return;
}
//参数1:activity对象
//参数2:需要被授权的权限
//参数3:请求吗
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.RECORD_AUDIO},1);
}
}
private void explainDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setMessage("录音操作必须要录制音频的权限,是否授权?")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//请求权限
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.RECORD_AUDIO},1);
}
})
.setNegativeButton("取消",null);
builder.show();
}
private int granted; //用于保存权限是否被授予的凭证
/**
* 请求权限后的回调方法
* @param requestCode 是指在requestPermissions()传递的请求码
* @param permissions 是指在requestPermissions()传递的需要请求的权限
* @param grantResults 是指申请权限后返回的结果
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == 1) {
granted = grantResults[0];
}
}
}
语音聊天室案例
AndroidManifest.xml与上边一样
to_msg.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="right|center_vertical"
android:orientation="horizontal" >
<!-- 发送 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="right" >
<TextView
android:id="@+id/msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/chat_to_bg_normal"
android:text="这是我发出去的"
android:layout_marginLeft="18dp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/smiley_6" />
</LinearLayout>
from_msg.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical">
<!-- 接受 -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/smiley_7" />
<TextView
android:id="@+id/msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="18dp"
android:background="@mipmap/chat_from_bg_normal"
android:text="这是对方发给我的" />
</LinearLayout>
activity_chatting.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.recordvoicedemo.ChattingActivity"
android:background="@mipmap/bg">
<ListView
android:id="@+id/msg_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:layout_weight="1"
android:dividerHeight="4dp"></ListView>
<Button
android:id="@+id/vice_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="按住说话"/>
</LinearLayout>
ChattingActivity.java
package com.example.recordvoicedemo;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ChattingActivity extends AppCompatActivity {
private Button voiceBtn;
private ListView msgList;
private ChattingAdapter adapter;
private List<Msg> datas = new ArrayList<>();
private MediaRecorder recorder;
private List<File> voices = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chatting);
// initData();
initView();
}
private void initView() {
voiceBtn = (Button) findViewById(R.id.vice_btn);
msgList = (ListView) findViewById(R.id.msg_list);
adapter = new ChattingAdapter(datas,this);
msgList.setAdapter(adapter);
//长按按钮,开始录音,松开按钮,录音结束
//发送语音的效果
//未来在点击了聊天气泡后才播放对应的语音
voiceBtn.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
voiceBtn.setText("请开始说话...");
//录音
//一系列特性的设置
try {
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
//指定语音文件
File tempFile = File.createTempFile("temp","mp3");
recorder.setOutputFile(tempFile.getAbsolutePath());
//保存语音文件
voices.add(tempFile);
//开始录音
recorder.prepare();
recorder.start();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
});
voiceBtn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(motionEvent.getAction() == MotionEvent.ACTION_UP) {
voiceBtn.setText("按住说话");
//停止录音
recorder.stop();
recorder.release();
//更新聊天界面
datas.add(new Msg(" ",voices.get(voices.size()-1),1));
datas.add(new Msg("哈哈哈哈IMOOC",null,-1)); //伪造一条跟随着的收到的信息
adapter.notifyDataSetChanged();
msgList.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
}
return false;
}
});
msgList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Msg m = datas.get(i);
try {
if (m.getFlag() == 1) {
final MediaPlayer player = new MediaPlayer();
player.setDataSource(m.getF().getAbsolutePath());
player.prepare();
player.start();
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
player.stop();
player.release();
}
});
}
}catch (Exception e){
e.printStackTrace();
}
}
});
}
private void initData() {
Msg m1 = new Msg("您好",null,1);
Msg m2 = new Msg("您也好",null,-1);
Msg m3 = new Msg("在干嘛",null,1);
Msg m4 = new Msg("在看慕课网的视频",null,-1);
Msg m5 = new Msg("好看吗",null,1);
Msg m6 = new Msg("倍好看",null,-1);
Msg m7 = new Msg("推荐个网址呗",null,1);
Msg m8 = new Msg("www.imooc.com",null,-1);
datas.add(m1);
datas.add(m2);
datas.add(m3);
datas.add(m4);
datas.add(m5);
datas.add(m6);
datas.add(m7);
datas.add(m8);
}
@Override
protected void onDestroy() {
super.onDestroy();
for(int i = 0 ; i < voices.size() ; i++){
voices.get(i).delete();
}
}
}
ChattingAdapter.java
package com.example.recordvoicedemo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
//适配器:处理聊天记录样式
public class ChattingAdapter extends BaseAdapter {
private List<Msg> data;
private Context ctx;
public ChattingAdapter(List<Msg> data,Context ctx) {
this.data = data;
this.ctx = ctx;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
Msg g = data.get(i);
// if(view == null){ }
if(g.getFlag() == 1) {
view = LayoutInflater.from(ctx).inflate(R.layout.to_msg,null);
}else{
view = LayoutInflater.from(ctx).inflate(R.layout.from_msg,null);
}
TextView msg = (TextView) view.findViewById(R.id.msg);
msg.setText(g.getTxt());
return view;
}
}
Msg.java
package com.example.recordvoicedemo;
import java.io.File;
public class Msg {
//内容、涉及到 语音、发送/接受的标志
private String txt;
private File f;
private int flag; //1:本人 -1:对方
public Msg(String txt, File f, int flag) {
this.txt = txt;
this.f = f;
this.flag = flag;
}
public String getTxt() {
return txt;
}
public void setTxt(String txt) {
this.txt = txt;
}
public File getF() {
return f;
}
public void setF(File f) {
this.f = f;
}
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
}