RemoteView(kotlin)

news2024/11/19 3:39:23

使用场景:通知栏&桌面部件

自定义通知栏

  1. 通知权限申请
    manifest配置
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

权限动态申请

package com.example.kotlinlearn.Common;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import android.widget.Toast;

import androidx.activity.ComponentActivity;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.content.ContextCompat;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class PermissionUtils {
    private static PermissionUtils permissionUtils;
    private String[] permissions = {
            Manifest.permission.POST_NOTIFICATIONS
    };

    private List<String> permissionList = new ArrayList<>();

    private ActivityResultLauncher<String[]> permissionLauncher;

    public static synchronized PermissionUtils getInstance() {
        if (permissionUtils == null) {
            permissionUtils = new PermissionUtils();
        }
        return permissionUtils;
    }

    private PermissionUtils() {
    }

    public void checkPermission(ComponentActivity activity) {
        permissionList.clear(); // Clear previous permission requests

        // Initialize the launcher if not already initialized
        if (permissionLauncher == null) {
            initLaunchers(activity);
        }


        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
                permissionList.add(permission);
            }
        }
        permissionLauncher.launch(permissionList.toArray(new String[0]));

    }

    private void initLaunchers(ComponentActivity activity) {
        // Initialize the launcher for requesting permissions
        permissionLauncher = activity.registerForActivityResult(
                new ActivityResultContracts.RequestMultiplePermissions(),
                new ActivityResultCallback<Map<String, Boolean>>() {
                    @Override
                    public void onActivityResult(Map<String, Boolean> result) {
                    }
                }
        );
    }
}
  1. 实现通知
package com.example.kotlinlearn.RemoteView

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import com.example.kotlinlearn.R

object NotificationUtil {
    private const val CHANNEL_ID = "my_channel_id"
    private const val CHANNEL_NAME = "My Channel"

    fun showCustomNotification(context: Context) {
        // 创建通知渠道(仅适用于 Android O 及以上版本)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID, CHANNEL_NAME,
                NotificationManager.IMPORTANCE_DEFAULT
            ).apply {
                enableLights(true)
                lightColor = Color.RED
                enableVibration(true)
            }
            val notificationManager = context.getSystemService(NotificationManager::class.java)
            notificationManager.createNotificationChannel(channel)
        }

        // 创建 RemoteView
        val remoteViews = RemoteViews(context.packageName, R.layout.notification_layout).apply {
            setTextViewText(R.id.notification_title, "自定义通知标题")
            setTextViewText(R.id.notification_content, "这是自定义通知内容")
        }

        // 设置点击通知的行为
        val intent = Intent(context, RemoteViewActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(
            context,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        val notification = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setCustomContentView(remoteViews)
            .setContentIntent(pendingIntent)
            .build()

        val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        manager.notify(1, notification)
    }
}
  1. activity中申请权限后直接调用就行
package com.example.kotlinlearn.RemoteView

import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.example.kotlinlearn.Common.PermissionUtils
import com.example.kotlinlearn.R


class RemoteViewActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        PermissionUtils.getInstance().checkPermission(this)
        setContentView(R.layout.activity_remote_view)
        var button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            NotificationUtil.showCustomNotification(this);
        }
    }
}

效果
在这里插入图片描述

自定义桌面小组件

  1. 定义组件的布局样式widget_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/widget_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello Widget"
        android:textSize="18sp" />

    <Button
        android:id="@+id/widget_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Update" />
</LinearLayout>

  1. MyWidgetProvider,需要继承自AppWidgetProvider
package com.example.kotlinlearn.RemoteView

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.widget.RemoteViews
import com.example.kotlinlearn.R
import java.util.Random

class MyWidgetProvider : AppWidgetProvider() {
    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray
    ) {
        for (appWidgetId in appWidgetIds) {
            val views = RemoteViews(context.packageName, R.layout.widget_layout)
            val intent = Intent(context, MyWidgetProvider::class.java)
            intent.setAction(BUTTON_CLICKED)
            val pendingIntent = PendingIntent.getBroadcast(
                context,
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )
            views.setOnClickPendingIntent(R.id.widget_button, pendingIntent)
            appWidgetManager.updateAppWidget(appWidgetId, views)
        }
    }

    override fun onReceive(context: Context, intent: Intent) {
        super.onReceive(context, intent)
        if (BUTTON_CLICKED == intent.action) {
            val appWidgetManager = AppWidgetManager.getInstance(context)
            val views = RemoteViews(context.packageName, R.layout.widget_layout)
            views.setTextViewText(R.id.widget_text, "Updated!" + Random().nextInt())
            val componentName = ComponentName(context, MyWidgetProvider::class.java)
            appWidgetManager.updateAppWidget(componentName, views)
        }
    }

    companion object {
        private const val BUTTON_CLICKED = "com.example.BUTTON_CLICKED"
    }
}

  1. 在res/xml下创建组件的属性文件my_widget_info.xml,包括大小等值
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="125dp"
    android:minHeight="50dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/widget_layout" />

  1. 在manifest中配置receiver,与activity同级
        <receiver android:name=".RemoteView.MyWidgetProvider" android:exported="true">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/my_widget_info" />
        </receiver>

效果
在这里插入图片描述
在这里插入图片描述
点击后text会显示随机的数字。

原理

  1. 可以很简单的看到,RemoteViews实现了Parcelable,所以是可序列化的,可以在进程之间传递。
    在这里插入图片描述
  2. 在官网可以看到,RemoteViews只支持基础的view,不支持自定义view,支持的布局以及组件如下所示
    在这里插入图片描述
  3. 从上面的代码示例中可以知道,在更改组件属性时使用的是setTextViewText,而不是findById。
    在这里插入图片描述
    从以上的调用链可以知道,view的设置被封装在反射对象,存在mActions中,是在接收者进行真正的设置。
    可以在Action的子类中找到getMethod(view, this.methodName, param, false /* async */).invoke(view, value);,接收者正是通过反射的方式调用action中封装的view设置方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2199968.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国产长芯微LDUM8801光耦兼容的单通道隔离式栅极驱动器P2P替代UCC23513 FOD8342 TLP5751成本低,质量更好

描述 LDUM8801是单通道兼容光耦输入的隔离式栅极驱动器&#xff0c;可应用于驱动IGBT、SiC 和 MOSFET。它可以提供5A的峰值拉/灌电流。支持150kV/μs的最小共模瞬态免疫&#xff08;CMTI&#xff09;&#xff0c;确保了系统的鲁棒性。驱动器的最大电源电压为32V。 其与光耦式栅…

【计网】【计网】从零开始学习http协议 ---理解http重定向和请求方法

去光荣地受伤&#xff0c; 去勇敢地痊愈自己。 --- 简嫃 《水问》--- 从零开始学习http协议 1 知识回顾2 认识网络重定向3 http请求方法3.1 http常见请求方法3.2 postman工具进行请求3.3 处理GET和POST参数 1 知识回顾 前面两篇文章中我们学习并实现了http协议下的请求与应…

【LeetCode】每日一题 2024_10_9 找到按位或最接近 K 的子数组(LogTrick、位运算)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;找到按位或最接近 K 的子数组 代码与解题思路 今天是 2100 的题目&#xff0c;难度略高&#xff0c;不在我的能力范围&#xff0c;推荐题解&#xff1a;两种方法&#xff1a;LogTrick/滑…

设计模式——门面模式 | 外观模式

哈喽&#xff0c;各位盆友们&#xff01;我是你们亲爱的学徒小z&#xff0c;今天给大家分享的文章是设计模式的——门面模式。 文章目录 定义通用类图1.通用结构2.优点3.缺点 使用场景注意事项1.一个子系统可以有多个门面2.门面不参与子系统内的业务逻辑 定义 定义&#xff1a;…

【Flutter】合并多个流Stream

1.说明 无意间发现了一个好用的库rxdart&#xff0c;它为 Dart 的 Stream 添加了额外的功能。 2.功能 &#xff08;1&#xff09;合并多个流Stream 借助Rx.combineLatest2()合并两个流stream1和stream2。 注意&#xff1a;如果dart文件中同时使用了getx&#xff0c;需要隐…

PCL 3D-SIFT关键点检测(Z方向梯度约束

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 SIFT关键点检测 2.1.2 可视化函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff08;长期更新&#…

调用CString::Format接口格式化字符串时产生异常,可能是将当前的CString对象作为参数传给CString::Format接口导致的

最近有人在技术群里问一个关于使用MFC库中的CString类格式化字符串时遇到的问题&#xff0c;有时格式化出来的字符串有问题&#xff08;不是预期的&#xff09;&#xff0c;有时会产生异常崩溃&#xff0c;让我们帮忙分析一下&#xff0c;看看是什么原因导致的。 后来到MSDN上查…

JAVA基础: synchronized 和 lock的区别、synchronized锁机制与升级

1 synchronized 和 lock的区别 synchronized是一个关键字&#xff0c; lock是一个接口&#xff0c;实际使用的是实现类 synchronized通过触发的是系统级别的锁机制&#xff0c; lock是API级别的锁机制 synchronized自动获得锁&#xff0c;自动释放锁。 lock需要通过方法获得锁…

基于SSM的校园教务系统的设计与实现(论文+源码)_kaic

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对校园教务信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差…

【含开题报告+文档+PPT+源码】基于SSM框架的民宿酒店预定系统的设计与实现

开题报告 随着人们旅游需求的增加&#xff0c;民宿行业呈现出快速发展的趋势。传统的住宿方式逐渐无法满足人们对个性化、舒适、便捷的需求&#xff0c;而民宿作为一种新型的住宿选择&#xff0c;逐渐受到人们的青睐。民宿的特点是具有独特的风格、便捷的地理位置、相对亲近的…

基于yolov8的版面分析AI能力生产全流程

目录 1.coco数据集 1.1 基本定义 1.2应用场景 1.3 数据结构 2.labelme标注工具 2.1 基本定义 2.2 应用场景 2.3 安装步骤 3. 模型训练 3.1 数据标注 3.2 环境准备 3.3 数据预处理 3.4 模型训练 3.5 模型推理 4.参考链接 1.coco数据集 1.1 基本定…

数据库的相关知识

数据库的相关知识 1.数据库能够做什么&#xff1f; 存储大量数据&#xff0c;方便检索和访问保持数据信息的一致、完整共享和安全通过组合分析&#xff0c;产生新的有用信息 2.数据库作用&#xff1f; 存储数据、检索数据、生成新的数据 3.数据库要求&#xff1f; 统一、…

51单片机的自动洗手器【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机红外传感器继电器LED等模块构成。适用于红外感应洗手器、自动出水等相似项目。 可实现功能: 1、红外传感器实时采集人体信息&#xff0c;如果有人靠近&#xff0c;则闭合水泵继电器开始出水&#xff0c;人离开5s后&#xff0c;继电…

微信5大隐藏技巧,让你成为聊天高手

微信&#xff0c;这个几乎人人都在使用的应用&#xff0c;它的一些隐藏功能却鲜为人知。 今天&#xff0c;就让我们一起来探索这些实用的小技巧&#xff0c;让你的微信使用体验更上一层楼。 一键长截图&#xff0c;保存完整信息 在微信里&#xff0c;当你需要截取某个网页或公…

JAVA八股文1

1.Java 基础 1.1 语法基础 封装 利用抽象数据类型将数据和基于数据的操作封装在一起&#xff0c;使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部&#xff0c;尽可能地隐藏内部的细节&#xff0c;只保留一些对外接口使之与外部发生联系。用户无需知道对象内…

【算法】链表:2.两数相加(medium)+模拟

系列专栏 《分治》 《模拟》 《Linux》 目录 1、题目链接 2、题目介绍 3、解法 (模拟) 4、代码 1、题目链接 2. 两数相加 - 力扣&#xff08;LeetCode&#xff09; 2、题目介绍 3、解法 (模拟) 理解题目要求&#xff1a; 我们有两个链表&#xff0c;每个链表代表一个…

完成Sentinel-Dashboard控制台数据的持久化-同步到Nacos

本次案例采用的是Sentinel1.8.8版本 一、Sentinel源码环境搭建 1、下载Sentinel源码工程 git clone https://github.com/alibaba/Sentinel.git 2、导入到idea 这里可以先运行DashboardApplication.java试一下是否运行成功&#xff0c;若成功&#xff0c;源码环境搭建完毕&a…

华为OD机试 - 最长广播响应 - 广度优先搜索(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

计算机视觉学习笔记--高斯金字塔,DoG金字塔和拉普拉斯金字塔附带代码

尺度空间和图像金字塔 尺度并非指图像的大小&#xff0c;而是指图像的模糊程度&#xff0c;从近距离到远距离图像越来越模糊的过程&#xff0c;也是图像的尺度越来越大的过程。尺度空间是图像在不同尺度下的连续表示。其中最常见的是使用高斯核对图像进行卷积。随着高斯滤波核…

网格剖分-耳切法效果展示

1.前言 将简单多边形转换成一组由同样顶点组成的三角形集合是计算机图形学中的一个经典问题。问题中&#xff0c;简单多边形是指由一组有序顶点组成的&#xff0c;点V0~点Vn-1。相邻的顶点之间通过边(Vi,Vi-1)连接&#xff0c;并且边&#xff08;Vn-1,V0&#xff09;连接起始点…