intent.getParcelableExtra() 仅在第一次发送推送通知时返回空值

Posted

技术标签:

【中文标题】intent.getParcelableExtra() 仅在第一次发送推送通知时返回空值【英文标题】:intent.getParcelableExtra() return a null value only the first time on sending push notification 【发布时间】:2021-07-05 13:03:10 【问题描述】:

我有 2 个文件。 一个文件是名为MyFirebaseMessagingService.kt 的消息传递服务

class MyFirebaseMessagingService : FirebaseMessagingService() 

    private val ADMIN_CHANNEL_ID = "admin_channel"

    override fun onMessageReceived(p0: RemoteMessage) 
        super.onMessageReceived(p0)

        val intent = Intent(this, ChatActivity::class.java)

        val username = p0.data["title"]

        val ref = FirebaseDatabase.getInstance().getReference("/users/").orderByChild("username").equalTo(username).addValueEventListener(object: ValueEventListener
            override fun onCancelled(error: DatabaseError) 

            

            override fun onDataChange(snapshot: DataSnapshot) 
                for(child in snapshot.children)
                    var user : User? = child.getValue(User::class.java)
                    if(user != null)
                        Log.d("TAG", user.username)
                        Log.d("TAG", user.image_url)
                        Log.d("TAG", user.uid)
                    
                    intent.putExtra(USER_KEY, user)
                
            
            )

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val notificationID = Random().nextInt(3000)


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
            setupChannels(notificationManager)
        

        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        val pendingIntent = PendingIntent.getActivity(
            this, 0, intent,
            PendingIntent.FLAG_ONE_SHOT
        )
        /*
        val largeIcon = BitmapFactory.decodeResource(
            resources,
            R.drawable.ic_delete
        )*/

        val notificationSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this, ADMIN_CHANNEL_ID)
            .setSmallIcon(R.drawable.custom_user_icon)
            //.setLargeIcon(largeIcon)
            .setContentTitle(p0?.data?.get("title"))
            .setContentText(p0?.data?.get("message"))
            .setAutoCancel(true)
            .setSound(notificationSoundUri)
            .setContentIntent(pendingIntent)

        //Set notification color to match app color template
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
            notificationBuilder.color = resources.getColor(R.color.black)
        
        notificationManager.notify(notificationID, notificationBuilder.build())
    

    @RequiresApi(api = Build.VERSION_CODES.O)
    private fun setupChannels(notificationManager: NotificationManager?) 
        val adminChannelName = "New notification"
        val adminChannelDescription = "Device to device notification"

        val adminChannel: NotificationChannel
        adminChannel = NotificationChannel(ADMIN_CHANNEL_ID, adminChannelName, NotificationManager.IMPORTANCE_HIGH)
        adminChannel.description = adminChannelDescription
        adminChannel.enableLights(true)
        adminChannel.lightColor = Color.GREEN
        adminChannel.enableVibration(true)
        notificationManager?.createNotificationChannel(adminChannel)
    

第二个文件是一个名为ChatActivity.kt的Activity

class ChatActivity : AppCompatActivity() 

    val adapter = GroupAdapter<GroupieViewHolder>()

    var receiver : User? = null

    private val FCM_API = "https://fcm.googleapis.com/fcm/send"
    private val serverKey =
        "key=" + "my api key"
    private val contentType = "application/json"

    private val requestQueue: RequestQueue by lazy 
        Volley.newRequestQueue(this.applicationContext)
    

    companion object
        var date_object: Message? = null
        var sender_name :String? = null
    

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_chat)

        val recycler_view = findViewById<RecyclerView>(R.id.recycler_view_messages)
        recycler_view.adapter = adapter
        receiver = intent.getParcelableExtra<User>(NewMessageActivity.USER_KEY)
        supportActionBar?.title = receiver?.username

        val ref = FirebaseDatabase.getInstance().getReference("/users/$FirebaseAuth.getInstance().uid"+"/username").addValueEventListener(object: ValueEventListener
            override fun onCancelled(error: DatabaseError) 

            

            override fun onDataChange(snapshot: DataSnapshot) 
                sender_name = snapshot.getValue(String::class.java)
                Log.e("TAG", "Ricevuta stringa "+sender_name)
            )

       
       ....

我使用 Parcelable 类 User 的对象作为 putParcelableExtra() 方法中的数据,这是 User 类。

class User(val uid:String, val username:String, val image_url:String): Parcelable
    constructor(): this("", "", "")

问题是第一次按下通知时,getParcelableExtra () 方法没有返回对象,因此receiver 对象为空。但是,当再次按下新通知时,该方法会返回可以使用的对象。该问题仅在您第一次点击通知时出现,在应用打开后(并且它尚未在后台)。

我该如何解决?

【问题讨论】:

您想获取用户列表吗? intent.putExtra(USER_KEY, user),这段代码在for循环里面 不,我只想获得一个特定的用户。 for 将只执行一次,因为我的查询基于唯一的用户名。 【参考方案1】:

您似乎在 onDataChange 回调中使用 intent.putExtra(USER_KEY, user) 保存了用户。发生的情况是通知在 onDataChange 回调中的代码执行之前显示,因此尚未在意图中设置用户。

要解决此问题,您应该在 Intent.putExtra(USER_KEY, user) 调用之后在 MyFirebaseMessagingService 类的 onDataChange 方法中显示通知。

编辑:

一个可能的解决方案是:

class MyFirebaseMessagingService : FirebaseMessagingService() 

private val ADMIN_CHANNEL_ID = "admin_channel"

override fun onMessageReceived(p0: RemoteMessage) 
    super.onMessageReceived(p0)

    val intent = Intent(this, ChatActivity::class.java)

    val username = p0.data["title"]

    val ref = FirebaseDatabase.getInstance().getReference("/users/").orderByChild("username").equalTo(username).addValueEventListener(object: ValueEventListener
        override fun onCancelled(error: DatabaseError) 

        

        override fun onDataChange(snapshot: DataSnapshot) 
            for(child in snapshot.children)
                var user : User? = child.getValue(User::class.java)
                if(user != null)
                    Log.d("TAG", user.username)
                    Log.d("TAG", user.image_url)
                    Log.d("TAG", user.uid)
                
                intent.putExtra(USER_KEY, user)
                showNotification(intent)
            
        
        )


fun showNotification(intent: Intent)
    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    val notificationID = Random().nextInt(3000)


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
        setupChannels(notificationManager)
    

    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
    val pendingIntent = PendingIntent.getActivity(
        this, 0, intent,
        PendingIntent.FLAG_ONE_SHOT
    )
    /*
    val largeIcon = BitmapFactory.decodeResource(
        resources,
        R.drawable.ic_delete
    )*/

    val notificationSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
    val notificationBuilder = NotificationCompat.Builder(this, ADMIN_CHANNEL_ID)
        .setSmallIcon(R.drawable.custom_user_icon)
        //.setLargeIcon(largeIcon)
        .setContentTitle(p0?.data?.get("title"))
        .setContentText(p0?.data?.get("message"))
        .setAutoCancel(true)
        .setSound(notificationSoundUri)
        .setContentIntent(pendingIntent)

    //Set notification color to match app color template
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
        notificationBuilder.color = resources.getColor(R.color.black)
    
    notificationManager.notify(notificationID, notificationBuilder.build())

【讨论】:

是的,我发现了错误。我尝试在intent.putExtra() 上传递一个对象,使用构造函数手动创建一个用户,问题解决了,谢谢。 我找到了问题,但是不知道在哪里写puExtra()方法。我必须在 onDataChange() 方法中创建对象,然后将其传递给 putExtra() 方法。 尝试将创建通知的代码(从创建 notificationManager 到 notificationManager.notify())移动到新函数,并在设置用户后在 onDataChange() 方法中调用此函数在额外内容中。只需将意图传递给新函数并将其传递给 pendingIntent - 请参阅我的答案的编辑。 现在似乎工作正常,非常感谢

以上是关于intent.getParcelableExtra() 仅在第一次发送推送通知时返回空值的主要内容,如果未能解决你的问题,请参考以下文章

如何从 IsoDep 获取额外的卡数据?

写入单块命令会因NfcV失败