This is my broadcast receiver class and the implementation of it in main.
Problem is that onReceive method never gets called.
class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
Toast.makeText(p0, "It works", Toast.LENGTH_LONG).show()
}
}
class MainActivity : AppCompatActivity() {
......
private var broadcastReceiver: MyBroadcastReceiver = MyBroadcastReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
......
registerReceiver(broadcastReceiver, IntentFilter().apply {
addAction(Intent.ACTION_PACKAGE_ADDED)
addAction(Intent.ACTION_PACKAGE_REMOVED)
})
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(broadcastReceiver)
}
}
Please help. Thanks in advance.
I could make it work with the following code
class KotlinBroadcastReceiver(action: (context: Context, intent: Intent) -> Unit) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) = action(context, intent)
}
class MainActivity : AppCompatActivity() {
private val broadcastReceiver = KotlinBroadcastReceiver { context, _ ->
Toast.makeText(context, "It works", Toast.LENGTH_LONG).show()
}
override fun onCreate(savedInstanceState: Bundle?) {
registerReceiver(broadcastReceiver, IntentFilter().apply {
addAction(Intent.ACTION_PACKAGE_ADDED)
addAction(Intent.ACTION_PACKAGE_REMOVED)
addDataScheme("package") // I could not find a constant for that :(
})
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(broadcastReceiver)
}
}
Usually the BroadcastReceiver needs a number of steps to be set up.
First of all did yout pass to the manifest the receiver?
<receiver android:name=".MyBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
</intent-filter>
</receiver>
Edit: Please see this post, where is suggested ACTION_PACKAGE_FULLY_REMOVED or JobScheduler
try also to reinstall the app on the emulator
Related
I`m trying to build a service that detects if the screen of a device is locked/unlocked (which I will later user as a native module in React). However, it seems like my service is not starting, and I don't receive the expected logs. Where is my mistake? (It's my first time dealing with native android & Kotlin, so apologies if this is a dumb question, and duplicates were related to java code)..
I have defined a Broadcast Receiver for each event here:
ScreenOnReceiver.kt
class screenOnReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if(intent!!.action == Intent.ACTION_SCREEN_ON) {
val screenOff = false
val i = Intent(context, PowerButtonService::class.java)
i.putExtra("screenState", screenOff)
context!!.startService(i)
}
}
}
ScreenOffReceiver.kt
class screenOffReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if(intent!!.action == Intent.ACTION_SCREEN_ON) {
val screenOff = false
val i = Intent(context, PowerButtonService::class.java)
i.putExtra("screenState", screenOff)
context!!.startService(i)
}
}
}
ScreenChangeService.kt:
class ScreenChangeService: Service() {
override fun onBind(p0: Intent?): IBinder? = null
override fun onCreate() {
val screenOnReceiver = screenONReceiver()
val screenOnFilter = IntentFilter(Intent.ACTION_SCREEN_ON)
registerReceiver(screenOnReceiver, screenOnFilter)
val screenOffReceiver = screenOffReceiver()
val screenOffFilter = IntentFilter(Intent.ACTION_SCREEN_OFF)
registerReceiver(screenOffreceiver, screenOffFilter)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val screenState = intent!!.getBooleanExtra("screenState", false)
if (screenState == true) {
Log.d("TAG", "Screen On")
} else {
Log.d("TAG", "Screen Off")
}
return START_NOT_STICKY
}
}
Manifest.xml
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.Test">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".PowerButtonService"/>
</application>
I have broadcast in separated class:
class Receiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {}
}
How to listen this broadcasrt in main activity?
I have tried:
class MainActivity : AppCompatActivity() {
private val receiver = Receiver()
override fun onCreate(savedInstanceState: Bundle?) {
receiver.onReceive(context: Context, intent: Intent) {
//
}
}
}
Now I register events like this:
override fun onStart() {
super.onStart()
registerReceiver(receiver, IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED))
}
I tried this in activity:
private val broadcastReceiver:BroadcastReceiver = (object :BroadcastReceiver(){
override fun onReceive(context: Context, intent: Intent) {
val ltInflater = layoutInflater
val layout: View = ltInflater.inflate(R.layout.custom_toast, findViewById(R.id.toast_layout))
val image = layout.findViewById<ImageView>(R.id.imageView)
}
So, I get error because I can not get access to layout in this step
You need to create a broadCast receiver in the main activity like this
val broadcastReceiver:BroadcastReceiver = (object :BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
val layout: View = ltInflater.inflate(R.layout.custom_toast, findViewById(R.id.toast_layout))
val image = layout.findViewById<ImageView>(R.id.imageView)
image.setImageResource(R.drawable.ic_launcher_background)
}
})
and you need to have string that's common between both the class that's going to broadcast the intent and the broadcast receiver let's call it key
val key = keyTelephonyManager.ACTION_PHONE_STATE_CHANGED
you have to register the receiver to start receiving intents like this (do this in onCreate())
var intentFilter = IntentFilter(MainActivity.key);
registerReceiver(broadcastReceiver, intentFilter);
I'm using Firebase analytics and Firebase BOM. I need to create AppMeasurementReceiver programatically, becasue I have more than one receiver that needs INSTALL_REFERRER. Unfortunately I get an error that class that is implemented by AppMeasurementReceiver is missing. Missing class is com.google.android.gms.measurement.internal.zzff$zza. It's hard to debug and guess what is missing.
class InstallRefererReceiver : BroadcastReceiver() {
private val otherReceivers = listOf(
AppMeasurementReceiver()
)
override fun onReceive(context: Context?, intent: Intent?) {
otherReceivers.forEach {
it.onReceive(context, intent)
}
}
}
<receiver
android:name="co.app.referer.InstallRefererReceiver"
android:exported="true"
android:permission="android.permission.INSTALL_PACKAGES">
<intent-filter android:priority="999">
<action android:name="com.google.android.gms.measurement.UPLOAD" />
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
I get following error:
e: Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath:
class com.google.android.gms.measurement.AppMeasurementReceiver, unresolved supertypes: com.google.android.gms.measurement.internal.zzff$zza
I can find undefined field in play-services-measurement. This undefinedtype type is probably the same type that AppMeasurementReceiver is implementing.
public final class zzff {
private final <undefinedtype> zza;
EDIT
I found really ugly solution, just create AppMeasurementReceiver via reflection.
class InstallRefererReceiver : BroadcastReceiver() {
private val otherReceivers = listOf(
FixedAppMeasurementReceiver()
)
override fun onReceive(context: Context?, intent: Intent?) {
otherReceivers.forEach {
it.onReceive(context, intent)
}
}
private class FixedAppMeasurementReceiver : BroadcastReceiver() {
private val appMeasurementReceiver: BroadcastReceiver? = try {
Class.forName("com.google.android.gms.measurement.AppMeasurementReceiver")
.newInstance() as BroadcastReceiver?
} catch (t: Throwable) {
null
}
override fun onReceive(context: Context?, intent: Intent?) {
try {
appMeasurementReceiver?.onReceive(context, intent)
} catch (t: Throwable) {
doNothing()
}
}
}
}
I have an Intent service & a BroadcastReceiver.
As per background limitation on Android Oreo & above, the background applications(when an application is not foreground ) cannot use the started service. When you call startService() method from the background applications simply through the IllegalStateException.
But In my case, My intent service is running properly even when the app is in the background.
I am using ADB cmd to trigger broadcast.
Please correct where I am missing.
adb shell am broadcast -a android.intent.action.TEST --es maxCountValue 10 -n com.example.servicedemo/.MyReceiver
enter code here
BroadcastReceiver class
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context, "CompleteReceiver", Toast.LENGTH_LONG).show()
if (intent!!.action.equals("android.intent.action.TEST")) {
val mIntent = Intent(context, MyIntentService::class.java).apply {
Log.v("MyIntentService", intent.data.toString())
this.putExtra("maxCountValue", 100)
}
context?.startService(mIntent)
}
}
}
Intent Service
private const val SERVICE_NAME = "MyIntentService"
class MyIntentService : IntentService(SERVICE_NAME) {
private val handler = Handler()
override fun onCreate() {
super.onCreate()
showToast("Job Execution Started")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
showToast("Job Execution onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
showToast("Job Execution onDestroy")
}
override fun onHandleIntent(intent: Intent?) {
val maxCount = intent!!.getIntExtra("maxCountValue", -1)
for (i in 0 until maxCount) {
Log.d(SERVICE_NAME, "onHandleWork: The number is: $i")
try {
Thread.sleep(100)
} catch (e: InterruptedException) {
Log.d(SERVICE_NAME, "Exception: ")
e.printStackTrace()
}
}
}
private fun showToast(msg: String) {
handler.post {
Toast.makeText(this#MyIntentService, msg, Toast.LENGTH_LONG).show()
}
}
}
Manifest :
<service android:name=".MyIntentService"/>
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.TEST" />
</intent-filter>
</receiver>
"The definition of background for purposes of service limitations is distinct from the definition used by memory management; an app might be in the background as pertains to memory management, but in the foreground as pertains to its ability to launch services."
-
https://developer.android.com/about/versions/oreo/background
PS that's the whole purpose of services
How to use register and create a Broadcast Receiver in Android in Kotlin. Any advice...
In Java, you can create it by declaring it as a Broadcast Receiver. But in Kotlin I am not able to find Broadcast Receiver ...well if it is there then how to use it.
you can do it in the following way
Create a broadcast receiver object in your activity class
val broadCastReceiver = object : BroadcastReceiver() {
override fun onReceive(contxt: Context?, intent: Intent?) {
when (intent?.action) {
BROADCAST_DEFAULT_ALBUM_CHANGED -> handleAlbumChanged()
BROADCAST_CHANGE_TYPE_CHANGED -> handleChangeTypeChanged()
}
}
}
Register broadcast receiver in onCreate() function of your activity
LocalBroadcastManager.getInstance(this)
.registerReceiver(broadCastReceiver, IntentFilter(BROADCAST_DEFAULT_ALBUM_CHANGED))
unregister it in ondestroy function of your activity
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(broadCastReceiver)
Anonymous class syntax in Kotlin is like this:
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
}
}
I've created a BroadcastReceiver Kotlin extension, which you can copy/paste anywhere.
It doesn't do much more than what is already mentioned, but it reduces some of the boilerplate. 😀
Using this extension, you should register/unregister like so:
private lateinit var myReceiver: BroadcastReceiver
override fun onStart() {
super.onStart()
myReceiver = registerReceiver(IntentFilter(BROADCAST_SOMETHING_HAPPENED)) { intent ->
when (intent?.action) {
BROADCAST_SOMETHING_HAPPENED -> handleSomethingHappened()
}
}
}
override fun onStop() {
super.onStop()
unregisterReceiver(myReceiver)
}