Ну, я не знаю, будет ли мой ответ решить ваш вопрос, но несколько дней назад у меня была проблема, скорее всего, ваша, но в моем случае использовалась база данных Firebase в реальном времени.Я спрашивал себя, как я могу защитить свое приложение от сетевых сбоев, как, например, отсутствие доступа к интернету?Ну, я тоже не использую пакет подключения, поэтому я решаю эту проблему с помощью подхода, который вы уже пробовали использовать тайм-аут для сетевых операций.Я поделюсь двумя фрагментами с различными подходами, которые я реализовал для решения этой проблемы, добавив некоторые комментарии, пытаясь объяснить различия между ними.
Подход 1. Установка времени ожидания вне метода сетевого запроса
Итак, приведенный ниже фрагмент кода представляет собой простой запрос к базе данных Firebase, где _viewsRef
- это ссылка на базу данных, а метод once
выполняет запрос и возвращает мне будущее с данными или без данных.
// get users visualization from realtime database and returns a future
static Future<DataSnapshot> getUserVisualizations({@required String uid}) async {
return _viewsRef.child(uid).limitToLast(50).once();
}
В моем классе компонентов BLoC я вызываю метод ниже и устанавливаю тайм-аут на будущее, которое возвращается.
myBlocComponentMethod(){
//.. some work and finally the call
FirebaseUserViewsHelper.getUserVisualizations(uid: _currentUid)
.then(
(dataSnapshot){
if (dataSnapshot.value == null) {
// do some things to handle no data
}
else {
/// handle your data here
});
}
} // setting timeout here is an important point
).timeout( Duration(seconds: Constants.NETWORK_TIMEOUT_SECONDS),
onTimeout: (){
// method to handle a timeout exception and tell to view layer that
// network operation fails
// if we do not implement onTimeout callback the framework will throw a TimeoutException
} );
}
Хорошо, какой здесь смысл?В этом случае, если тайм-аут истекает, а будущее еще не завершено, вызывается обратный вызов onTimeout, и там я могу сообщить слою представления, что работа сети не удалась, и показать пользователю некоторый виджет об этом.Но даже по истечении времени ожидания запрос к базе данных firebase продолжает повторяться снова и снова, это похоже на асинхронное событие запроса, которое база данных остается в очереди событий dart.Я думаю, что это плохое поведение с точки зрения производительности, но если вы создаете свой пользовательский интерфейс с использованием StreamBuilder с небольшим количеством логики и кода, то ваши запрошенные данные будут доступны сразу же после подключения к Интернету, и с шаблоном BLoC пользовательский интерфейс может легко реагировать на это.событие, и нам не нужно предоставлять кнопку обновления в качестве примера, чтобы пользователь сделал запрос снова.Я не знаю, является ли это правильным подходом для реализации этого поведения, но оно работает.
Подход 2 - Установка таймаута внутри из метода сетевого запроса
Под другой пожарной базойметод запроса базы данных
static Future<DataSnapshot> readUserNode( {@required String uid} ) async
=> USERS_REFERENCE.child(uid).once()
.timeout( Duration(seconds: Constants.NETWORK_TIMEOUT_SECONDS ) );
//note: Without timeout callback this line will throw a TimeoutException if the time expires
Использование в другом компоненте BLoc:
myBlocComponentMethod2(){
for( String uid in iterable ){
FirebaseUserHelper.readUserNode(uid: uid)
.then( (userSnapshot){
if (userSnapshot.value == null){
// do your stuffs
}
else {
// more stuffs to do
}
}).catchError( (error){
// when timeout expired we will catch the TimeoutException HERE and handling telling
// the UI what we need
} );
}
}
Большая разница, которую я получил, заключалась в поведении.Во втором случае, так как я поместил тайм-аут в метод запроса, когда тайм-аут истекает, событие запроса больше не запускается, это похоже на то, что событие запроса было удалено из очереди событий dart.Это может быть полезно с точки зрения производительности, но теперь нам нужно предоставить кнопку обновления в пользовательском интерфейсе, чтобы пользователь снова мог выполнять данные, чтобы снова получать данные из Интернета.
Я не знаю, разрешит ли этот обходной путь вашу проблему, потому что вы рассказываете о SocketException, а не тот случай, который я описал, и я не знаю, какой API вы используете для выполнения ваших запросов.В любом случае, я надеюсь, что концепции, описанные в этом посте, помогут вам реализовать решение вашей проблемы.