#java #android #service #speech-recognition #android-context
#java #Android #Обслуживание #распознавание речи #android-контекст
Вопрос:
Для начала я знаю, что этот вопрос задавался несколько раз, но, похоже, я до сих пор не нашел ни одного, у которого был бы рабочий ответ для моего случая.
Итак, это мой класс обслуживания (РЕДАКТИРОВАНИЕ 2: теперь здесь почти весь код — извините, переменные на португальском языке -> при необходимости я все перевожу):
public class Google_voice_recognition extends Service implements RecognitionListener {
private SpeechRecognizer speechRecognizer;
private boolean a_ouvir = false;
private String processar_fala_string = "";
private String ultima_fala_processada = "";
private String fala_processada_total = "";
private long ativar_resultados_parciais_tempo = 0;
private int ativar_resultados_parciais_num = 0;
private boolean ativar_resultados_parciais = true;
private String ultima_fala_nao_util = "";
private Context contexto;
private boolean onEndOfSpeech_ultimo = false;
private long reposicao_reconhecimento_google_erro_tempo = 0;
public static final String ACAO_ENVIAR_TAREFA = "enviar_tarefa()";
@Override
public void onCreate() {
super.onCreate();
contexto = getApplicationContext();
System.out.println(this);
System.out.println("whatever 1");
if (contexto == null) {
System.out.println("null 1");
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
ativar_resultados_parciais = false;//Utils_gerais.func_ext_disponiveis();
System.out.println(ativar_resultados_parciais);
System.out.println(this);
speechRecognizer = SpeechRecognizer.createSpeechRecognizer(contexto);
Intent mSpeechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, contexto.getPackageName());
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE, true);
}
Reconhecimento_voz_Google listener = new Reconhecimento_voz_Google();
speechRecognizer.setRecognitionListener(listener);
speechRecognizer.startListening(mSpeechRecognizerIntent);
processamento_fala_parcial.start();
reposicao_reconhecimento_google_erro.start();
System.out.println("whatever 2");
if (contexto == null) {
System.out.println("null 2");
}
return START_NOT_STICKY;
}
@Override
public void onBeginningOfSpeech() {
ultima_fala_processada = "";
fala_processada_total = "";
processar_fala_string = "";
ativar_resultados_parciais_num = 0;
onEndOfSpeech_ultimo = false;
ultima_fala_nao_util = "";
}
@Override
public void onBufferReceived(byte[] buffer) {
}
@Override
public void onEndOfSpeech() {
System.out.println("GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG");
a_ouvir = false;
onEndOfSpeech_ultimo = true;
reposicao_reconhecimento_google_erro_tempo = System.currentTimeMillis();
ativar_resultados_parciais = false;
}
@Override
public void onError(int error) {
if (!a_ouvir) {
return;
}
a_ouvir=false;
onEndOfSpeech_ultimo = false;
reposicao_reconhecimento_google_erro_tempo = 0;
System.out.println("KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK");
System.out.println(error);
ativar_resultados_parciais = false;
speechRecognizer.stopListening();
}
@Override
public void onEvent(int eventType, Bundle params) {
}
@Override
public void onPartialResults(Bundle partialResults) {
ArrayList<String> matches = partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
if (ativar_resultados_parciais) {
if (matches != null) {
System.out.println(" ");
System.out.println(matches.get(0).toLowerCase());
if (!matches.get(0).toLowerCase().equals(ultima_fala_processada) amp;amp; matches.get(0).toLowerCase().length() - 1 > ativar_resultados_parciais_num) {
processar_fala_string = matches.get(0).toLowerCase().substring(ativar_resultados_parciais_num);
ativar_resultados_parciais_tempo = System.currentTimeMillis();
System.out.println(processar_fala_string);
}
System.out.println(" ");
}
}
}
@Override
public void onReadyForSpeech(Bundle params) {
System.out.println("UUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
a_ouvir=true;
}
@Override
public void onResults(Bundle results) {
onEndOfSpeech_ultimo = false;
reposicao_reconhecimento_google_erro_tempo = 0;
a_ouvir=false;
ArrayList<String> matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
System.out.println("--------------------------");
System.out.println(matches);
System.out.println("--------------------------");
if (matches != null) {
System.out.println("A------------------------A");
System.out.println(matches.get(0).toLowerCase().substring(ativar_resultados_parciais_num));
System.out.println("A------------------------A");
}
ativar_resultados_parciais = false;
if (matches != null) {
if (matches.get(0).toLowerCase().length() - 1 > ativar_resultados_parciais_num amp;amp; !matches.get(0).toLowerCase().equals(fala_processada_total)) {
processar_fala_string = matches.get(0).toLowerCase().substring(ativar_resultados_parciais_num);
if (!processar_fala_string.equals(ultima_fala_processada)) {
System.out.println("whatever 3");
if (contexto == null) {
//System.out.println(getApplicationContext()); --> "getApplicationContext() on a null object reference"
System.out.println(getBaseContext());
System.out.println(this);
System.out.println("null 3");
}
Intent intent = new Intent(ACAO_ENVIAR_TAREFA);
intent.putExtra("extras_frase_str", matches.get(0).toLowerCase().substring(ativar_resultados_parciais_num));
intent.putExtra("extras_resultados_parciais", false);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
}
System.out.println(speechRecognizer);
if (speechRecognizer != null) {
speechRecognizer.stopListening();
speechRecognizer.cancel();
speechRecognizer.destroy();
speechRecognizer = null;
}
Utils_processos.encerrar_pid(Utils_processos.obter_pid_atual());
}
@Override
public void onRmsChanged(float rmsdB) {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
System.out.println("RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR");
if (speechRecognizer != null) {
speechRecognizer.stopListening();
speechRecognizer.cancel();
speechRecognizer.destroy();
speechRecognizer = null;
}
super.onDestroy();
}
}
Я вырезал много частей, которые не имели никакого отношения к проблеме, и оставил только то, что, по моему мнению, связано с проблемой (которая Context
где-то используется).
Когда я запускаю службу нормально, как вы ( startService
или startForeground
— я использую первый, поскольку это на Lollipop), onCreate()
вызывается с некоторым контекстом, который я получаю из this
и onStartCommand()
тоже с тем же this
значением. Это круто. Теперь я не понимаю, почему getApplicationContext()
вызывается какая-то нулевая вещь, когда я вызываю ее из RecognitionListener
методов.
Мои извинения, поскольку я не до конца понимаю Context
материал Android, за исключением того, что он, похоже, связан с процессом. Говоря о процессе, может быть, было бы полезно сказать, что эта служба запущена в отдельном процессе? Предполагается, что он автоматически запускает распознавание, прослушивает материал и сообщает другой запущенной службе выполнить функцию (таким образом, широковещательную передачу). Это отдельный процесс, поэтому я могу отключить распознавание, когда захочу, и мне не нужно ждать, пока он решит остановиться, даже после того, как я сказал ему немедленно остановиться. Таким образом, это действительно останавливается сразу. Но из-за этого я не могу заставить его работать полностью. Он останавливается и прочее, но не возвращает результаты. Это полезно xD.
Ошибка возникает из-за этого метода внутри LocalBroadcastManager
класса:
@NonNull
public static LocalBroadcastManager getInstance(@NonNull Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
Со context.getApplicationContext()
стороны. Вот где ошибка. Я могу передать context
переменную или this
в getInstance()
, но ошибка все равно появится, потому getApplicationContext()
что используется, что, похоже, является проблемой здесь. Интересно, почему это происходит, getApplicationContext()
когда я вызываю его из onResults()
— или, может быть, любого другого метода из RecognitionListener? Это потому, что это не из метода, который является частью Service? Если это причина, есть ли какой-либо способ передачи сообщения в другую службу? Я пытался избежать таких вещей, как SharedPreferences
файлы или.
Кстати, для меня очень странная вещь: «null 3» появляется в logcat, в то время как ни один из других не появляется….. Как это возможно?? Почему переменная изменилась, если я не сказал ей измениться???
РЕДАКТИРОВАТЬ 1: В случае, если это полезно, вот трассировка стека ошибки.
10-25 18:10:44.080 14968-14968/com.dadi590.androidos E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.dadi590.androidos:AndroidOS, PID: 14968
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:106)
at androidx.localbroadcastmanager.content.LocalBroadcastManager.getInstance(LocalBroadcastManager.java:107)
at com.dadi590.androidos.Services.Google_voice_recognition.onResults(Reconhecimento_voz_Google.java:232)
at android.speech.SpeechRecognizer$InternalListener$1.handleMessage(SpeechRecognizer.java:467)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:139)
at android.app.ActivityThread.main(ActivityThread.java:5298)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:950)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:745)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:107)
10-25 18:10:44.087 14968-14968/com.dadi590.androidos D/AppTracker: App Event: crash
10-25 18:10:44.142 14968-14968/com.dadi590.androidos I/Process: Sending signal. PID: 14968 SIG: 9
РЕДАКТИРОВАТЬ 3: START_STICKY , START_STICKY_COMPATIBILITY или START_REDELIVER_INTENT ничего не делают, если это полезно. Все та же ошибка.
Комментарии:
1. Во-первых,
LocalBroadcastManager
он устарел в течение многих лет. Во-вторых, это не работает во всех процессах. В-третьих, вам не нужноgetApplicationContext()
, посколькуService
наследуется отContext
, поэтому вы можете просто использоватьthis
. «в logcat появляется значение «null 3″» — это меня удивляет. Из вашей трассировки стекаcontext
это неnull
так, но это недопустимыйContext
экземпляр. Например,Service
возможно, он был уничтожен к моментуonResults()
вызова.2. 1 — Я узнал, что он устарел несколько минут назад, но все же хотел понять, почему это происходит, поэтому я все же задал вопрос. 2 — Хорошо, тогда я буду использовать обычный вещатель. Кажется, я недостаточно прочитал, чтобы знать, что это только в том же процессе… Спасибо. 3 — Этого я вообще не знал, поскольку это относится к той части, которую я не понимаю
Context
, ха-ха. Тем не менее, полезно знать. 4 — Таким образом, с уничтоженными службами методы все еще могут быть вызваны… Мне действительно нужно больше узнать об Android. Еще раз спасибо за это. Теперь, об этом, я понятия не имею, почему он будет уничтожен. Знаете ли вы причину?3. Кроме того, откуда вы знаете, что контекст не равен нулю из трассировки стека, и это недопустимо? (извините, если это идиотский вопрос)
4. «откуда вы знаете, что контекст не равен нулю из трассировки стека, и это недопустимо?» — верхняя строка «at» в трассировке стека показывает, где произошел сбой. В вашем случае это так
android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:106)
. Это означает, что мы добрались до этой строки кода, а затем потерпели неудачу там. ВашаLocalBroadcastManager.getInstance()
строка следующая. Итак,getInstance()
вызываетсяgetApplicationContext()
для не-null
объекта… но у этого объекта (aContextWrapper
) есть поле, которое былоnull
.5. ОК. Это дополнительно предполагает, что ваша служба была уничтожена к моменту
onResults()
вызова. Я не использовалRecognitionListener
илиSpeechRecognizer
. API выглядит… паршиво. Но, похоже, вам не следует останавливать свою службу, пока вы не вызоветеstopListening()
SpeechRecognizer
.