欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android widget 开发

程序员文章站 2022-03-11 10:57:28
...

   因为项目中需要用到widget,所以在这里大致记录一下widget的使用流程。因为没有深入的研究,所以仅仅是做一个大概的解析,因为需求简单,这里就不介绍RemoteViewService和RemoteViewFactory了,如果需要的不要浪费时间看下去,抱歉各位。widget也叫小部件,是一个微型视图,其实在手机launcher中的表就是个widget。在开始流程之前需要明白两个概念:

    AppWidgetProviderInfo

描述小部件的元数据元素,包括描述了部件的布局和更新频率,以及AppWidgetProvider的信息

   AppWidgetProvider

基于广播事件,,在这里可以对widget进行一些操作,包括widget的启用,更新,删除等操作。因为继承自BroadcastReceiver,因此也可以根据最基本的广播操作来进行事件的处理。

   接下来就是开始创建widget,其实过程比较简单,studio提供了很多帮助:

android widget 开发

     在这里直接创建widget,填写细节之后,就会生成一个继承自AppWidgetProvider的类,

public class MyWidget extends AppWidgetProvider {

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {

        //在这里进行部件的更新。需要怎样操控部件都可以再这里通过RemoteViews实现。
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        //这里会遍历所有的部件,然后都进行更新。
        for (int appWidgetId : appWidgetIds) {

            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }

    @Override
    public void onEnabled(Context context) {
        // 当widget被创建的时候调用。
    }

    @Override
    public void onDisabled(Context context) {
        // Enter relevant functionality for when the last widget is disabled
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        //这里可以接收自定义的一些广播,进行处理。
    }
}

     同时在androidManifest文件中也会生成MyWidget的注册内容

<receiver
            android:name=".widget.MyWidget"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <!-- 在这里还可以添加其他自定义的广播 -->
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <!-- widget的配置信息文件 -->
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/new_app_widget_info" />
        </receiver>

   其中name属性表明类名,intent-filter表示的是接收的广播action,meta中的属性name表示meta-data的名称,这里必须是android.appwidget.provider, resource这里是表示资源文件的目录。接下来看资源文件:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialKeyguardLayout="@layout/new_app_widget"
    android:initialLayout="@layout/new_app_widget"
    android:minHeight="170dp"
    android:minWidth="250dp"
    android:previewImage="@drawable/example_appwidget_preview"
    android:resizeMode="horizontal|vertical"
    android:updatePeriodMillis="86400000"
    android:widgetCategory="home_screen"></appwidget-provider>

     initialkeyguardlayout表示了一个资源文件,在widget创建的时候可以立刻出现。4.2以后引入的。

     initialLayout 表示了widget的资源文件。

     minHeight和minWidth定义了widget的最小高和宽,低于这个值widget不可以用。

     previewImage这个就是一个预览图的效果。就像app的桌面logo,默认是applogo。

     resizeMode:指定widget大小在哪个方向调整。

     updatePerionMillis:这个只的是部件的更新频率,最小是半小时,设置的很小也会默认为半小时。

     widgetCategory:表示部件是否可以显示在主屏上,默认home_screen,还有power属性。

     到这里就可以通过new_app_widget这个布局文件来写小部件的布局了。需要注意的是这个布局文件支持的控件是有限制的, 首先自定义的控件不支持, 支持的布局控件如下:

     布局:FrameLayout,RelativeLayout,Linearlayout,GridLayout

     控件:Button,ImageButton, ImageView,TextView,ListView,GridView,AnalogClock,Progressbar,ViewFlpper,StackView

     更新部件的功能都是通过RemoteView来实现的,至于怎样更新可以根据自己的需求来定。如果用到listview,gridview等布局可以通过RemoteviewService来实现这个部件的更新,在我的项目里比较简单,直接通过启动一个service进行来更新:在MyWidget中的onenable中通过启动一个service来实现更新,

private void updateWidget(Context context, WeatherWrap weatherWrap) {
        if (weatherWrap == null) {
            return;
        }
        ComponentName componentName = new ComponentName(context, WeatherWidget.class);
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);

        remoteViews.setTextViewText(R.id.temperature, weatherWrap.getNow().getTemp()+"°C");
        remoteViews.setTextViewText(R.id.weather_status, DBHelper.getInstance().getWeatherTypeByCode(
                weatherWrap.getNow().getWeatherType()));
        remoteViews.setTextViewText(R.id.city, weatherWrap.getRegion());


        remoteViews.setTextViewText(R.id.air_quality, weatherWrap.getAqi().getAqi() + " "
                + weatherWrap.getAqi().getQuality());

        if (weatherWrap.getSuggestion().getDressing() != null) {
            remoteViews.setTextViewText(R.id.clothing_index, weatherWrap.getSuggestion().getDressing().getBrief());
        }
        remoteViews.setTextViewText(R.id.humidity, weatherWrap.getNow().getHumidity() + "%");

        if(weatherWrap.getSuggestion().getHongfans() != null){
            remoteViews.setTextViewText(R.id.env_status,weatherWrap.getSuggestion().getHongfans().getDetails());
        }

        remoteViews.setImageViewResource(R.id.weather_bg, Utils.weatherCode2BG(weatherWrap.getNow().getWeatherType()));

        //在这里添加一个点击事件,当点击id为city的按钮会跳转到制定activity
        Intent intent = new Intent(context, WeatherActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
        remoteViews.setOnClickPendingIntent(R.id.city, pendingIntent);

        AppWidgetManager awm = AppWidgetManager.getInstance(context.getApplicationContext());
        awm.updateAppWidget(componentName, remoteViews);
    }

        可以看到remoteVIew的设置控件内容的方式,以及点击跳转的方式。最后都需要通过AppWidgetManager来进行更新。在MyWidget文件的updateAppWidget()函数中也需要添加好更新widget的方法。至于具体的更新方式要根据自己的项目需求而定。