1

ユーザーが画面上の任意の場所をタップしてオーディオスニペットを記録し、ログに記録するときにトラックに添付できる GPS アプリを開発しています。暗黙のインテントを発行するのではなく、アプリ内でこれを行うためにメディア レコーダーを使用しています。これにより、ユーザーは次のように「アイズフリー」で操作できます。私は 2 つのモードをコーディングしました。(1) ユーザーのタップとアプリは短い固定 (10 秒) のスニペットを記録します。(2) ユーザーがタップしてメディア レコーダーを開始し、もう一度タップして停止します。

Overlay.onTap でタップを監視し、独自のスレッドでメディア レコーダーを実行します。コードは次のとおりです。

モード(2)での私の問題は次のとおりです。最初のタップの後、メディアレコーダーは正常に起動しますが、後続のタップは onTap を起動しません。実際、UI スレッドは 60 秒間の記録で完全にフリーズしているように見えます。

ところで、私はもともとメディア レコーダーをアクティビティでコーディングしていました。次に、それをバックグラウンド スレッドに移動して、フリーズの問題を解決しようとしましたが、役に立ちませんでした。

オーバーレイ コードは次のとおりです。

/**
* 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;
  }
};
4

1 に答える 1

0

UI コンポーネントは、UI スレッドからのみ変更できます。トースト メッセージを削除するか、スレッドを UI スレッドとして実行してみてください。

public void run(){
activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
                    // Things to do
                 }
              });
             }
于 2013-03-25T19:24:04.530 に答える