【问题标题】:thread problem when recording audio录制音频时出现线程问题
【发布时间】:2011-01-30 13:15:41
【问题描述】:

我正在尝试使用 AudioRecord 录制音频样本。我已经使用线程来执行记录方法。线程似乎有问题。任何想法为什么?

package com.tecmark;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class recorder extends Activity  {




    private Thread thread;
    private boolean isRecording;
    private AudioRecord recorder;
    private FileOutputStream os;
    private BufferedOutputStream bos;
    private DataOutputStream dos;
    private TextView text;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);



    }



    public void onClickPlay(View v){


    }


    public void record(){


        Log.i("inside record method", "******");

         text = (TextView)findViewById(R.id.TextView01);
         text.setText("recording");

        int audioSource = MediaRecorder.AudioSource.MIC;
        int sampleRate = 22050;
        int channel = AudioFormat.CHANNEL_CONFIGURATION_MONO;
        int encoding = AudioFormat.ENCODING_PCM_16BIT;
        int result = 0;



        File path = Environment.getExternalStorageDirectory();
        Log.v("file path", ""+path.getAbsolutePath());

        File file = new File(path, "test.wav");

        if(file.exists()){
            file.delete();
        }

        path.mkdirs();
        Log.v("file path", ""+file.getAbsolutePath());

         recorder = new AudioRecord(audioSource, sampleRate,channel,encoding,
                    AudioRecord.getMinBufferSize(sampleRate, channel,encoding));
                    Log.i("recorder", "recorder object created");

            try {
                 os = new FileOutputStream(file);
                 bos = new BufferedOutputStream(os);            
                 dos = new DataOutputStream(bos);
            } catch (Exception e1) {

                e1.printStackTrace();
            }


            int bufferSize = AudioRecord.getMinBufferSize(sampleRate,channel,encoding);
            byte[] buffer = new byte[bufferSize];

            recorder.startRecording();
            isRecording = true;

        try{  

        while (isRecording){



                 result = recorder.read(buffer, 0, bufferSize);
                 for(int a=0; a<result;a++){
                    dos.write(buffer[a]);

                    if(!isRecording){
                        recorder.stop();

                        break;
                    }

                 }

            }
            dos.flush();
            dos.close();

        }catch(Exception e) {

            e.printStackTrace();
        }

    }// end of record method




         public void onClickStop(View v){
                Log.v("onClickStop", "stop clicked");

                isRecording=false;


            }   



    public void onClickReverse(View v){
        Log.v("onClickReverse", "reverse clicked");


    } 

    public void onClickRecord(View v){

        thread = new Thread(new Runnable() {


            public void run() {
                isRecording = true;
                record();
            }
        });

        thread.start();

        isRecording = false;


    }

}//end of class

这是错误。

01-30 12:27:50.434: ERROR/AndroidRuntime(2226): Uncaught handler: thread Thread-8 exiting due to uncaught exception
01-30 12:27:50.459: ERROR/AndroidRuntime(2226): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at android.view.ViewRoot.checkThread(ViewRoot.java:2706)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at android.view.ViewRoot.invalidateChild(ViewRoot.java:573)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:599)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at android.view.ViewGroup.invalidateChild(ViewGroup.java:2396)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at android.view.View.invalidate(View.java:4945)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at android.widget.TextView.checkForRelayout(TextView.java:5366)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at android.widget.TextView.setText(TextView.java:2684)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at android.widget.TextView.setText(TextView.java:2552)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at android.widget.TextView.setText(TextView.java:2527)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at com.tecmark.recorder.record(recorder.java:54)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at com.tecmark.recorder$1.run(recorder.java:151)
01-30 12:27:50.459: ERROR/AndroidRuntime(2226):     at java.lang.Thread.run(Thread.java:1096)

【问题讨论】:

    标签: android multithreading


    【解决方案1】:

    您在record() 中调用findViewById(),但record() 未在UI 线程中运行,因为您在新线程的run() 方法中调用它。正如错误所说:

    android.view.ViewRoot$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能接触其视图

    从您的record() 方法中删除对findViewById()text.setText() 的调用。相反,请在创建新线程之前尝试在 onClickRecord() 中设置您的 UI 元素。

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        text = (TextView)findViewById(R.id.TextView01);
    }
    ...
    public void onClickRecord(View v){
        text.setText("recording");
        thread = new Thread(new Runnable() {
            public void run() {
                isRecording = true;
                record();
            }
        });
        thread.start();
        isRecording = false;
    }
    

    【讨论】:

    • 好的,谢谢,但我在 oncreate 方法中使用 setContentView 设置了四个按钮。这就是我布局应用程序的方式。我如何将按钮放在记录方法中。这是你的意思吗?
    • @turtleboy 我已经更新了我的答案。您应该首先在您的onCreate() 方法中创建并设置对您的TextView 的引用。然后只需确保您对其所做的任何更新(即调用text.setText())都发生在 UI 线程中。
    • @dave.c 请看我的问题,让我知道为什么我的 UI 线程挂起,即使我有一个单独的线程来阅读.....stackoverflow.com/questions/9413998/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    相关资源
    最近更新 更多