RemoteView(kotlin)

打印 上一主题 下一主题

主题 683|帖子 683|积分 2049

使用场景:关照栏&桌面部件

自界说关照栏


  • 关照权限申请
    manifest设置
  1. <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
复制代码
权限动态申请
  1. package com.example.kotlinlearn.Common;
  2. import android.Manifest;
  3. import android.content.Intent;
  4. import android.content.pm.PackageManager;
  5. import android.net.Uri;
  6. import android.os.Build;
  7. import android.os.Environment;
  8. import android.provider.Settings;
  9. import android.widget.Toast;
  10. import androidx.activity.ComponentActivity;
  11. import androidx.activity.result.ActivityResult;
  12. import androidx.activity.result.ActivityResultCallback;
  13. import androidx.activity.result.ActivityResultLauncher;
  14. import androidx.activity.result.contract.ActivityResultContracts;
  15. import androidx.core.content.ContextCompat;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. import java.util.Map;
  19. public class PermissionUtils {
  20.     private static PermissionUtils permissionUtils;
  21.     private String[] permissions = {
  22.             Manifest.permission.POST_NOTIFICATIONS
  23.     };
  24.     private List<String> permissionList = new ArrayList<>();
  25.     private ActivityResultLauncher<String[]> permissionLauncher;
  26.     public static synchronized PermissionUtils getInstance() {
  27.         if (permissionUtils == null) {
  28.             permissionUtils = new PermissionUtils();
  29.         }
  30.         return permissionUtils;
  31.     }
  32.     private PermissionUtils() {
  33.     }
  34.     public void checkPermission(ComponentActivity activity) {
  35.         permissionList.clear(); // Clear previous permission requests
  36.         // Initialize the launcher if not already initialized
  37.         if (permissionLauncher == null) {
  38.             initLaunchers(activity);
  39.         }
  40.         for (String permission : permissions) {
  41.             if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
  42.                 permissionList.add(permission);
  43.             }
  44.         }
  45.         permissionLauncher.launch(permissionList.toArray(new String[0]));
  46.     }
  47.     private void initLaunchers(ComponentActivity activity) {
  48.         // Initialize the launcher for requesting permissions
  49.         permissionLauncher = activity.registerForActivityResult(
  50.                 new ActivityResultContracts.RequestMultiplePermissions(),
  51.                 new ActivityResultCallback<Map<String, Boolean>>() {
  52.                     @Override
  53.                     public void onActivityResult(Map<String, Boolean> result) {
  54.                     }
  55.                 }
  56.         );
  57.     }
  58. }
复制代码

  • 实现关照
  1. package com.example.kotlinlearn.RemoteView
  2. import android.app.NotificationChannel
  3. import android.app.NotificationManager
  4. import android.app.PendingIntent
  5. import android.content.Context
  6. import android.content.Intent
  7. import android.graphics.Color
  8. import android.os.Build
  9. import android.widget.RemoteViews
  10. import androidx.core.app.NotificationCompat
  11. import com.example.kotlinlearn.R
  12. object NotificationUtil {
  13.     private const val CHANNEL_ID = "my_channel_id"
  14.     private const val CHANNEL_NAME = "My Channel"
  15.     fun showCustomNotification(context: Context) {
  16.         // 创建通知渠道(仅适用于 Android O 及以上版本)
  17.         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  18.             val channel = NotificationChannel(
  19.                 CHANNEL_ID, CHANNEL_NAME,
  20.                 NotificationManager.IMPORTANCE_DEFAULT
  21.             ).apply {
  22.                 enableLights(true)
  23.                 lightColor = Color.RED
  24.                 enableVibration(true)
  25.             }
  26.             val notificationManager = context.getSystemService(NotificationManager::class.java)
  27.             notificationManager.createNotificationChannel(channel)
  28.         }
  29.         // 创建 RemoteView
  30.         val remoteViews = RemoteViews(context.packageName, R.layout.notification_layout).apply {
  31.             setTextViewText(R.id.notification_title, "自定义通知标题")
  32.             setTextViewText(R.id.notification_content, "这是自定义通知内容")
  33.         }
  34.         // 设置点击通知的行为
  35.         val intent = Intent(context, RemoteViewActivity::class.java)
  36.         val pendingIntent = PendingIntent.getActivity(
  37.             context,
  38.             0,
  39.             intent,
  40.             PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
  41.         )
  42.         val notification = NotificationCompat.Builder(context, CHANNEL_ID)
  43.             .setSmallIcon(R.drawable.ic_launcher_foreground)
  44.             .setCustomContentView(remoteViews)
  45.             .setContentIntent(pendingIntent)
  46.             .build()
  47.         val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
  48.         manager.notify(1, notification)
  49.     }
  50. }
复制代码

  • activity中申请权限后直接调用就行
  1. package com.example.kotlinlearn.RemoteView
  2. import android.os.Bundle
  3. import android.widget.Button
  4. import androidx.appcompat.app.AppCompatActivity
  5. import com.example.kotlinlearn.Common.PermissionUtils
  6. import com.example.kotlinlearn.R
  7. class RemoteViewActivity : AppCompatActivity() {
  8.     override fun onCreate(savedInstanceState: Bundle?) {
  9.         super.onCreate(savedInstanceState)
  10.         PermissionUtils.getInstance().checkPermission(this)
  11.         setContentView(R.layout.activity_remote_view)
  12.         var button = findViewById<Button>(R.id.button)
  13.         button.setOnClickListener {
  14.             NotificationUtil.showCustomNotification(this);
  15.         }
  16.     }
  17. }
复制代码
效果

自界说桌面小组件


  • 界说组件的布局样式widget_layout.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:orientation="vertical"
  6.     android:padding="16dp">
  7.     <TextView
  8.         android:id="@+id/widget_text"
  9.         android:layout_width="wrap_content"
  10.         android:layout_height="wrap_content"
  11.         android:text="Hello Widget"
  12.         android:textSize="18sp" />
  13.     <Button
  14.         android:id="@+id/widget_button"
  15.         android:layout_width="wrap_content"
  16.         android:layout_height="wrap_content"
  17.         android:text="Update" />
  18. </LinearLayout>
复制代码

  • MyWidgetProvider,必要继续自AppWidgetProvider
  1. package com.example.kotlinlearn.RemoteView
  2. import android.app.PendingIntent
  3. import android.appwidget.AppWidgetManager
  4. import android.appwidget.AppWidgetProvider
  5. import android.content.ComponentName
  6. import android.content.Context
  7. import android.content.Intent
  8. import android.widget.RemoteViews
  9. import com.example.kotlinlearn.R
  10. import java.util.Random
  11. class MyWidgetProvider : AppWidgetProvider() {
  12.     override fun onUpdate(
  13.         context: Context,
  14.         appWidgetManager: AppWidgetManager,
  15.         appWidgetIds: IntArray
  16.     ) {
  17.         for (appWidgetId in appWidgetIds) {
  18.             val views = RemoteViews(context.packageName, R.layout.widget_layout)
  19.             val intent = Intent(context, MyWidgetProvider::class.java)
  20.             intent.setAction(BUTTON_CLICKED)
  21.             val pendingIntent = PendingIntent.getBroadcast(
  22.                 context,
  23.                 0,
  24.                 intent,
  25.                 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
  26.             )
  27.             views.setOnClickPendingIntent(R.id.widget_button, pendingIntent)
  28.             appWidgetManager.updateAppWidget(appWidgetId, views)
  29.         }
  30.     }
  31.     override fun onReceive(context: Context, intent: Intent) {
  32.         super.onReceive(context, intent)
  33.         if (BUTTON_CLICKED == intent.action) {
  34.             val appWidgetManager = AppWidgetManager.getInstance(context)
  35.             val views = RemoteViews(context.packageName, R.layout.widget_layout)
  36.             views.setTextViewText(R.id.widget_text, "Updated!" + Random().nextInt())
  37.             val componentName = ComponentName(context, MyWidgetProvider::class.java)
  38.             appWidgetManager.updateAppWidget(componentName, views)
  39.         }
  40.     }
  41.     companion object {
  42.         private const val BUTTON_CLICKED = "com.example.BUTTON_CLICKED"
  43.     }
  44. }
复制代码

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

  • 在manifest中设置receiver,与activity同级
  1.         <receiver android:name=".RemoteView.MyWidgetProvider" android:exported="true">
  2.             <intent-filter>
  3.                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
  4.             </intent-filter>
  5.             <meta-data
  6.                 android:name="android.appwidget.provider"
  7.                 android:resource="@xml/my_widget_info" />
  8.         </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企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表