初学安卓,自己写的demo,供大家参考,可以在此基础上实现更多功能。功能并不完善,还有许多地方值得优化,但是整体的流程基本上已经实现。坚持学习,你我都会成功。
大致结构分为:
- xml三个按钮控件实现:开始录音,停止录音,播放录音
- activty实现:按钮绑定事件,启动service和停止service
- 两个service:RecordService 实现录音功能,PlayerService实现播放功能,停止的话停掉录音service就可以了。
xml文件布局,随便写
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<Button
android:id="@+id/record"
android:text="后台录音开启"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/stoprecord"
android:text="结束录音"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/play"
android:text="播放录音"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
清单文件,权限声明
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<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/Theme.MyApplication">
<service
android:name=".RecordService"
android:enabled="true"
android:exported="true"></service>
<service
android:name=".PlayerService"
android:enabled="true"
android:exported="true" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity实现如下:
package com.example.backgroundservice; import android.Manifest; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.view.View; import android.widget.Button; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; public class MainActivity extends AppCompatActivity implements View.OnClickListener { Button record; Button stoprecord; Button play; private final String[] permissions=new String[]{ Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.SYSTEM_ALERT_WINDOW }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); //请求权限 ActivityCompat.requestPermissions(this,permissions,1); record=findViewById(R.id.record); stoprecord=findViewById(R.id.stoprecord); play=findViewById(R.id.play); record.setOnClickListener(this); stoprecord.setOnClickListener(this); play.setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId()==R.id.record){ //录音事件 Intent intent=new Intent(this, RecordService.class); startService(intent); }else if (v.getId()==R.id.stoprecord){ //停止录音,调用停止service的api Intent intent=new Intent(this, RecordService.class); stopService(intent); } else if (v.getId()==R.id.play) { //播放录音 需要显示上层窗口权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { //跳转设置界面 Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, 1); } } Intent intent=new Intent(this,PlayerService.class); startService(intent); } } }
RecordService实现如下:
package com.example.backgroundservice;
import android.app.Service;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.IBinder;
import java.io.File;
import java.io.IOException;
public class RecordService extends Service {
MediaRecorder mediaRecorder;
public RecordService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mediaRecorder==null){
mediaRecorder=new MediaRecorder();
}
//mediarecorder设置参数
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mediaRecorder.setOutputFile(new File(getExternalFilesDir(""),"test.mp3"));
}
try {
mediaRecorder.prepare();
} catch (IOException e) {
throw new RuntimeException(e);
}
mediaRecorder.start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
mediaRecorder.stop();
mediaRecorder.release();
mediaRecorder=null;
super.onDestroy();
}
}
PlayerService代码实现如下:
package com.example.backgroundservice;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.SeekBar;
import java.io.File;
import java.io.IOException;
public class PlayerService extends Service {
MediaPlayer mediaPlayer;
SeekBar seekBar;
WindowManager windowManager;
Handler handler;
public PlayerService() {
}
@Override
public IBinder onBind(Intent intent) {
return new Binder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//设置音频媒体
mediaPlayer=new MediaPlayer();
//设置生成文件
String path=getExternalFilesDir("")+"/tes1.mp3";
Log.d("test", "path: "+path);
try {
mediaPlayer.setDataSource(path);
//使用同步准备,异步准备会出现mediaplayer丢失问题
mediaPlayer.prepare();
} catch (IOException e) {
throw new RuntimeException(e);
}
mediaPlayer.start();
//测试日志
if (mediaPlayer.isPlaying()) {
Log.d("test", "onStartCommand: 正在播放");
}
//创建更新线程,实现进度条更新
handler=new Handler();
Runnable updateRunnable=new Runnable() {
@Override
public void run() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
//获取mediaplayer当前进度
int currentPosition = mediaPlayer.getCurrentPosition();
seekBar.setProgress(currentPosition);
//this是当前接口参数,不能写内部实现,否则会变成调用对象
handler.postDelayed(this, 1000); // 每秒更新一次
}
}
};
handler.post(updateRunnable);
//设置进度条
seekBar=new SeekBar(this);
seekBar.setMax(mediaPlayer.getDuration());
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mediaPlayer.seekTo(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
//设置界面,使用window生成视图
windowManager=(WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE);
//视图参数
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, // 或者其他类型,根据需要选择
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // 禁止窗口获得焦点
PixelFormat.TRANSLUCENT // 设置窗口的像素格式
);
//水平居中,处于底部
params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
//添加视图到窗口
windowManager.addView(seekBar,params);
//录音完成事件
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mediaPlayer.reset();
stopSelf();
}
});
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
windowManager.removeView(seekBar);
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
Log.d("test", "onDestroy: 执行");
super.onDestroy();
}
}