getApplicationContext() для ссылки на нулевой объект в службе, которая реализует RecognitionListener

#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 объекта… но у этого объекта (a ContextWrapper ) есть поле, которое было null .

5. ОК. Это дополнительно предполагает, что ваша служба была уничтожена к моменту onResults() вызова. Я не использовал RecognitionListener или SpeechRecognizer . API выглядит… паршиво. Но, похоже, вам не следует останавливать свою службу, пока вы не вызовете stopListening() SpeechRecognizer .