桌面(小部件)widget注意事项

这几天想做一个开机后自动启动的一个服务,结果android8.1以后不允许静态注册广播的开机自动启动,所以我就想用widget桌面挂件来做,这个服务本身就正常服务不涉及用户隐私。完全后台开启服务android有好多限制,后面会介绍的到。

androidstudio 快捷创建一个widget

快捷创建一个widget系统会自动创建一个widget继承了AppWidgetProvider类的java文件,layout界面的xml文件(用于ui的显示),一个配置widget的文件。下面详细对这几个配置文件讲一下
在这里插入图片描述
在这里插入图片描述

widget 中java文件注意事项

widget运行在系统的进程里,widget继承了AppWidgetProvider类,根据跟人需要在相应回调的地方写入相应方法实现自己的功能。

onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) //系统更新小部件是回调到这里
 onDeleted(Context context, int[] appWidgetIds)//当用户删除小部件时,删除与之关联的偏好。
onEnabled(Context context)//进入相关功能时创建第一个小部件
onDisabled(Context context) //进入相关功能当最后一个部件是禁用的

widget主要任务是刷新窗口小部件的UI,但是正因为系统进程在这里面操作,刷新UI的事情并不是一件很容易的事,所以我们要建立一个服务,使用服务来刷新widget的界面。android8以后谷歌对后android进行了一些优化,一部分是针对后台服务的开启与关闭的。我在调试的时候就碰到了好多的困难。
在widget中正确开启服务的方法:只有使用startForegroundService()才能开启服务,开启服务后必须使用通知进行服务开启后对用户进行提示必须调用( startForeground(10, notification)😉,否则5秒钟后自动关闭服务,否则5秒钟后自动关闭服务,否则5秒钟后自动关闭服务。。(重要的事多说几遍)最恶心的是关闭服务并不报故障,为这事调了半天才找到原因。

    @Override
    public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
        Log.e("信息","刷新了小部件");
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        Intent bindIntent = new Intent(context, WidgetService.class);
        context.startForegroundService(bindIntent);//开启服务
    }

怎么能正确使用进行服务开启后对用户进行通知提示呢?代码如下:(加上这段代码就不会5秒关闭服务了)

 @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("信息", "onStartCommand()");
        // 在API11之后构建Notification的方式
        NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
        // 构建 Notification
        Notification.Builder builder = new Notification.Builder(getApplicationContext());
        builder.setContentTitle("控制管理")
                .setSmallIcon(R.mipmap.ic_launcher)//设置图标
                .setContentText("控制后台服务已经开启")
                .setDefaults(Notification.DEFAULT_ALL);//设置振铃

        // 兼容  API 26,Android 8.0
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // 第三个参数表示通知的重要程度,默认则只在通知栏闪烁一下
            NotificationChannel notificationChannel = new NotificationChannel("AppTestNotificationId", "AppTestNotificationName", NotificationManager.IMPORTANCE_DEFAULT);
            // 注册通道,注册后除非卸载再安装否则不改变
            notificationManager.createNotificationChannel(notificationChannel);
            builder.setChannelId("AppTestNotificationId");
        }
//        notificationManager.notify(10, builder.build());// 发出通知
        Notification notification = builder.build(); // 获取构建好的Notification
        startForeground(10, notification);// 开始前台服务
        return super.onStartCommand(intent, flags, startId);
    }

使用服务更新widget UI

废了半天劲终于可以开启更新服务了。name我们怎么跟他更新UI呢?使用RemoteViews这个类才能更新因为,RemoteViews这个类具有跨进程的能力。
但是我们的问题又来了,RemoteViews好多的控件和布局竟然不支持!!
支持的布局:

  • AdapterViewFlipper
  • FrameLayout
  • GridLayout
  • GridView
  • LinearLayout
  • ListView
  • RelativeLayout
  • StackView
  • ViewFlipper
    支持的控件:
  • AnalogClock
  • Button
  • Chronometer
  • ImageButton
  • ImageView
  • ProgressBar
  • TextClock
  • TextView
    如果上面的控件满足不了我们的要求,首先想到的是自定义view,但是添加上自定义view了无法加载控件,说明也不支持。那我们有什么办法呢?我们可以用ImageView模拟出来具体看下面的一段代码,下面代码的意思就是画一个画展示出来
    private void updateView(boolean state) {
        RemoteViews rViews = new RemoteViews(getPackageName(), R.layout.new_app_widget);
        rViews.setImageViewResource(R.id.widget_logo,R.mipmap.ic_launcher);//LOG显示
        rViews.setImageViewBitmap(R.id.hardware_view,getDeskClockIcon());
        // 刷新
        AppWidgetManager manager = AppWidgetManager.getInstance(getApplicationContext());
        ComponentName cName = new ComponentName(getApplicationContext(), NewAppWidget.class);
        manager.updateAppWidget(cName, rViews);
    }
 private Bitmap getDeskClockIcon() {
        //todo:好像是如果设置的比例不同拉伸的时候就会造成显示不全的问题
        //todo:只要符合比应该就能填充满这个view  记得在XML里面设置imageView属性 
        int widget_width=500;
        int widget_heigh=500;
        Bitmap widget_window = Bitmap.createBitmap(widget_width, widget_heigh, Bitmap.Config.ARGB_4444);//创建一个空间这个空间就是widget的大小
        Canvas canvas = new Canvas(widget_window);//widget窗口当做画布
        Paint paint=new Paint();//准备一个画笔
        //画一个边框
        paint.setARGB(125,255,255,255);//隐形红色
        paint.setStyle(Paint.Style.STROKE);//空心
        paint.setStrokeWidth((float) 30.0);//设置线宽
        RectF upperRectF=new RectF(0,0,widget_width,widget_width);//找到找到上半部分的绘图区
        canvas.drawRoundRect(upperRectF, 80, 80, paint);//画圆角矩形
        return widget_window;
    }

如何设置点击按钮弹出一个activity?


        //                                           需要开启的activity
        Intent startActivityIntent=new Intent(this ,SettingsActivity.class);
        // Intent实例化一个PendingIntent
        PendingIntent Pintent= PendingIntent.getActivity(this, 0, startActivityIntent, 0);
        RemoteViews ActivityView= new RemoteViews(getPackageName(), R.layout.new_app_widget);// 实例化RemoteView
        ActivityView.setOnClickPendingIntent(R.id.widget_logo, Pintent); //设置点击事件
        //更新控件
        AppWidgetManager manager = AppWidgetManager.getInstance(getApplicationContext());
        ComponentName cName = new ComponentName(getApplicationContext(), NewAppWidget.class);
        manager.updateAppWidget(cName, ActivityView);

widge窗口的信息(xml)配置

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"

    android:initialKeyguardLayout="@layout/new_app_widget"
    android:initialLayout="@layout/new_app_widget"
    android:minWidth="300dp"//窗口最小宽度
    android:minHeight="200dp"//窗口最小高度
    android:previewImage="@drawable/example_appwidget_preview"
    android:resizeMode="none"//是否可以改变窗口的大小 none代表不能
    android:updatePeriodMillis="1800000" //更新时间最小也得是三十分,
    android:widgetCategory="home_screen"></appwidget-provider>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值