CountDownTimer использует обработчик для отправки сообщений в очередь сообщений потока, который имеет Looper. onTick
и onFinish
будут вызываться в каком потоке в зависимости от того, где вы создали экземпляр CountDownTimer.
В вашем случае, потому что вы создаете экземпляр CountDownTimer в doInBackground
методе AsyncTask, поэтому эти два метода будут вызываться в потоке AsyncTask.
В конструкторе CountDownTimer он также создаст экземпляр обработчика. Обработчик проверит, имеет ли текущий поток Looper, если нет, он выдаст исключение RuntimeException с сообщением.
Невозможно создать обработчик внутри потока, который не вызвал
Looper.prepare ()
Поскольку AsyncTask использует поток, в котором нет Looper, именно поэтому ваше приложение вылетает.
Мое предложение заключается в методе doInBackground
, когда вы открываете соединение с файлом .lrc и читаете каждую строку, для каждой прочитанной строки используйте runOnUIThread
, чтобы отправить строку в поток пользовательского интерфейса (тогда вы можете обработать строку, прочитанную там, отображение тоста на экране и т. д.).
Обновление: Я продемонстрирую, как читать строку за строкой из файла, а затем отображать его в текстовом представлении каждые 3 секунды.
Сначала напишите класс, который читает строку входного потока строка за строкой
static class ReadLyricTask extends AsyncTask<InputStream, String, Void> {
WeakReference<MainActivity> mMainActivity;
ReadLyricTask(MainActivity activity) {
mMainActivity = new WeakReference<>(activity);
}
@Override
protected Void doInBackground(InputStream... inputStreams) {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStreams[0]));
String line;
try {
while ((line = reader.readLine()) != null) {
publishProgress(line);
}
} catch (IOException e) {
// Do nothing.
} finally {
try {
inputStreams[0].close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
MainActivity activity = mMainActivity.get();
if (activity != null) {
activity.displayLyricLineOnTextView(values[0]);
}
}
}
Тогда просто используйте его в MainActivity
public class MainActivity extends AppCompatActivity {
private static final int UPDATE_LYRIC_TEXT_INTERVAL = 3000; // Change lyric text each 3 seconds.
private int mCurrentInterval = 0;
private TextView mLyricTextView;
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLyricTextView = findViewById(R.id.lyricText);
// I put a file named lyric.lrc in raw folder, for your case just open an input stream from a file.
InputStream inputStream = getResources().openRawResource(R.raw.lyric);
new ReadLyricTask(this).execute(inputStream);
}
private void displayLyricLineOnTextView(final String lyricLine) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mLyricTextView.setText(lyricLine);
}
}, mCurrentInterval);
mCurrentInterval += UPDATE_LYRIC_TEXT_INTERVAL;
}
}