how to send FCM message to MainActivity - android

I want to show FCM received message in my mainActivity as a bottomNavigation badge,
but how can I send data to activity from services?
I used:
override fun onMessageReceived(p0: RemoteMessage) {
super.onMessageReceived(p0)
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.putExtra("badge", p0.notification?.body)
startActivity(intent)
}
but this code open new MainActivity, while there's another one!

You could try sending a LocalBroadcast if your service and activity run in the same process.
// Inside the service
override fun onMessageReceived(p0: RemoteMessage) {
super.onMessageReceived(p0)
val lbm = LocalBroadcastManager.getInstance(this)
val dataIntent = Intent().apply {
putExtra("badge", p0.notification?.body)
}
lbm.sendBroadcast(dataIntent)
}
// Inside the activity
private val lbm by lazy { LocalBroadcastManager.getInstance(this) }
private val badgeListener = object : BroadcastReceiver() {
override fun onReceive(ctx: Context, data: Intent) {
val count = intent.getIntExtra("badge")
// Update the view here
}
}
override fun onCreate(){
// Other stuff
lbm.registerReceiver(badgeListener)
}
override fun onDestroy() {
lbm.unregisterReceiver(badgeListener)
}

Related

How to listen BroadcastReceiver in main activity?

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);

Listen for onDownloadComplete Exoplayer

I am trying to download a video for offline playing in exoplayer, but I don't know how to listen for onDownloadComplete. In the exoplayer docs they say DownloadService is a wrap around android DownloadManager so I try to listen for DownloadManager.ACTION_DOWNLOAD_COMPLETE broadcast but it's not working, actually this is my first time using exoplayer.
Download Service
class MediaDownloadService : DownloadService(
C.DOWNLOAD_NOTIFICATION_ID, DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL,
C.CHANNEL_ID, R.string.channel_name, R.string.channel_description
) {
override fun onCreate() {
registerReceiver(onComplete, IntentFilter(ACTION_DOWNLOAD_COMPLETE))
super.onCreate()
}
override fun onDestroy() {
unregisterReceiver(onComplete)
super.onDestroy()
}
override fun getDownloadManager(): DownloadManager {
return DownloadUtil.getDownloadManager(this)
}
override fun getForegroundNotification(downloads: MutableList<Download>): Notification {
val intent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val notificationHelper = DownloadNotificationHelper(this, C.CHANNEL_ID)
return notificationHelper.buildProgressNotification(
R.drawable.ic_notification,
pendingIntent,
"simple message",
downloads
)
}
override fun getScheduler(): Scheduler? {
return null
}
val onComplete: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(ctxt: Context?, intent: Intent?) {
toast("Download COmpleted")
}
}
}
You can compare bytesDownloaded and contentLength to check if it's finish downloading.
downloadManager.addListener(object : DownloadManager.Listener {
override fun onDownloadChanged(downloadManager: DownloadManager, download: Download) {
if (download.bytesDownloaded == download.contentLength) {
Log.d("Completed")
}
}
})

Pass data to Service in Kotlin

I have an app that uses Service class to perform task in foreground.
This service also contains a Handler object to run same function multiple times. I want to change attributes in my activity_main.xml while functions are running in Service. For example when function calculates something in Service the result prints in TextView.
How it would be correct access activity_main's objects to retrieve and change their values and attributes?
Here is what I have:
MainActivity.kt:
class MainActivity : AppCompatActivity() {
private var notificationManager: NotificationManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
buttonStart.setOnClickListener{
buttonStart.isEnabled = false
buttonStop.isEnabled = true
IdListener.startService(this, "Foreground Service is running...")
}
}
}
IdListener.kt:
class IdListener : Service() {
private val CHANNEL_ID = "ForegroundService Kotlin"
private lateinit var mainHandler: Handler
private lateinit var mRunnable: Runnable
companion object {
fun startService(context: Context, message: String) {
val startIntent = Intent(context, IdListener::class.java)
startIntent.putExtra("inputExtra", message)
ContextCompat.startForegroundService(context, startIntent)
}
fun stopService(context: Context) {
val stopIntent = Intent(context, IdListener::class.java)
context.stopService(stopIntent)
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
mainHandler = Handler()
mRunnable = Runnable { showRandomNumber(tm) }
mainHandler.postDelayed(mRunnable, 1000)
val input = intent?.getStringExtra("inputExtra")
createNotificationChannel()
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
0, notificationIntent, 0
)
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service Kotlin Example")
.setContentText(input)
.setSmallIcon(R.drawable.ic_notofication)
.setContentIntent(pendingIntent)
.build()
startForeground(1, notification)
return START_NOT_STICKY
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onDestroy() {
super.onDestroy()
mainHandler.removeCallbacks(mRunnable)
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(CHANNEL_ID, "Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT)
val manager = getSystemService(NotificationManager::class.java)
manager!!.createNotificationChannel(serviceChannel)
}
}
/// function in which I want elements from activity_main.xml to be changed
fun showRandomNumber(manager: TelephonyManager){
myTextView.text = "Working..."
mainHandler.postDelayed(mRunnable, 1000)
}
}
Here's how I'd probably handle your case. I don't know exactly what you're doing, but I'm just having the text view show "Working..." when it starts the service until there's an ID available. I haven't tested this and haven't worked with services in a long time, so you might want other input.
object IdServiceData {
val id = MutableLiveData<String>()
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
//...
myTextView.text = "Working..." // should really use string resource here.
IdServiceData.id.observe(this) {
myTextView.text = it.value
}
}
}
When an Activity or Fragment observes a LiveData, they automatically stop observing when they are destroyed, so they are not leaked. So your Activity can be destroyed and recreated multiple times while the Service is running and it will keep getting the proper updates.
class IdListener : Service() {
//...
private fun broadcastNewId(id: String){
mainHandler.post {
IdServiceData.id.value = id
}
}
}
If you want better encapsulation, I suppose you could abstract out the MutableLiveData by creating a separate IdServiceDataProvider that has the MutableLiveData and is used by the service, and the IdServiceData would reference the data like this: val id: LiveData<String> = IdServiceDataProvider.id

How to send context to BroadcastReceiver?

I want to use my BroadcastReceiver as sender of data into my activity. For this reason I'm using LocalBroadcastManager. This manager is used to register and unregister my receiver. Problem is that Context in onReceive method is different than Context in onStart and onStop method.
I need to pass activity context into my BroadcastReceiver or instance of LocalBroadcastManager initialized inside Activity. Because my receiver is not receiving any data.
Maybe it is not fault of this manager context but I don't know why it doesnt work since I implemented this manager.
class GPSReceiver: BroadcastReceiver(){
companion object{
const val GPS_PAYLOAD = "gps_payload"
}
override fun onReceive(context: Context, intent: Intent) {
try {
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val int = Intent(GPS_PAYLOAD)
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
int.putExtra(GPS_PAYLOAD, true)
} else {
int.putExtra(GPS_PAYLOAD, false)
}
LocalBroadcastManager.getInstance(context).sendBroadcast(int)
} catch (ex: Exception) {
}
}
}
Registering receiver inside Activity:
private val gpsStatusReceiver = object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
App.log("isGpsEnabled: onReceive")
val gpsStatus = intent?.extras?.getBoolean(GPS_PAYLOAD)
if (gpsStatus != null) {
if (gpsStatus){
App.log("isGpsEnabled: true")
hideGpsSnackbar()
} else {
App.log("isGpsEnabled: false")
showGpsSnackbar()
}
} else {
App.log("isGpsEnabled: null")
}
}
}
override fun onStart() {
super.onStart()
LocalBroadcastManager.getInstance(this).apply {
val filter = IntentFilter()
filter.apply {
addAction("android.location.PROVIDERS_CHANGED")
addAction(GPS_PAYLOAD)
}
registerReceiver(gpsStatusReceiver, filter)
}
}
I have seen your code. So there is not issue with context, but in the approach.
Your are registering your reciever with the same strings in which you are getting you data inside the Reciever.
So Send Your broadcast from Fragment/Activity
Send BroadCast Like
private fun sendSuccessfulCheckoutEvent() {
val intent = Intent("successful_checkout_event")
intent.putExtra("cartID", cartId)
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
And Listen it in Activity/Fragment like this
1) Create broadcast Reciever
private val checkoutDoneReciever : BroadcastReceiver = object : BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
val cartNumbers = intent.getIntExtra("cartID", 0)
Log.d("receiver", "Got message: $cartNumbers.toString()")
}
}
2) Register it in onCreate()/onStart()
LocalBroadcastManager.getInstance(this).registerReceiver(cartUpdatedReceiver,IntentFilter("successful_checkout_event"))
3) Unregister it in onDestroy()
LocalBroadcastManager.getInstance(this).unregisterReceiver(cartUpdatedReceiver)

How do I call a method on a different activity?

Im working on an android app which uses notifications frequently.
I chose to set the alarms via setting activity rather then Main Activity but I couldn't manage to find out how to cancel the Alarm Manager via the settingActivity immediately after pressing the switch.
I only found out how to cancel the notifications on the MainActivity, which stops them only after closing and opening the app.
what is the preferred way to do it?
from SettingActivity.kt:
class NotificationPreferenceFragment : PreferenceFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_notification)
setHasOptionsMenu(false)
var switchPref: Preference = findPreference(getString(R.string.pref_notifications_switch_key))
switchPref.onPreferenceChangeListener = OnPreferenceChangeListener { preference, isChecked ->
var toast: Toast = if (isChecked as Boolean) {
Toast.makeText(activity, "switch is ON", Toast.LENGTH_SHORT)
} else {
Toast.makeText(activity, "notifications is OFF", Toast.LENGTH_SHORT)
}
toast.show()
true
}
}
cancel method from MainActivity:
fun cancelAlarm() {
alarmMgr = applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent1 = Intent(applicationContext, AlarmReceiver::class.java)
alarmIntent = PendingIntent.getBroadcast(applicationContext, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT)
alarmMgr!!.cancel(alarmIntent)
}
As said by a commenter, just use BroadcastReceiver
NotificationPreferenceFragment.java
class NotificationPreferenceFragment : PreferenceFragment() {
val broadcaster: LocalBroadcastManager? = null;
override fun onCreate(savedInstanceState: Bundle?) {
broadcaster = LocalBroadcastManager.getInstance(this);
}
// Inside your onPreferenceChangeListener, depends on when you want to call it, either ON or OFF
Intent intent = new Intent("YOUR_DATA_STRING");
intent.putExtra(ANY_EXTRAS_STRING, DATA_ITSELF);
broadcaster.sendBroadcast(intent);
}
MainActivity.java
import android.support.v4.content.LocalBroadcastManager;
override fun onStart() {
super.onStart()
LocalBroadcastManager.getInstance(this).registerReceiver(MYReceiver,
IntentFilter("YOUR_DATA_STRING")
)
}
private val MYReceiver = object : BroadcastReceiver() {
fun onReceive(context: Context, intent: Intent) {
if (intent.extras != null) {
// get any extras if neccessary
// intent.extras!!.getString("ANY_EXTRAS_STRING")
cancelAlarm()
}
}
}
override fun onStop() {
super.onStop()
LocalBroadcastManager.getInstance(this).unregisterReceiver(MYReceiver)
}

Categories

Resources