0

我正在尝试编写一个录音机应用程序。整个应用程序由两个组件组成:Main Activity,它只包含一个名为 RecordFragment 的片段,以及负责录制音频的 RecordThread 类。

RecordThread 是从 HandlerThread 扩展而来的。

这个想法是用户按下一个按钮,并且附加到 RecordThread looper 的处理程序发送一条空消息以开始录制。然后线程应该处理该消息并开始录制,直到用户再次按下按钮停止录制,该处理程序再次发送另一条消息(我认为线程的消息队列)以停止录制。

问题#1:RecordThread 从不开始记录甚至处理来自队列的消息。

问题 #2:我应该如何处理 recordThread 中的消息?

记录线程.java

public class RecordThread extends HandlerThread {
    private final String TAG = "RecordThread";
    private final int RECORD_START = 1;
    private final int RECORD_STOP = 3;

    private MediaRecorder mRecorder;
    private String mFilePath = null;
    private String mFileName = null;
    private Handler mHandler;

    public RecordThread(String name) {
        super(name);
    }

    @Override
    protected void onLooperPrepared() {
        super.onLooperPrepared();

        mHandler = new Handler(getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case RECORD_START:
                        startRecording();
                        Log.d(TAG, "Recording");
                        break;

                    case RECORD_STOP:
                        stopRecording();
                        Log.d(TAG, "Stopping");
                        break;
                }
            }
        };
    }

    // prepares the media recorder and starts recording
    private void startRecording() {
        seuUpFilePath();

        mRecorder = new MediaRecorder();
        mRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mRecorder.setOutputFile(mFilePath);
        mRecorder.setAudioChannels(1);

        try {
            mRecorder.prepare();
            mRecorder.start();
        } catch (IOException e) {
            Log.e(TAG, "Error while preparing Media Recorder" + e.toString());
        }
    }

    /**
     * create file's name and path for storing it on external storage
     */
    private void seuUpFilePath() {
        // building file's name
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss",
                new Locale("en", "IR"));

        Date date = Calendar.getInstance().getTime();

        String currentTime = dateFormat.format(date);
        mFileName = "Record" + currentTime + ".mp4";

        // creating file's path
        mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath();
        mFilePath += "/Sound Recorder/" + mFileName;
        Log.d(TAG, "FilePath: " + mFilePath);
    }

    private void stopRecording() {
        mRecorder.stop();
        mRecorder.reset();
        mRecorder.release();
        mRecorder = null;
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void resumeRecorder() {
        mRecorder.resume();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void pauseRecording() {
        mRecorder.pause();
    }


}

记录片段.java

public class RecordFragment extends Fragment {

    private static final String TAG = "RecordFragment";
    private final String THREAD_RECORDING = "recording thread";
    private final int RECORD_START = 1;
    private final int RECORD_STOP = 3;

    int count = 1;

    private FloatingActionButton mRecordFab;
    private boolean isRecording = false;
    private boolean paused = false;
    private RecordThread mRecordThread;
    private Handler mRecordHandler;
    private Chronometer mChronometer;
    private TextView mMessage;
    private long timeWhenPaused;


    public RecordFragment() {
        // Required empty public constructor
    }

    public static RecordFragment newInstance() {
        return new RecordFragment();
    }

    /**
     * getting reference to views and setting basic attributes
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_record, container, false);

        mChronometer = view.findViewById(R.id.chronometer);

        mMessage = view.findViewById(R.id.recording_status_tv);
        mMessage.setText("Tap the button to start recording");

        mRecordFab = view.findViewById(R.id.record_fab);

        return view;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mChronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            @Override
            public void onChronometerTick(Chronometer chronometer) {
                switch (count) {
                    case 1:
                        mMessage.setText("Recording.");
                        count++;
                        break;

                    case 2:
                        mMessage.setText("Recording..");
                        count++;
                        break;

                    case 3:
                        mMessage.setText("Recording...");
                        count = 1;
                        break;
                }
            }
        });

        mRecordFab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // stop recording
                if (isRecording) {
                    Log.d(TAG, "Stopping");
                    mRecordFab.setImageResource(R.drawable.ic_mic_white_36dp);
                    mChronometer.stop();
                    mChronometer.setBase(SystemClock.elapsedRealtime());
                    mMessage.setText("Tap the button to start recording");

                    mRecordHandler.sendEmptyMessage(RECORD_STOP);

                    Log.d(TAG, "thread state:" + mRecordThread.getState());
                    Log.d(TAG, "thread interrupted?: " + mRecordThread.isInterrupted());
                    Log.d(TAG, "thread is alive? " + mRecordThread.isAlive());

                    isRecording = false;
                }

                // start recording
                else {
                    // changing views attributes
                    mRecordFab.setImageResource(R.drawable.ic_media_stop);
                    mChronometer.setBase(SystemClock.elapsedRealtime());
                    mChronometer.start();

                    isRecording = true;

                    Log.d(TAG, "handler succeeded? " + mRecordHandler.sendEmptyMessage(RECORD_START));

                    Log.d(TAG, "Recording");
                    Log.d(TAG, "thread interrupted?: " + mRecordThread.isInterrupted());
                    Log.d(TAG, "thread state:" + mRecordThread.getState());
                    Log.d(TAG, "thread is alive? " + mRecordThread.isAlive());
                }
    }

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

        mRecordThread = new RecordThread(THREAD_RECORDING);
        mRecordThread.start();
        mRecordHandler = new Handler(mRecordThread.getLooper());
        mRecordHandler.sendEmptyMessage(RECORD_START);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mRecordThread.quit();
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

<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>

4

0 回答 0