2016-05-12 37 views
6

Próbuję utworzyć przycisk, który pozwala mi nagrywać dźwięk za pośrednictwem usługi, chcę przycisk mieć tekst: "Start Recording". W przypadku zdarzenia OnClick chcę, aby tekst przycisku zmienił się na: "Stop Recording".(Widok (przycisk)) wewnątrz usługi nie działa

Miałem ten kod działający, gdy był w klasie, ale teraz nie działa w usłudze, jednak, ponieważ chcę, aby rekord audio działał jako usługa, nie wydaje mi się, aby tekst przycisku mógł się zmienić. Jestem całkiem nowy w kodowaniu, więc każda pomoc będzie bardzo ceniona!

Mój kod wygląda następująco:

Klasa:

public class Test extends AppCompatActivity {  

    public void Record(View view) { 
     Intent intent = new Intent(this, RecordService.class); 
     startService(intent); 
    }  

    public void Play(View view) { 
     Intent intent = new Intent(this, RecordService.class); 
     stopService(intent);  
    } 
} 

Usługa:

import android.app.Service; 
import android.content.Intent; 
import android.media.MediaRecorder; 
import android.os.Environment; 
import android.os.IBinder; 
import android.widget.Button; 
import android.view.View; 

import java.io.IOException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 

public class RecordService extends Service { 

    MediaRecorder mRecorder; 
    public static String audioFilePath; 
    public boolean isRecording = false; 

    public RecordService() { 
    } 

    @Override 
    public IBinder onBind(Intent intent) { 
     // TODO: Return the communication channel to the service. 
     throw new UnsupportedOperationException("Not yet implemented"); 
    } 

    public void onCreate() { 

     if(mRecorder == null){ 

      SimpleDateFormat s = new SimpleDateFormat("ddMMyyyy_hhmmss"); 
      String format = s.format(new Date()); 

      audioFilePath = Environment.getExternalStorageDirectory(). 
        getAbsolutePath() + "/" + format + ".3gpp"; 

      mRecorder = new MediaRecorder(); 
      mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
      mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 
      mRecorder.setOutputFile(audioFilePath); 
      mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 
     } 

     if (isRecording) { 
      try{ 
       stopRecording(); 
       isRecording = false; 
       ((Button)view).setText("Start Recording"); 
      }catch(Exception e){ 
       e.printStackTrace(); 
      } 
     } else { 
      try{ 
       startRecording(); 
       isRecording = true; 
       ((Button)view).setText("Stop Recording"); 
      }catch(Exception e){ 
       e.printStackTrace(); 
      } 
     } 
    } 

    public void startRecording() throws IllegalStateException, IOException{ 
     mRecorder.prepare(); 
     mRecorder.start(); 
    } 

    public void stopRecording() throws IllegalStateException, IOException{ 
     mRecorder.stop(); 
     mRecorder.release(); 
    } 


    public void onStartCommand() 
    { 
     SimpleDateFormat s = new SimpleDateFormat("ddMMyyyy_hhmmss"); 
     String format = s.format(new Date()); 

     audioFilePath = Environment.getExternalStorageDirectory(). 
       getAbsolutePath() + "/" + format + ".3gpp"; 

     mRecorder = new MediaRecorder(); 
     mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
     mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 
     mRecorder.setOutputFile(audioFilePath); 
     mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 
     try { 
      mRecorder.prepare(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     mRecorder.start(); 

    } 

    public void onDestroy() 
    { 
     super.onDestroy(); 
     mRecorder.stop(); 
     mRecorder.release(); 

    } 


} 

aktywny:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" 
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    tools:context="kyr.com.knowyourrights.Test"> 

    <TextView android:text="@string/hello_world" android:layout_width="wrap_content" 
     android:layout_height="wrap_content" /> 

    <Button 
     android:text="Record" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:id="@+id/RecordButton" 
     android:layout_alignParentTop="true" 
     android:onClick="Record"> 
    </Button> 

</RelativeLayout> 

Odpowiedz

1

Chcesz przycisk, aby zadzwonić do eksploatacji, spróbuj użyć BroadcastReceiver

+0

Jak mogę połączyć to z istniejącym kodem? gdzie powinienem napisać metodę runOnUiThread, ponieważ nie mogę umieścić jej w mojej Boolean, a także nie mogę stworzyć z nią nowej metody? @hoanngothanh – Viverson

+0

@Viverson jak komentarz Xema, spróbuj użyć biblioteki otto – hoanngothanh

1

To, rzeczywiście, nie może pracować tutaj od czasu ((przycisk) View) nie wystąpienia w onCreate().

Sugeruję, aby wywołać z usługi funkcję wewnątrz działania, która wykonuje to, co chcesz zrobić (tutaj zmień tekst). Możesz to osiągnąć za pomocą BroadcastReceiver.

Aby to zrobić, można wykonać następujące czynności:

Wewnątrz działalność:

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

    // Register mMessageReceiver to receive messages. 
    LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, 
     new IntentFilter("change-text")); 
} 

// handler for received Intents for the "change-text" event 
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
    // Extract data included in the Intent 
    String message = intent.getStringExtra("message"); 
    button.setText(message); //Assuming you have instantiate properly your button inside your onCreate() 
    } 
}; 

@Override 
protected void onPause() { 
    // Unregister since the activity is not visible 
    LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver); 
    super.onPause(); 
} 

wewnątrz serwisu:

// Send an Intent with an action named "change-text". 
private void sendMessage(boolean startRecording) { 
    Intent intent = new Intent("change-text"); 
    // add data 
    if (startRecording) intent.putExtra("message", "Start Recording"); 
    else intent.putExtra("message","Stop Recording"); 
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 
} 

zmienić przycisk tekst z usługi, będzie musiał wywołać funkcję sendMessage z wartością true lub false jako parametrem w zależności od tego, co chcesz zrobić!

Można zobaczyć źródło kodu, który ja dostosowanej do sytuacji, tutaj: http://www.vogella.com/tutorials/AndroidBroadcastReceiver/article.html#ownreceiver_localbroadcastmanager

0

Coś jak to będzie działać

if (isRecording) { 
      try { 
       stopRecording(); 
       isRecording = false; 
       yourcontext.runOnUiThread(new Runnable() { 
        public void run() { 
         ((Button) view).setText("Start Recording"); 
        } 
       }); 


      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } else { 
      try { 
       startRecording(); 
       isRecording = true; 
       yourcontext.runOnUiThread(new Runnable() { 
        public void run() { 
         ((Button) view).setText("Stop Recording"); 
        } 
       }); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
+0

Mam takie same problemy z tym jak wcześniej, wyobrażam sobie, ponieważ usługa nie powinna wchodzić w interakcje z interfejsem użytkownika, dlatego nie mogę zmienić widoku przycisku – Viverson

0

Może lepiej byłoby zmienić tekst w aktywność, może bardziej pasować do ducha służby. Powinieneś rzucić okiem na ten temat: Example: Communication between Activity and Service using Messaging

Moim zdaniem, aby utworzyć program obsługi w komunikatorze jest bardzo przydatny i skuteczny sposób, aby utworzyć most komunikacji między usługą i działalności. W ten sposób prawdopodobnie utworzysz znaczniki stanu reprezentujące bieżący stan w Twojej usłudze, np.g w przypadku:

Message message = new Message(); 
message.setData(b); // bundle containing extra data if you need it 
message.what = MSG_RECORD_STOP; 
mActivity.send(message); 

Następnie w swojej działalności, gdy masz zwrotnego z Messenger, można po prostu zrobić coś takiego:

(TextView) mRecordButton =(TextView)rootView.findViewById(R.id.RecordButton); 
mRecordButton.setText("Stop Recording"); 
0

Dlaczego chcesz zmienić przycisk tekst w serwisie? Może tego właśnie potrzebujesz. public class test rozciąga AppCompatActivity {

public void Record(View view) { 
    Intent intent = new Intent(this, RecordService.class); 
    startService(intent); 
    yourButton.setText("Stop Recording"); 
} 



public void Play(View view) { 
    Intent intent = new Intent(this, RecordService.class); 
    stopService(intent); 
    yourButton.setText("Start Recording"); 

} 

}

+0

Czy to znaczy, że potrzebuję dwóch przycisków? jak wyobrażam sobie, że są to zasadniczo dwa różne zdarzenia kliknięcia, w jaki sposób dałbym jeden przycisk w moim pliku xml dwa zdarzenia kliknięcia? @Guliash – Viverson

0

Deklarują swoją przycisku jako statyczne w swojej działalności np

public static Button recordButton; 
public void onCreate(Bundle savedInstanceState) { 
    .... 
    recordButton =(Button) findViewById(R.id.RecordButton); 
    .... 
} 

następnie zrobić coś takiego w swojej służbie, w którym chcesz

WeakReference<Button> recordButton = new WeakReference<Button>(YourActivity.recordButton); 
recordButton.setText("Start Recording"); 
+0

To nie jest dobre rozwiązanie, istnieje wiele lepszych sposobów radzenia sobie z takim stanem, niż sprawienie, by widok był statyczny. – JoxTraex