Недавно я начал программировать для Android и пытаюсь узнать, какие языки преобразования текста в речь доступны на устройстве, и отобразить их в счетчике, но я столкнулся с действительно странной проблемой.
Вот соответствующая часть кода:
package com.example.dshawn.ttsapp;
import android.speech.tts.TextToSpeech;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;
import java.util.*;
public class MainActivity extends AppCompatActivity implements
AdapterView.OnItemSelectedListener {
private TextToSpeech mTTS;
Locale[] locales = Locale.getAvailableLocales();
List<Locale> localeList = new ArrayList<Locale>();
List<String> country= new ArrayList<String>();
List<String> asdf= new ArrayList<String>();
int sum=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTTS = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int i) {
if (i==TextToSpeech.SUCCESS){
for (Locale locale : locales) {
int res = mTTS.isLanguageAvailable(locale);
if (res == TextToSpeech.LANG_COUNTRY_AVAILABLE) {
sum++;
localeList.add(locale);
country.add(locale.getDisplayName());
}
}
asdf.add(Integer.toString(sum));
}
}
});
//Getting the instance of Spinner and applying OnItemSelectedListener on it
Spinner spin = (Spinner) findViewById(R.id.spinner);
spin.setOnItemSelectedListener(this);
//Creating the ArrayAdapter instance having the country list
ArrayAdapter<String> aa = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,country);
aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//Setting the ArrayAdapter data on the Spinner
spin.setAdapter(aa);
}
//Performing action onItemSelected and onNothing selected
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
Toast.makeText(getApplicationContext(),country.get(position) , Toast.LENGTH_LONG).show();
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}
После этой инициализации TTS я пытаюсь вывести сумму, она показывает 0. Я пытаюсь получить доступ к элементам в localeList и стране, выполняя что-то вроде String = country.get (1); и компилятор выдаст ошибку о том, что индекс, к которому я пытаюсь получить доступ, не существует и в списке 0 элементов. Итак, на данный момент кажется, что на устройстве, вероятно, нет доступных языков, но странно то, что когда я помещаю ArrayList страны в раскрывающееся меню счетчика через ArrayAdapter, фактические доступные страны на моем устройстве отображаются в счетчике меню, но оно сломано, вот гифка того, что я имею в виду:
Счетчик никогда не попадает в мой прослушиватель onItemSelected, и элемент не отображается в счетчике после щелчка по нему. Я вошел в настройки устройства, и те, которые появились, действительно являются доступными языками для TTS на этом устройстве. и когда я удаляю часть кода «if (res == TextToSpeech.LANG_COUNTRY_AVAILABLE)», которая, похоже, никогда не будет доступна, в раскрывающемся меню счетчика ничего не будет. Таким образом, он явно каким-то образом захватывает доступные локали, но когда я пытался получить доступ к arraylist, он действовал так, как будто он был пуст, но каким-то образом он использует этот «пустой» Arraylist и получает правильные страны в поле счетчика, но блок счетчика сломан, предположительно, потому что ArrayList не работает, потому что я пробовал то же самое с ArrayList, который заполняю вручную, и элементы отображаются нормально, и я могу выбрать его в обычном режиме.
В чем может быть проблема? Я перепробовал все, что мог придумать, все, что я знаю, это проблема в части инициализации TTS.
В основном я не могу получить доступ ни к одному из элементов, которые были установлены или добавлены в методе onInit для TTS, что также приводит к поломке моего счетчика.
Я добавил полный код, но не знаю, поможет ли это.




Куда вы звоните String=country.get(1);? Поскольку это обратный вызов, вы не узнаете, когда он будет вызван. Если вы поместите код внутри onInit после блока операторов if, вы увидите значение?
Кажется, что я могу получить доступ к значениям в onInit, я снова попытался отобразить сумму, и она показывает 7 при доступе изнутри метода onInit. Но я не могу переместить свой счетчик в onInit, потому что мой ArrayAdapter не может быть применен внутри метода onInit. есть ли способ сохранить значения после onInit?
Да, сейчас было бы отличное время использовать Rx, создав поток и разместив значения в потоке, когда onInit завершится, а затем подписаться на onResume (не забудьте удалить в onPause или использовать Autodispose от Uber). Другой вариант - иметь класс слушателя и вызывать слушателя, который обновляет счетчик (слушатель может быть реализован действием, или вы можете спроектировать его так, чтобы он был более тестируемым с чистым классом java)
Я думаю, проблема заключалась в том, что вы создавали адаптер (используя список стран) до того, как список был заполнен (потому что TTS еще не был инициализирован).
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
private TextToSpeech mTTS;
Locale[] locales = Locale.getAvailableLocales();
List<Locale> localeList = new ArrayList<Locale>();
List<String> country = new ArrayList<String>();
// * - Move these two variables out here
ArrayAdapter<String> aa;
Spinner spin;
int sum = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i("XXX", "onCreate() was called");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTTS = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int i) {
if (i == TextToSpeech.SUCCESS) {
// * - delay important tasks until TTS is initialized
startWhenTTSIsInitialized();
}
}
});
//Getting the instance of Spinner and applying OnItemSelectedListener on it
spin = (Spinner) findViewById(R.id.spinner);
}
private void startWhenTTSIsInitialized() {
Log.i("XXX", "startWhenTTSIsInitialized() was called");
for (Locale locale : locales) {
int res = mTTS.isLanguageAvailable(locale);
if (res == TextToSpeech.LANG_COUNTRY_AVAILABLE) {
sum++;
localeList.add(locale);
// * - 'country' is used to populate the adapter, so
// this line must come first
country.add(locale.getDisplayName());
}
}
//Creating the ArrayAdapter instance having the country list
// * - now it's safe to set the adapter because the country list has been populated
aa = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, country);
aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//Setting the ArrayAdapter data on the Spinner
spin.setAdapter(aa);
spin.setOnItemSelectedListener(this);
}
//Performing action onItemSelected and onNothing selected
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
Log.i("XXX", "onItemSelected() was called");
Toast.makeText(getApplicationContext(), country.get(position), Toast.LENGTH_LONG).show();
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}
Я могу привести пример кода, который делает то, что вы пытаетесь сделать, но если вы хотите знать, почему ваш подход не работает, вам нужно опубликовать все действие.