使用场景:关照栏&桌面部件
自界说关照栏
- <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) {
- }
- }
- );
- }
- }
复制代码- 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)
- }
- }
复制代码- 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);
- }
- }
- }
复制代码 效果
自界说桌面小组件
- 界说组件的布局样式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>
复制代码
- 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"
- }
- }
复制代码
- 在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" />
复制代码
- 在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会显示随机的数字。
原理
- 可以很简单的看到,RemoteViews实现了Parcelable,所以是可序列化的,可以在进程之间传递。
- 在官网可以看到,RemoteViews只支持基础的view,不支持自界说view,支持的布局以及组件如下所示
- 从上面的代码示例中可以知道,在更改组件属性时使用的是setTextViewText,而不是findById。
从以上的调用链可以知道,view的设置被封装在反射对象,存在mActions中,是在接收者进行真正的设置。
可以在Action的子类中找到getMethod(view, this.methodName, param, false /* async */).invoke(view, value);,接收者正是通过反射的方式调用action中封装的view设置方法。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |