- Broadcasts
- Системные сообщения
- Получение сообщений
- Объявление в манифесте
- Регистрация в контексте
- Общий принцип работы
- Отправка сообщений
- Установка разрешений
- Отправка сообщений с разрешениями
- Получение сообщений с разрешением
- Полезные ссылки
- Android BroadcastReceiver Example Tutorial
- Android BroadcastReceiver
- Broadcast Receiver in Android
- Creating a BroadcastReceiver
- Registering the BroadcastReceiver in android app
- Sending Broadcast intents from the Activity
- BroadcastReceiver in Android Project Structure
- Android BroadcastReceiver Code
Broadcasts
Broadcasts — это широковещательные сообщения, которые отправляются, когда происходит определённое событие. Приложения могут отправлять их сами, либо получать сообщения, отправляемые системой Android и другими приложениями. Когда происходит трансляция сообщения, система автоматически будет направлять его всем, кто на него подписался.
Системные сообщения
Системные сообщения отправляются автоматически, когда происходят различные системные события: включение системы или выход из режима полёта. Такие сообщения отправляются всем приложениям, которые подписаны на их получение.
Полный список системных событий можно посмотреть в файле BROADCAST_ACTION.TXT в Android SDK.
Получение сообщений
Приложения могут получать сообщения двумя способами: объявив в манифесте приёмник широковещательных сообщений (broadcast receiver), либо зарегистрировать его в контексте.
Объявление в манифесте
Если приёмник широковещательных сообщений будет объявлен в манифесте, то система запустит приложение при отправке сообщения.
Алгоритм объявления приёмника состоит из двух шагов:
Создать класс, расширяющий базовый класс BroadcastReceiver и реализовать в нём метод обратного вызова onReceive() .
class MyReceiver : BroadcastReceiver() < override fun onReceive(context: Context, intent: Intent) < val msg = intent.getStringExtra("msg") Toast.makeText(context, "New message received: $msg", Toast.LENGTH_LONG).show() >>
Добавить элемент в манифест. При этом с помощью intent-фильтров нужно объявить события, на которые подписывается этот приёмник. Они могут быть как системные, так и пользовательские (как в данном случае).
Регистрация в контексте
Алгоритм объявления приёмника состоит из трёх шагов:
Создать класс, расширяющий базовый класс BroadcastReceiver и реализовать в нём метод обратного вызова onReceive() . Создать экземпляр этого класса.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
class MyReceiver : BroadcastReceiver() < override fun onReceive(context: Context, intent: Intent) < StringBuilder().apply < append("Action: $\n") append("URI: $\n") toString().also < log ->Toast.makeText(context, log, Toast.LENGTH_LONG).show() > > > > . val br: BroadcastReceiver = MyReceiver()
Создать intent-фильтр и зарегистрировать приёмник, вызвав метод registerReceiver(BroadcastReceiver, IntentFilter) .
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply < addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED) >registerReceiver(br, filter)
Отменить регистрацию приёмника при помощи метода unregisterReceiver(android.content.BroadcastReceiver) .
Такие приёмники будут работать до тех пор, пока существует контекст, в котором они были зарегистрированы. Например, если приёмник был зарегистрирован в контексте активити, то он будет получать сообщения, пока активити не будет уничтожена. Если приёмник зарегистрирован в контексте приложения, то он будет получать сообщения, пока работает приложение.
Чтобы лишний раз не тратить ценные ресурсы, следует отменять регистрацию приёмника, когда в нём больше нет необходимости, либо когда контекст, в котором он был зарегистрирован, перестаёт существовать.
Также важно и то, в каком месте отменять регистрацию. Например, если приёмник был зарегистрирован в методе активити onCreate() , то отменять регистрацию следует в методе onDestroy() , чтобы предотвратить утечку приёмника из контекста. Если же приёмник был зарегистрирован в методе onResume() , то отменять регистрацию следует в методе onPause() , чтобы не получать сообщения пока активити “приостановлена”.
Общий принцип работы
Все широковещательные сообщения помещаются в Intent , в котором параметр action отвечает за произошедшее событие. Также он может включать какие-либо дополнительные данные, в зависимости от типа события.
Сообщение получают все приложения, которые на него подписались. Когда сообщение получает непосредственно приёмник, система вызывает метод onReceive() и передаёт в него Intent , который содержит сообщение.
В период выполнения метода onReceive() приёмник считается процессом переднего плана, поэтому система будет поддерживать выполнение этого процесса. Но как только ваш код вернётся из onReceive() , приёмник перестаёт быть активным, то есть его приоритет становится низким и система может его уничтожить в любое время.
По этой причине не следует запускать длительные фоновые потоки из приёмника: они, как и приёмник, для системы являются неактивными и уничтожаются вместе с ним.
Есть несколько способов, чтобы этого избежать:
- goAsync() . Как правило приёмники могут работать до 10 секунд. Если же требуется немного больше времени, но не более 30 секунд, то следует использовать goAsync() ;
- JobScheduler , Service или JobIntentService . Данные системные средства должны использоваться, когда требуется выполнить более длительную работу.
Отправка сообщений
В основном смысл отправки сообщений из вашего приложения заключается в том, чтобы пока пользователь совершает какие-либо действия, обрабатывать их в другой части вашего приложения для выполнения определенной логики.
Отправлять сообщения можно тремя способами:
sendOrderedBroadcast(Intent, String) — отправляет сообщение только одному приёмнику за раз. При этом приёмник может передать результат следующему приёмнику или остановить распространение сообщения. Это возможно благодаря тому, что каждый приёмник работает по очереди, а управлять очерёдностью можно с помощью атрибута android:priority элемента . Приёмники с одинаковым приоритетом будут работать в произвольном порядке.
Вторым параметром данного метода являются разрешения, которые приёмник должен иметь для получения сообщения. Может равняться null — это означает, что разрешение не требуется.
val requiredPermission = "com.example.MY_BROADCAST_PERMISSION" Intent().also < intent ->intent.action = "com.example.MY_NOTIFICATION" intent.putExtra("msg","Hi! I'm message.") sendOrderedBroadcast(intent, requiredPermission) // sendOrderedBroadcast(intent, null) >
sendBroadcast(Intent) — отправляет сообщение всем приёмникам в произвольном порядке. Этот способ также называют “нормальной трансляцией сообщений”. Несмотря на свою эффективность, имеет некоторые недостатки по сравнению с первым способом: приёмники не могут передавать и считывать результаты других приёмников, а также прерывать трансляцию сообщений.
Intent().also < intent ->intent.action = "com.example.MY_NOTIFICATION" intent.putExtra("msg","Hi! I'm message.") sendBroadcast(intent) >
LocalBroadcastManager.sendBroadcast — отправляет сообщения только тем приёмникам, которые определены в том же приложении, что и отправитель. При использовании данного способа не нужно будет беспокоиться, что стороннее приложение поймает ваше сообщение.
Для использования этого метода нужно зарегистрировать приёмник с помощью LocalBroadcastManager .
LocalBroadcastManager.getInstance(this).registerReceiver( object : BroadcastReceiver() < override fun onReceive(context: Context?, intent: Intent?) < val msg = intent?.getStringExtra("msg") Toast.makeText(context, "New message received: $msg", Toast.LENGTH_LONG).show() >>, IntentFilter("com.example.MY_NOTIFICATION") )
Intent().also < intent ->intent.action = "com.example.MY_NOTIFICATION" intent.putExtra("msg", "Hi! I'm message.") LocalBroadcastManager.getInstance(this).sendBroadcast(intent) >
Если LocalBroadcastManager не импортируется, то следует добавить зависимость:
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
В версии 1.1.0-alpha01 Google признали LocalBroadcastManager устаревшим (deprecated).
Установка разрешений
Разрешения позволяют ограничить рассылку сообщений определённым набором приложений. Ограничения можно добавить как к отправителю, так и к получателю сообщений.
Отправка сообщений с разрешениями
Когда вы отправляете сообщение с помощью методов sendBroadcast(Intent, String) или sendOrderedBroadcast(Intent, String) , то в качестве второго параметра им можно передать разрешение. Тогда это сообщение дойдёт только до тех приёмников, у которых в манифесте указано это разрешение. При этом разрешение может быть как системным, так и пользовательским.
Например, при отправке сообщения было указано системное разрешение:
sendBroadcast(intent, Manifest.permission.SEND_SMS)
Это сообщение получат только те, у кого в манифесте есть такая строчка:
Пользовательские разрешения добавляются в манифест при помощи элемента .
Получение сообщений с разрешением
При регистрации приёмника в манифесте или с помощью метода registerReceiver() можно задать разрешение. Тогда такому приёмнику смогут отправлять сообщения только такие отправители, у которых в манифесте указано это разрешение.
Допустим, у вас в манифесте объявлен приёмник с разрешением:
Или вы зарегистрировали приёмник с разрешением в контексте:
var filter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED) registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null )
Отправлять сообщения подобным приёмникам смогут такие приложения, у которых в манифесте присутствует строчка:
Полезные ссылки
Broadcasts overview — официальная документация про широковещательные сообщения.
Implicit Broadcast Exceptions.
Android BroadcastReceiver Example Tutorial
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
Today we’ll discuss and implement Android BroadcastReceiver that is a very important component of Android Framework.
Android BroadcastReceiver
- android.intent.action.BATTERY_LOW : Indicates low battery condition on the device.
- android.intent.action.BOOT_COMPLETED : This is broadcast once, after the system has finished booting
- android.intent.action.CALL : To perform a call to someone specified by the data
- android.intent.action.DATE_CHANGED : The date has changed
- android.intent.action.REBOOT : Have the device reboot
- android.net.conn.CONNECTIVITY_CHANGE : The mobile network or wifi connection is changed(or reset)
Broadcast Receiver in Android
To set up a Broadcast Receiver in android application we need to do the following two things.
Creating a BroadcastReceiver
Let’s quickly implement a custom BroadcastReceiver as shown below.
public class MyReceiver extends BroadcastReceiver < public MyReceiver() < >@Override public void onReceive(Context context, Intent intent) < Toast.makeText(context, "Action: " + intent.getAction(), Toast.LENGTH_SHORT).show(); >>
BroadcastReceiver is an abstract class with the onReceiver() method being abstract. The onReceiver() method is first called on the registered Broadcast Receivers when any event occurs. The intent object is passed with all the additional data. A Context object is also available and is used to start an activity or service using context.startActivity(myIntent); or context.startService(myService); respectively.
Registering the BroadcastReceiver in android app
A BroadcastReceiver can be registered in two ways.
Using intent filters we tell the system any intent that matches our subelements should get delivered to that specific broadcast receiver.3. By defining it programmatically Following snippet shows a sample example to register broadcast receiver programmatically.
IntentFilter filter = new IntentFilter(); intentFilter.addAction(getPackageName() + "android.net.conn.CONNECTIVITY_CHANGE"); MyReceiver myReceiver = new MyReceiver(); registerReceiver(myReceiver, filter);
To unregister a broadcast receiver in onStop() or onPause() of the activity the following snippet can be used.
@Override protected void onPause()
Sending Broadcast intents from the Activity
The following snippet is used to send an intent to all the related BroadcastReceivers.
Intent intent = new Intent(); intent.setAction("com.journaldev.CUSTOM_INTENT"); sendBroadcast(intent);
Don’t forget to add the above action in the intent filter tag of the manifest or programmatically. Let’s develop an application that listens to network change events and also to a custom intent and handles the data accordingly.
BroadcastReceiver in Android Project Structure
Android BroadcastReceiver Code
The activity_main.xml consists of a button at the centre that sends a broadcast intent.
The MainActivity.java is given below.
package com.journaldev.broadcastreceiver; import android.content.Intent; import android.content.IntentFilter; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import butterknife.ButterKnife; import butterknife.InjectView; import butterknife.OnClick; public class MainActivity extends AppCompatActivity < ConnectionReceiver receiver; IntentFilter intentFilter; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.inject(this); receiver = new ConnectionReceiver(); intentFilter = new IntentFilter("com.journaldev.broadcastreceiver.SOME_ACTION"); >@Override protected void onResume() < super.onResume(); registerReceiver(receiver, intentFilter); >@Override protected void onDestroy() < super.onDestroy(); unregisterReceiver(receiver); >@OnClick(R.id.button) void someMethod() < Intent intent = new Intent("com.journaldev.broadcastreceiver.SOME_ACTION"); sendBroadcast(intent); >>
In the above code we’ve registered another custom action programmatically. The ConnectionReceiver is defined in the AndroidManifest.xml file as below.
The ConnectionReceiver.java class is defined below.
public class ConnectionReceiver extends BroadcastReceiver < @Override public void onReceive(Context context, Intent intent) < Log.d("API123",""+intent.getAction()); if(intent.getAction().equals("com.journaldev.broadcastreceiver.SOME_ACTION")) Toast.makeText(context, "SOME_ACTION is received", Toast.LENGTH_LONG).show(); else < ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); if (isConnected) < try < Toast.makeText(context, "Network is connected", Toast.LENGTH_LONG).show(); >catch (Exception e) < e.printStackTrace(); >> else < Toast.makeText(context, "Network is changed or reconnected", Toast.LENGTH_LONG).show(); >> > >
In the above code we check the intent action that triggers the onReceive() method and based on that display the toast. Note: To make the broadcast receiver unavailable to external applications, add the attribute android:exported=false in the manifest. When we send a broadcast, it is possible for the external applications too to receive them. This can be prevented by specifying this limitation. The output app in action is given below. This brings an end android BroadcastReceiver tutorial. You can download the final BroadcastReceivers project from the link below.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.