Java Question Error: java.lang.NullPointerException: Attempt to invoke virtual method...

watesoft

Active Member
Licensed User
Longtime User
This is a Chinese TTS developed with Android studio. I packaged its modules into aar (because it contains so files, it is too large to upload). I refer to DemoActivity.java and use the RunMethod method to test in B4A. There is no problem in calling the "init" method, but an error occurs when calling the "speak" method. I looked at the java class and since I'm not familiar with java, I don't know how to solve the problem. I uploaded the B4A project and java class, hope to get your tips.Thank you in advance.
Test:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
    GetTTS.RunMethod("init", Array(GetContext))
End Sub

Sub Activity_Resume

End Sub

Sub GetTTS As JavaObject
    Dim jo As JavaObject
    Return jo.InitializeNewInstance("com.wzq.ntts.tts.TtsManager",Null).RunMethodJO("getInstance", Null)
End Sub

Sub GetContext As JavaObject
    Return GetBA.GetField("context")
End Sub

Sub GetBA As JavaObject
    Dim jo As JavaObject
    Dim cls As String = Me
    cls = cls.SubString("class ".Length)
    jo.InitializeStatic(cls)
    Return jo.GetFieldJO("processBA")
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Button1_Click
    GetTTS.RunMethodJO("speak", Array("语音合成示例",1.0F,True))
    'GetTTS1.RunMethodJO("stopTts", Null)
End Sub
b4x:
Logger connected to:  HUAWEI BLN-AL30
--------- beginning of main
--------- beginning of system
Copying updated assets files (1)
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Error occurred on line: 39 (Main)
java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:132)
    at anywheresoftware.b4j.object.JavaObject.RunMethodJO(JavaObject.java:139)
    at b4a.example.main._button1_click(main.java:454)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:197)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)
    at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:80)
    at android.view.View.performClick(View.java:6291)
    at android.view.View$PerformClick.run(View.java:24931)
    at android.os.Handler.handleCallback(Handler.java:808)
    at android.os.Handler.dispatchMessage(Handler.java:101)
    at android.os.Looper.loop(Looper.java:166)
    at android.app.ActivityThread.main(ActivityThread.java:7529)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.wzq.ntts.tts.InputWorker.interrupt()' on a null object reference
    at com.wzq.ntts.tts.TtsManager.stopTts(TtsManager.java:87)
    at com.wzq.ntts.tts.TtsManager.speak(TtsManager.java:92)
    ... 22 more
TtsManager.java:
package com.wzq.ntts.tts;

import android.content.Context;
import android.util.Log;

import com.wzq.ntts.dispatcher.TtsStateDispatcher;
import com.wzq.ntts.utils.ThreadPoolManager;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @author {@link "mailto:xuefeng.ding@outlook.com" "Xuefeng Ding"}
 * Created 2020-07-28 14:25
 */

public class TtsManager {
    private static final String TAG = "TtsManager";
    private static final Object INSTANCE_WRITE_LOCK = new Object();

    private static volatile TtsManager instance;

    public static TtsManager getInstance() {
        if (instance == null) {
            System.loadLibrary("tensorflowlite_flex_jni");
            System.loadLibrary("tensorflowlite_jni");
            synchronized (INSTANCE_WRITE_LOCK) {
                if (instance == null) {
                    instance = new TtsManager();
                }
            }
        }
        return instance;
    }

    private InputWorker mWorker;
//    private final static String FASTSPEECH2_MODULE = "fastspeech2_quan.tflite";
    private final static String FASTSPEECH2_MODULE = "fastspeech2_quan.tflite";
    private final static String MELGAN_MODULE = "mb_melgan_new.tflite";

    public void init(Context context) {
        ThreadPoolManager.getInstance().getSingleExecutor("init").execute(() -> {
            try {
                String fastspeech = copyFile(context, FASTSPEECH2_MODULE);
                String vocoder = copyFile(context, MELGAN_MODULE);
                mWorker = new InputWorker(context,fastspeech, vocoder);
            } catch (Exception e) {
                Log.e(TAG, "mWorker init failed", e);
            }
            TtsStateDispatcher.getInstance().onTtsReady();
        });
    }

    private String copyFile(Context context, String strOutFileName) {
        Log.d(TAG, "start copy file " + strOutFileName);
        File file = context.getFilesDir();

        String tmpFile = file.getAbsolutePath() + "/" + strOutFileName;
        File f = new File(tmpFile);
        if (f.exists()) {
            Log.d(TAG, "file exists " + strOutFileName);
            return f.getAbsolutePath();
        }

        try (OutputStream myOutput = new FileOutputStream(f);
             InputStream myInput = context.getAssets().open(strOutFileName)) {
            byte[] buffer = new byte[1024];
            int length = myInput.read(buffer);
            while (length > 0) {
                myOutput.write(buffer, 0, length);
                length = myInput.read(buffer);
            }
            myOutput.flush();
            Log.d(TAG, "Copy task successful");
        } catch (Exception e) {
            Log.e(TAG, "copyFile: Failed to copy", e);
        } finally {
            Log.d(TAG, "end copy file " + strOutFileName);
        }
        return f.getAbsolutePath();
    }

    public void stopTts() {
        mWorker.interrupt();
    }

    public void speak(String inputText, float speed, boolean interrupt) {
        if (interrupt) {
            stopTts();
        }

        ThreadPoolManager.getInstance().execute(() ->
                mWorker.processInput(inputText, speed));
    }

}
InputWorker.java:
package com.wzq.ntts.tts;

import android.content.Context;
import android.util.Log;

import com.wzq.ntts.dispatcher.TtsStateDispatcher;
import com.wzq.ntts.module.FastSpeech2;
import com.wzq.ntts.module.MBMelGan;
import com.wzq.ntts.utils.Processor;
import com.wzq.ntts.utils.ThreadPoolManager;
import com.wzq.ntts.utils.ZhProcessor;

import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;

import java.util.Arrays;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @author {@link "mailto:xuefeng.ding@outlook.com" "Xuefeng Ding"}
 * Created 2020-07-28 14:25
 */
class InputWorker {
    private static final String TAG = "InputWorker";

    private LinkedBlockingQueue<InputText> mInputQueue = new LinkedBlockingQueue<>();
    private InputText mCurrentInputText;
    private FastSpeech2 mFastSpeech2;
    private MBMelGan mMBMelGan;
    private Processor mProcessor;
    private TtsPlayer mTtsPlayer;
    private ZhProcessor zhProcessor;
    private Context context;

    InputWorker(Context context, String fastspeech, String vocoder) {
        this.context = context;
        mFastSpeech2 = new FastSpeech2(fastspeech);
        mMBMelGan = new MBMelGan(vocoder);
        mProcessor = new Processor();
        mTtsPlayer = new TtsPlayer();
        zhProcessor = new ZhProcessor(context);

        ThreadPoolManager.getInstance().getSingleExecutor("worker").execute(() -> {
            //noinspection InfiniteLoopStatement
            while (true) {
                try {
                    mCurrentInputText = mInputQueue.take();
                    Log.d(TAG, "processing: " + mCurrentInputText.INPUT_TEXT);
                    TtsStateDispatcher.getInstance().onTtsStart(mCurrentInputText.INPUT_TEXT);
                    mCurrentInputText.proceed();
                    TtsStateDispatcher.getInstance().onTtsStop();
                } catch (Exception e) {
                    Log.e(TAG, "Exception: ", e);
                }
            }
        });
    }

    void processInput(String inputText, float speed) {
        Log.d(TAG, "add to queue: " + inputText);
        mInputQueue.offer(new InputText(inputText, speed));
    }

    void interrupt() {
        mInputQueue.clear();
        if (mCurrentInputText != null) {
            mCurrentInputText.interrupt();
        }
        mTtsPlayer.interrupt();
    }


    private class InputText {
        private final String INPUT_TEXT;
        private final float SPEED;
        private boolean isInterrupt;

        private InputText(String inputText, float speed) {
            this.INPUT_TEXT = inputText;
            this.SPEED = speed;
        }

        private void proceed() {
            String[] sentences = INPUT_TEXT.split("[\n,。??!!,;;]");
            Log.d(TAG, "speak: " + Arrays.toString(sentences));

            for (String sentence : sentences) {

                long time = System.currentTimeMillis();

//                int[] inputIds = mProcessor.textToIds(sentence);
                int[] inputIds = zhProcessor.text2ids(sentence);
                TensorBuffer output = mFastSpeech2.getMelSpectrogram(inputIds, SPEED);

                if (isInterrupt) {
                    Log.d(TAG, "proceed: interrupt");
                    return;
                }

                long encoderTime = System.currentTimeMillis();

                float[] audioData;
                try {
                    audioData = mMBMelGan.getAudio(output);
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }

                if (isInterrupt) {
                    Log.d(TAG, "proceed: interrupt");
                    return;
                }

                long vocoderTime = System.currentTimeMillis();

                Log.d(TAG, "Time cost: " + (encoderTime - time) + "+" + (vocoderTime - encoderTime) + "=" + (vocoderTime - time));

                mTtsPlayer.play(new TtsPlayer.AudioData(sentence, audioData));
            }
        }

        private void interrupt() {
            this.isInterrupt = true;
        }
    }

}
DemoActivity.java:
package com.air4.ttschineseDemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioGroup;

import com.air4.chinesetts.dispatcher.OnTtsStateListener;
import com.air4.chinesetts.dispatcher.TtsStateDispatcher;
import com.air4.chinesetts.tts.TtsManager;
import com.air4.chinesetts.utils.ThreadPoolManager;

public class DemoActivity extends AppCompatActivity {
    private static final String DEFAULT_INPUT_TEXT = "君不见,黄河之水天上来,奔流到海不复回,君不见,高堂明镜悲白发,朝如青丝暮成雪,人生得意须尽欢,莫使金樽空对月";
    private View speakBtn;
    private RadioGroup speedGroup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ttsdemo);

        TtsManager.getInstance().init(this);

        TtsStateDispatcher.getInstance().addListener(new OnTtsStateListener() {
            @Override
            public void onTtsReady() {
                speakBtn.setEnabled(true);
            }

            @Override
            public void onTtsStart(String text) {
            }

            @Override
            public void onTtsStop() {
            }
        });

        EditText input = findViewById(R.id.input);
        input.setHint(DEFAULT_INPUT_TEXT);

        speedGroup = findViewById(R.id.speed_chooser);
        speedGroup.check(R.id.normal);

        speakBtn = findViewById(R.id.start);
        speakBtn.setEnabled(false);
        speakBtn.setOnClickListener(v ->
                ThreadPoolManager.getInstance().execute(() -> {
                    float speed;
                    switch (speedGroup.getCheckedRadioButtonId()) {
                        case R.id.fast:
                            speed = 0.8F;
                            break;
                        case R.id.slow:
                            speed = 1.2F;
                            break;
                        case R.id.normal:
                        default:
                            speed = 1.0F;
                            break;
                    }

                    String inputText = input.getText().toString();
                    if (TextUtils.isEmpty(inputText)) {
                        inputText = DEFAULT_INPUT_TEXT;
                    }
                    TtsManager.getInstance().speak(inputText, speed, true);
                }));

        findViewById(R.id.stop).setOnClickListener(v ->
                TtsManager.getInstance().stopTts());
    }
}
 

Attachments

  • CN_TTS.zip
    9.2 KB · Views: 233
  • com.zip
    18.1 KB · Views: 241
Last edited:

watesoft

Active Member
Licensed User
Longtime User
This is a Chinese TTS developed with Android studio. I packaged its modules into aar (because it contains so files, it is too large to upload). I refer to DemoActivity.java and use the RunMethod method to test in B4A. There is no problem in calling the "init" method, but an error occurs when calling the "speak" method. I looked at the java class and since I'm not familiar with java, I don't know how to solve the problem. I uploaded the B4A project and java class, hope to get your tips.Thank you in advance.
Test:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
    GetTTS.RunMethod("init", Array(GetContext))
End Sub

Sub Activity_Resume

End Sub

Sub GetTTS As JavaObject
    Dim jo As JavaObject
    Return jo.InitializeNewInstance("com.wzq.ntts.tts.TtsManager",Null).RunMethodJO("getInstance", Null)
End Sub

Sub GetContext As JavaObject
    Return GetBA.GetField("context")
End Sub

Sub GetBA As JavaObject
    Dim jo As JavaObject
    Dim cls As String = Me
    cls = cls.SubString("class ".Length)
    jo.InitializeStatic(cls)
    Return jo.GetFieldJO("processBA")
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Button1_Click
    GetTTS.RunMethodJO("speak", Array("语音合成示例",1.0F,True))
    'GetTTS1.RunMethodJO("stopTts", Null)
End Sub
b4x:
Logger connected to:  HUAWEI BLN-AL30
--------- beginning of main
--------- beginning of system
Copying updated assets files (1)
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Error occurred on line: 39 (Main)
java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:132)
    at anywheresoftware.b4j.object.JavaObject.RunMethodJO(JavaObject.java:139)
    at b4a.example.main._button1_click(main.java:454)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:197)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)
    at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:80)
    at android.view.View.performClick(View.java:6291)
    at android.view.View$PerformClick.run(View.java:24931)
    at android.os.Handler.handleCallback(Handler.java:808)
    at android.os.Handler.dispatchMessage(Handler.java:101)
    at android.os.Looper.loop(Looper.java:166)
    at android.app.ActivityThread.main(ActivityThread.java:7529)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.wzq.ntts.tts.InputWorker.interrupt()' on a null object reference
    at com.wzq.ntts.tts.TtsManager.stopTts(TtsManager.java:87)
    at com.wzq.ntts.tts.TtsManager.speak(TtsManager.java:92)
    ... 22 more
TtsManager.java:
package com.wzq.ntts.tts;

import android.content.Context;
import android.util.Log;

import com.wzq.ntts.dispatcher.TtsStateDispatcher;
import com.wzq.ntts.utils.ThreadPoolManager;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @author {@link "mailto:xuefeng.ding@outlook.com" "Xuefeng Ding"}
 * Created 2020-07-28 14:25
 */

public class TtsManager {
    private static final String TAG = "TtsManager";
    private static final Object INSTANCE_WRITE_LOCK = new Object();

    private static volatile TtsManager instance;

    public static TtsManager getInstance() {
        if (instance == null) {
            System.loadLibrary("tensorflowlite_flex_jni");
            System.loadLibrary("tensorflowlite_jni");
            synchronized (INSTANCE_WRITE_LOCK) {
                if (instance == null) {
                    instance = new TtsManager();
                }
            }
        }
        return instance;
    }

    private InputWorker mWorker;
//    private final static String FASTSPEECH2_MODULE = "fastspeech2_quan.tflite";
    private final static String FASTSPEECH2_MODULE = "fastspeech2_quan.tflite";
    private final static String MELGAN_MODULE = "mb_melgan_new.tflite";

    public void init(Context context) {
        ThreadPoolManager.getInstance().getSingleExecutor("init").execute(() -> {
            try {
                String fastspeech = copyFile(context, FASTSPEECH2_MODULE);
                String vocoder = copyFile(context, MELGAN_MODULE);
                mWorker = new InputWorker(context,fastspeech, vocoder);
            } catch (Exception e) {
                Log.e(TAG, "mWorker init failed", e);
            }
            TtsStateDispatcher.getInstance().onTtsReady();
        });
    }

    private String copyFile(Context context, String strOutFileName) {
        Log.d(TAG, "start copy file " + strOutFileName);
        File file = context.getFilesDir();

        String tmpFile = file.getAbsolutePath() + "/" + strOutFileName;
        File f = new File(tmpFile);
        if (f.exists()) {
            Log.d(TAG, "file exists " + strOutFileName);
            return f.getAbsolutePath();
        }

        try (OutputStream myOutput = new FileOutputStream(f);
             InputStream myInput = context.getAssets().open(strOutFileName)) {
            byte[] buffer = new byte[1024];
            int length = myInput.read(buffer);
            while (length > 0) {
                myOutput.write(buffer, 0, length);
                length = myInput.read(buffer);
            }
            myOutput.flush();
            Log.d(TAG, "Copy task successful");
        } catch (Exception e) {
            Log.e(TAG, "copyFile: Failed to copy", e);
        } finally {
            Log.d(TAG, "end copy file " + strOutFileName);
        }
        return f.getAbsolutePath();
    }

    public void stopTts() {
        mWorker.interrupt();
    }

    public void speak(String inputText, float speed, boolean interrupt) {
        if (interrupt) {
            stopTts();
        }

        ThreadPoolManager.getInstance().execute(() ->
                mWorker.processInput(inputText, speed));
    }

}
InputWorker.java:
package com.wzq.ntts.tts;

import android.content.Context;
import android.util.Log;

import com.wzq.ntts.dispatcher.TtsStateDispatcher;
import com.wzq.ntts.module.FastSpeech2;
import com.wzq.ntts.module.MBMelGan;
import com.wzq.ntts.utils.Processor;
import com.wzq.ntts.utils.ThreadPoolManager;
import com.wzq.ntts.utils.ZhProcessor;

import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;

import java.util.Arrays;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @author {@link "mailto:xuefeng.ding@outlook.com" "Xuefeng Ding"}
 * Created 2020-07-28 14:25
 */
class InputWorker {
    private static final String TAG = "InputWorker";

    private LinkedBlockingQueue<InputText> mInputQueue = new LinkedBlockingQueue<>();
    private InputText mCurrentInputText;
    private FastSpeech2 mFastSpeech2;
    private MBMelGan mMBMelGan;
    private Processor mProcessor;
    private TtsPlayer mTtsPlayer;
    private ZhProcessor zhProcessor;
    private Context context;

    InputWorker(Context context, String fastspeech, String vocoder) {
        this.context = context;
        mFastSpeech2 = new FastSpeech2(fastspeech);
        mMBMelGan = new MBMelGan(vocoder);
        mProcessor = new Processor();
        mTtsPlayer = new TtsPlayer();
        zhProcessor = new ZhProcessor(context);

        ThreadPoolManager.getInstance().getSingleExecutor("worker").execute(() -> {
            //noinspection InfiniteLoopStatement
            while (true) {
                try {
                    mCurrentInputText = mInputQueue.take();
                    Log.d(TAG, "processing: " + mCurrentInputText.INPUT_TEXT);
                    TtsStateDispatcher.getInstance().onTtsStart(mCurrentInputText.INPUT_TEXT);
                    mCurrentInputText.proceed();
                    TtsStateDispatcher.getInstance().onTtsStop();
                } catch (Exception e) {
                    Log.e(TAG, "Exception: ", e);
                }
            }
        });
    }

    void processInput(String inputText, float speed) {
        Log.d(TAG, "add to queue: " + inputText);
        mInputQueue.offer(new InputText(inputText, speed));
    }

    void interrupt() {
        mInputQueue.clear();
        if (mCurrentInputText != null) {
            mCurrentInputText.interrupt();
        }
        mTtsPlayer.interrupt();
    }


    private class InputText {
        private final String INPUT_TEXT;
        private final float SPEED;
        private boolean isInterrupt;

        private InputText(String inputText, float speed) {
            this.INPUT_TEXT = inputText;
            this.SPEED = speed;
        }

        private void proceed() {
            String[] sentences = INPUT_TEXT.split("[\n,。??!!,;;]");
            Log.d(TAG, "speak: " + Arrays.toString(sentences));

            for (String sentence : sentences) {

                long time = System.currentTimeMillis();

//                int[] inputIds = mProcessor.textToIds(sentence);
                int[] inputIds = zhProcessor.text2ids(sentence);
                TensorBuffer output = mFastSpeech2.getMelSpectrogram(inputIds, SPEED);

                if (isInterrupt) {
                    Log.d(TAG, "proceed: interrupt");
                    return;
                }

                long encoderTime = System.currentTimeMillis();

                float[] audioData;
                try {
                    audioData = mMBMelGan.getAudio(output);
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }

                if (isInterrupt) {
                    Log.d(TAG, "proceed: interrupt");
                    return;
                }

                long vocoderTime = System.currentTimeMillis();

                Log.d(TAG, "Time cost: " + (encoderTime - time) + "+" + (vocoderTime - encoderTime) + "=" + (vocoderTime - time));

                mTtsPlayer.play(new TtsPlayer.AudioData(sentence, audioData));
            }
        }

        private void interrupt() {
            this.isInterrupt = true;
        }
    }

}
DemoActivity.java:
package com.air4.ttschineseDemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioGroup;

import com.air4.chinesetts.dispatcher.OnTtsStateListener;
import com.air4.chinesetts.dispatcher.TtsStateDispatcher;
import com.air4.chinesetts.tts.TtsManager;
import com.air4.chinesetts.utils.ThreadPoolManager;

public class DemoActivity extends AppCompatActivity {
    private static final String DEFAULT_INPUT_TEXT = "君不见,黄河之水天上来,奔流到海不复回,君不见,高堂明镜悲白发,朝如青丝暮成雪,人生得意须尽欢,莫使金樽空对月";
    private View speakBtn;
    private RadioGroup speedGroup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ttsdemo);

        TtsManager.getInstance().init(this);

        TtsStateDispatcher.getInstance().addListener(new OnTtsStateListener() {
            @Override
            public void onTtsReady() {
                speakBtn.setEnabled(true);
            }

            @Override
            public void onTtsStart(String text) {
            }

            @Override
            public void onTtsStop() {
            }
        });

        EditText input = findViewById(R.id.input);
        input.setHint(DEFAULT_INPUT_TEXT);

        speedGroup = findViewById(R.id.speed_chooser);
        speedGroup.check(R.id.normal);

        speakBtn = findViewById(R.id.start);
        speakBtn.setEnabled(false);
        speakBtn.setOnClickListener(v ->
                ThreadPoolManager.getInstance().execute(() -> {
                    float speed;
                    switch (speedGroup.getCheckedRadioButtonId()) {
                        case R.id.fast:
                            speed = 0.8F;
                            break;
                        case R.id.slow:
                            speed = 1.2F;
                            break;
                        case R.id.normal:
                        default:
                            speed = 1.0F;
                            break;
                    }

                    String inputText = input.getText().toString();
                    if (TextUtils.isEmpty(inputText)) {
                        inputText = DEFAULT_INPUT_TEXT;
                    }
                    TtsManager.getInstance().speak(inputText, speed, true);
                }));

        findViewById(R.id.stop).setOnClickListener(v ->
                TtsManager.getInstance().stopTts());
    }
}

The problem has been solved, java cannot directly access so, you need to create a Java native interface.
 
Top