安卓后台录音service和播放录音service实现

本文档展示了初学者如何在安卓应用中实现录音、播放功能,通过XML布局控制按钮,以及处理录音服务(RecordService)和播放服务(PlayerService)。还涉及了权限声明和界面管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

初学安卓,自己写的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();
    }

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值