Search code examples
androidandroid-fragmentstext-to-speechandroid-viewmodelgoogle-text-to-speech

why tts isn't changing the languge in Android Fragment but works fine in Activity?


So I have been trying to change the TTS language inside a fragment but it isn't working but same code works fine inside MainActivity. I don't understand why. I have checked other solutions but none worked for me. I have tried different solution , solution but even this isn't working.

public class HomeFragment extends Fragment  implements TextToSpeech.OnInitListener{
    private static final int TTS_DATA_CHECK = 1;
    private TextToSpeech engine;
    private SettingsViewModel settingsViewModel;
    private EditText textMsg;
    private Button button;

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        engine = new TextToSpeech(getContext(),this);
        settingsViewModel = new ViewModelProvider(getActivity()).get(SettingsViewModel.class);
        return inflater.inflate(R.layout.fragment_home, container, false);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        textMsg = view.findViewById(R.id.textMsg);
        button = view.findViewById(R.id.playButton);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                engine.speak(textMsg.getText().toString(), TextToSpeech.QUEUE_FLUSH, null,null);
            }
        });
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        settingsViewModel.getLanguage().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.d("LANGUAGE_SELECTED",s);
                switch (s){
                    case "ENGLISH":
                        engine.setLanguage(Locale.ENGLISH);
                        break;
                    case "FRENCH":
                        engine.setLanguage(Locale.FRENCH);
                        break;
                }
            }
        });
    }

    @Override
    public void onInit(int status) {
        if(status==TextToSpeech.SUCCESS){
            int result = engine.setLanguage(Locale.ENGLISH);
            if(result == TextToSpeech.LANG_MISSING_DATA
                    || result== TextToSpeech.LANG_NOT_SUPPORTED){
                Toast.makeText(getContext(),"Not supported",Toast.LENGTH_LONG).show();
            }
        }else{
            Toast.makeText(getContext(),"TTS is missing",Toast.LENGTH_LONG).show();
        }
    }

}

Solution

  • First you need to initialize TTS in main activity like this -

    public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {
     
        private static final int TTS_DATA_CHECK = 101;
        static TextToSpeech engine;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            engine = new TextToSpeech(this,this);
        }
    
        
        @Override
        public final void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == 101)
            {
                if (resultCode != TextToSpeech.Engine.CHECK_VOICE_DATA_PASS)
                {
                    final Intent tnt = new Intent(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
                    startActivity(tnt);
                }
            }
        }
    
        @Override
        public void onInit(int status) {
            if(status==TextToSpeech.SUCCESS){
                if(TTS_DATA_CHECK == TextToSpeech.LANG_MISSING_DATA
                  || TTS_DATA_CHECK== TextToSpeech.LANG_NOT_SUPPORTED){
                    Toast.makeText(this,"Not supported",Toast.LENGTH_LONG).show();
                }
            }
        }
    
        static public TextToSpeech getInstance() {
            return engine;
        }
    
    }
    

    Then you have to call the TTS instance inside Fragment like this. Note that, MainActivity is the parent activity of the given Fragment.

    Now replace the following code in your Fragment with this code -

    @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            Log.d("VMA","OnActivityCreated");
            settingsViewModel.getLanguage().observe(getViewLifecycleOwner(), new Observer<String>() {
                @Override
                public void onChanged(String s) {
                    Log.d("VMA","LANGUAGE_SELECTED " + s);
                    switch (s){
                        case "FRENCH":
                            MainActivity.getInstance().setLanguage(Locale.FRENCH);
                            break;
                        case "ENGLISH":
                            MainActivity.getInstance().setLanguage(Locale.ENGLISH);
                            break;
                    }
                }
            });
        }  
    

    Also, you can remove the rest of the TTS code from Fragment. You don't that anymore.