Android媒体录制器冻结(锁定)UI线程

时间:2013-03-16 23:29:09

标签: android multithreading mediarecorder ui-thread

我正在开发一个GPS应用程序,用户可以在屏幕上的任意位置点按以录制音频片段,然后在录制时将其附加到轨道。我正在使用媒体记录器在我的应用程序内执行此操作,而不是发出隐含的意图。这样,用户可以“无眼睛”操作,如下所示。我编写了两种模式:(1)用户点击和应用程序记录一个简短的,固定的(10秒)片段; (2)用户点击以启动媒体记录器,然后再次点击以停止它。

我在Overlay.onTap中观察点击,并在自己的线程中运行媒体记录器。代码如下。

这是我的问题,在模式(2)中:第一次点击后,媒体记录器启动正常,但没有后续的点击触发。实际上,在60秒的录制过程中,UI线程似乎已完全冻结。

顺便说一下,我最初在活动中编写了媒体记录器的东西;然后我把它移到后台线程试图解决冻结问题,但没有用。

重叠代码如下:

/**
* DKR: When User has tapped on a media icon,
* The MapView calls us here, giving us the GeoPoint
* (lat and lon) where User tapped. 
*/
@Override
public boolean onTap(GeoPoint tappedGeoPoint, MapView mapview)
{
  return commonOnTap(tappedGeoPoint);
}
//boolean isRecording = false;
 boolean oneTapAudio = false;
 boolean twoTapAudio = true;
 boolean firstTap = false;

 /**
 * Method AsyncOverlay.onTap calls commonOnTap and sends us the GeoPoint of the tap.
  * Send the tapped GeoPoint to each segment object, to see which one has
* the corresponding media waypoint, if any.
 */
 public boolean commonOnTap(GeoPoint tappedGeoPoint)
{
   boolean isLogging = GPSLoggerService.isLogging();
   if ( isLogging )
   {
      if ( oneTapAudio )  // Override so that tap takes User to audio recorder @ InsertNote.addQuickAudio
      {                   // Possibly run addQuickAudio in background thread for greater reliability.
         Intent intent = new Intent(mLoggerMap.getActivity(), InsertNote.class);
         String s = GPStracking.AUTHORITY+"/Request";
         intent.putExtra(s, InsertNote.ONETAPAUDIO);
         mLoggerMap.getActivity().startActivity(intent);
         return true;
         //mLoggerMap.invalidate();
         //InsertNote insert = new InsertNote();
         //insert.addQuickAudio();
      }
      if ( twoTapAudio )
      {
         if ( !firstTap )
         {
            firstTap = true;
            Intent intent = new Intent(mLoggerMap.getActivity(), InsertNote.class);
            String s = GPStracking.AUTHORITY+"/Request";
            intent.putExtra(s, InsertNote.TWOTAPONAUDIO);
            mLoggerMap.getActivity().startActivity(intent);
         }
         else
         {
            firstTap = false;
            Intent intent = new Intent(mLoggerMap.getActivity(), InsertNote.class);
            String s = GPStracking.AUTHORITY+"/Request";
            intent.putExtra(s, InsertNote.TWOTAPOFFAUDIO);
            mLoggerMap.getActivity().startActivity(intent);
         }
         return true;
      }
   }

  boolean handled = false;
  for (SegmentRendering segment : mSegmentRenderersList)
  {
     if (!handled)
     {
        handled = segment.commonOnTap(tappedGeoPoint);
     }
  }
  return handled;
}

活动代码如下:

@Override
protected void onCreate(Bundle savedInstanceState)
{
  super.onCreate(savedInstanceState);
  this.setVisible(false);
  paused = false;
  isRecording = false;
  mLoggerServiceManager = new GPSLoggerServiceManager(this);

  final Semaphore audioSemaphore = new Semaphore(0);
  mRecordAudioThread = new Thread("audioRecorder")
  {

     @Override
     public void run()
     {
        Looper.prepare();             // Initialize the current thread as a looper.
        mAudioThreadHandler = new Handler();     // Create an Handler to communicate with the Looper.
        audioSemaphore.release(); // the only release in the whole program
        Looper.loop();                // Run the message queue in this thread.
     }
  };
  mRecordAudioThread.start();
  try
  {
     audioSemaphore.acquire();
  }
  catch (InterruptedException e)
  {
     Log.e(TAG, "Failed waiting for a semaphore", e);
  }
 }

@Override
protected void onResume()
{
  int request = 0;
  super.onResume();
  String s = GPStracking.AUTHORITY+"/Request";
  Bundle extras = getIntent().getExtras();
  if (extras != null) request = extras.getInt(s);      
  if ( request  == ONETAPAUDIO || request  == TWOTAPONAUDIO || request  == TWOTAPOFFAUDIO )
  {
     QuickAudioLogic( request );
     return;
  }

  if (mServiceBindAction == null)
  {
     mServiceBindAction = new Runnable()
     {
        @Override
        public void run()
        {
           showDialog(DIALOG_INSERTNOTE);
        }
     };
  }
  ;
  mLoggerServiceManager.startup(this, mServiceBindAction);
}

@Override
protected void onPause()
{
  super.onPause();
  mLoggerServiceManager.shutdown(this);
  paused = true;
  if (mRecorder != null) {
     mRecorder.release();
     mRecorder = null;
 }
}

public void QuickAudioLogic(int request)
{
  mRecorder = new MediaRecorder();
  if ( request == ONETAPAUDIO )  
  {
     if ( !isRecording )
     {
        isRecording = true;
        mDuration = ONETAPDURATION;
        mAudioThreadHandler.post(recordAudioAsync);
        //            QuickAudioAction ( ONETAPDURATION );
     }
     return;
  }
  if ( request == TWOTAPONAUDIO )
  {
     if ( !isRecording )
     {
        isRecording = true;
        mDuration = TWOTAPDURATION;
        mAudioThreadHandler.post(recordAudioAsync);
        //            QuickAudioAction ( TWOTAPDURATION );
     }
     return;
  }
  if ( request == TWOTAPOFFAUDIO )
  {
     if ( isRecording )
     {
        isRecording = false;
        Toast.makeText(this, "Stop recording audio",Toast.LENGTH_SHORT).show();
        mRecorder.reset();
        mRecorder.release();
        mRecorder = null;
        finish();
     }
  }
}

后台(媒体记录器)线程如下:

public Runnable recordAudioAsync = new Runnable()
{

  @Override
  public void run()
  {
     String newName;
     Calendar c = Calendar.getInstance();
     newName = String.format( "Audio" + getString( R.string.dialog_filename_default)+".3gpp", c, c, c, c, c, c );
     //newName = String.format("Audio_%tY-%tm-%td_%tH%tM%tS.3gpp", c, c, c, c, c, c);
     File newFile = new File(Constants.getSdCardDirectory(InsertNote.this) + newName);
     newName = newFile.toString();
     android.net.Uri.Builder builder = new Uri.Builder();;
     sUri = builder.scheme("file").appendEncodedPath("/"+newName).build();
     //sUri = Uri.parse(newName);  // store Uri static, so that   
     try {
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        mRecorder.setOutputFile(newName);
        mRecorder.setMaxDuration( mDuration );//mDuration = 10000 for one tap or 60000 for two tap mode
        mRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener(){ 
           @Override 
           public void onInfo(MediaRecorder mr, int what, int extra) { 
                 if(what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED ) 
                 {
                    InsertNote.this.mLoggerServiceManager.storeMediaUri(sUri);
                    //setResult(MENU_VOICE, new Intent());
                    //mLoggerMap.invalidate();
                    isRecording = false;
                    Toast.makeText(InsertNote.this, "Timeout recording audio",Toast.LENGTH_SHORT).show();
                    mRecorder.reset();
                    mRecorder.release();
                    finish();
                    //startActivity(new Intent(this.getApplicationContext(), ANOTHERACTIVITY.class)); 
                 } 
              } 
           });
        mRecorder.prepare();
        isRecording = true;
        Toast.makeText(InsertNote.this, "Start recording audio",Toast.LENGTH_LONG).show();
        mRecorder.start();
        //((Button)(findViewById(R.id.record_button))).setText("stop");
     } 
     catch (Exception e) {
        Toast.makeText(InsertNote.this, "Error starting audio recorder.",Toast.LENGTH_SHORT).show();
     }
     return;
  }
};

1 个答案:

答案 0 :(得分:0)

只能从UI线程修改UI组件。 删除toast消息或尝试将线程作为UI线程运行。

public void run(){
activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
                    // Things to do
                 }
              });
             }