Лучшая практика для клиента android для связи с сервером с помощью потоков

Я создаю приложение для Android, которое регулярно связывается с сервером, пока приложение работает.

Я делаю это, инициируя подключение к серверу при запуске приложения, тогда у меня есть отдельный thread для получения сообщений с именем ReceiverThread, этот thread читает сообщение из socket, анализирует его, и пересылает его в соответствующую часть приложения.

Этот thread работает в цикле, считывая все, что ему нужно прочитать, а затем блокирует команду read() до тех пор, пока не появятся новые данные, поэтому он тратит большую часть времени на блокировку.

Я обрабатываю отправку сообщений через другой поток, называемый SenderThread. Мне интересно, должен ли я структурировать SenderThread аналогичным образом? Смысл должен ли я поддерживать некоторую форму очереди для этого потока, пусть он отправляет все сообщения в очереди, а затем блокирует до тех пор, пока в очередь не войдут новые сообщения, или я должен просто начать новый экземпляр потока каждый раз, когда сообщение нужно отправить, пусть он отправит сообщение, а затем "умрет"? Я склоняюсь к первому подходу, но я не знаю, что на самом деле лучше как с точки зрения производительности (сохранение заблокированного потока в памяти и инициализация новых потоков), так и с точки зрения правильности кода.

Кроме того, поскольку все мои действия должны иметь возможность отправлять и получать сообщения, я держу ссылку на оба потока в классе Application, является ли приемлемый подход или я должен реализовать его по-другому?

Одна из проблем, с которыми я столкнулся, заключается в том, что иногда, если я закрываю приложение и запускаю его снова, у меня на самом деле есть два экземпляра ReceiverThread, поэтому я получаю несколько сообщений дважды.

Я предполагаю, что это потому, что мое приложение фактически не закрывалось, и предыдущий поток все еще был активным (заблокирован в операции read()), и когда я снова открыл приложение, новый поток был инициализирован, но оба были связаны на сервер, чтобы сервер отправил сообщение обоим. Любые советы о том, как обойти эту проблему или о том, как полностью переорганизовать ее, чтобы она была правильной?

Я попытался найти эти вопросы, но нашел некоторые противоречивые примеры для моего первого вопроса и ничего полезного и применил к моему второму вопросу...

Ответ 1

1.. Ваш подход одобрен, если вы действительно должны поддерживать открытое соединение между сервером и клиентом во все времена любой ценой. Однако я бы использовал асинхронное соединение, например, отправляя HTTP-запрос на сервер, а затем получаю ответ, когда сервер чувствует себя так.

Если вам понадобится сервер для ответа клиенту через некоторое время, но вы не знаете, когда вы также можете изучить инфраструктуру Google Cloud Messaging, который дает вам прозрачный и последовательный способ отправки небольших сообщений вашим клиентам с вашего сервера.

Вам нужно рассмотреть некоторые вещи, когда вы разрабатываете мобильное приложение.

  • У смартфона нет бесконечного количества батареи.

  • Подключение к Интернету для смартфонов несколько неустойчиво, и вы потеряете интернет-соединение в разное время.

Когда вы постоянно поддерживаете прямое подключение к серверу, ваше приложение продолжает отправлять пакеты keep-alive, что означает, что вы сосать телефон довольно быстро. Когда интернет-соединение так же неустойчиво, как и в мобильной широкополосной связи, вы иногда теряете соединение и нуждаетесь в восстановлении от этого. Поэтому, если вы используете TCP, потому что хотите убедиться, что ваши пакеты получены, вы можете повторно отправлять одни и те же пакеты много раз и поэтому получать много накладных расходов.

Также вы можете столкнуться с проблемами с потоками на стороне сервера, если вы сами откроете потоки на сервере, что это похоже. Скажем, у вас одновременно подключено 200 клиентов к серверу. Каждый клиент имеет 1 поток, открытый на сервере. Если сервер должен одновременно обслуживать 200 различных потоков, это может быть довольно сложной задачей для сервера в конце, и вам также нужно будет сделать много работы самостоятельно.

2.. Когда вы выходите из приложения, вам нужно будет очистить его после. Это должно быть сделано в вашем onPause методе Activity, который активен.

Это означает, что вы убиваете все активные потоки (или, по крайней мере, их перехватываете), сохраняя состояние вашего пользовательского интерфейса (если вам это нужно), и очищаете и закрываете любые открытые соединения с сервером, который у вас есть.

Что касается использования Threads, я бы рекомендовал использовать некоторые из встроенных инструментов потоковой обработки, таких как Обработчики или реализовать AsyncTask.

Если вы действительно думаете, что Thread - это способ пойти, я определенно рекомендую использовать шаблон Singleton в качестве "менеджера" для вашей потоковой передачи.

Этот менеджер будет управлять вашими потоками, так что вы не столкнетесь с более чем одним Thread, разговаривающим с сервером в любой момент времени, даже если вы находитесь в другой части приложения.

Что касается реализации класса Application, посмотрите документацию по классу приложения:

Базовый класс для тех, кто должен поддерживать глобальное состояние приложения. Вы можете предоставить свою собственную реализацию, указав ее имя в своем теге AndroidManifest.xml, что приведет к тому, что этот класс будет создан для вас, когда будет создан процесс для вашего приложения/пакета.

Как правило, нет необходимости в подклассе Application. В большинстве ситуаций статические синглтоны могут обеспечивать одинаковые функциональные возможности более модульным способом.

Поэтому рекомендуется избегать применения собственного класса Application, однако если вы позволите одному из ваших Activities инициализировать свой собственный класс Singleton для управления Threads и подключений, которые вы могли бы (просто могли бы) запустить в потому что инициализация singleton может "привязываться" к конкретному Activity, и поэтому, если конкретный Activity будет удален с экрана и приостановлен, он может быть убит, и поэтому синглтон может быть убит. Таким образом, инициализация синглтона внутри вашей реализации Application может показаться полезной.

Извините за стену текста, но ваш вопрос довольно "открытый", поэтому я попытался дать вам несколько открытые вопросы - надеюсь, что это поможет; -)