如何在app小部件中设置Android AnalogClock的时间?

stu*_*low 0 layout android components widget android-appwidget

如何AnalogClock在app小部件中设置Android的自定义时间?

作为替代方案,我正在考虑覆盖默认的AnalogClock来设置代码的时间.换句话说,我会创建自定义时钟,它从默认的View或AnalogClock扩展.然后将我的自定义时钟放在小部件布局UI上.

这可能吗?我担心RemoteViews会限制我们自己的自定义组件.

更新: 这是错误日志我首先遵循vArDo给出的解决方案.

在此输入图像描述

vAr*_*rDo 6

介绍

在app小部件中包含自定义视图是不可能的.根据文档,在布局中只能使用小的预定义视图子集.所以,正如你所提到的,不可能创建自己的AnalogClock视图(正如我在其他答案中所示)并将其包含在app小部件中.

但是,还有其他方法可用于AnalogClock在app小部件中创建自定义.在这样的实现中,设置时间直接AnalogClock应该不成问题.

简短的回答

其中一个做到这一点的方法之一是借鉴自AnalogClock成ImageView(这是在应用小部件允许的景色之一).重复PendingIntent使用每60秒Service画ImageView一次(通过RemoteViews).

电池使用注意事项

请记住,调用Service操作以更新的应用程序插件通过RemoteViews每隔60秒不上电池,所以重量轻.在Jelly Bean示例实施中,夜间使用2%的电池(屏幕关闭,平均网络强度).但是,我每隔15秒就更新一次屏幕,这在模拟时钟方面是不必要的.因此粗略估计,每晚更新一次的应用程序小部件将在夜间消耗大约0.5%的电量 - 这对您的用户来说可能很重要.

解决方案细节

更改绘图服务

首先,您必须创建Service将ImageView在您的视图中绘制的内容.绘图代码几乎取决于AnalogClock实现,并根据需要重新排列.首先,没有检查时间是否已经改变 - 这是因为Service只有在我们决定时才会调用(例如每60秒).第二个变化是我们Drawable从方法中的资源创建s.

另一个变化是代码Bitmap使用Canvas以下方法将模拟时钟绘制到本地

    // Creating Bitmap and Canvas to which analog clock will be drawn.
    Bitmap appWidgetBitmap = Bitmap.createBitmap(availableWidth, availableHeight, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(appWidgetBitmap);
Run Code Online (Sandbox Code Playgroud)

更新被吸引到ImageViewvia RemoteViews.汇总更改,然后将其推送到主屏幕上的应用小部件 - 有关详细信息,请参阅文档.在我们的例子中,只有一个变化,它通过特殊方法完成:

    remoteViews.setImageViewBitmap(R.id.imageView1, appWidgetBitmap);
Run Code Online (Sandbox Code Playgroud)

请记住,要使代码工作,您必须声明绘制模拟时钟的可用空间.根据您声明的内容widget_provider.xml,您可以确定尺寸ImageView.请注意,在绘制之前,您必须将dp单位转换为px单位:

    // You'll have to determine tour own dimensions of space to which analog clock is drawn.
    final int APP_WIDGET_WIDTH_DP = 210; // Taken from widget_provider.xml: android:minWidth="210dp"
    final int APP_WIDGET_HEIGHT_DP = 210; // Taken from widget_provider.xml: android:minHeight="210dp"

    final int availableWidth = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, APP_WIDGET_WIDTH_DP, r.getDisplayMetrics()) + 0.5f);
    final int availableHeight = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, APP_WIDGET_HEIGHT_DP, r.getDisplayMetrics()) + 0.5f);
Run Code Online (Sandbox Code Playgroud)

我在这里粘贴了Service子类的完整代码.

同样在顶部,您将找到负责设置将显示的时间的代码 - 根据需要进行修改:

    mCalendar = new Time();

    // Line below sets time that will be displayed - modify if needed.
    mCalendar.setToNow();

    int hour = mCalendar.hour;
    int minute = mCalendar.minute;
    int second = mCalendar.second;

    mMinutes = minute + second / 60.0f;
    mHour = hour + mMinutes / 60.0f;
Run Code Online (Sandbox Code Playgroud)

另外,不要忘记Service在AndroidManifest.xml文件中声明此和app小部件,例如:

    <receiver 
        android:name="TimeSettableAnalogClockAppWidget"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name">

        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
            <action android:name="android.appwidget.action.APPWIDGET_DISABLED"/>
        </intent-filter>

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

    </receiver>
    <service android:name="TimeSettableAnalogClockService"/>
Run Code Online (Sandbox Code Playgroud)

有关使用服务更新应用小部件的最重要信息,请参阅此博客文章.

调用绘图

调度更新是在onUpdate()您的AppWidgetProvider子类的方法中完成的- 在您的AndroidManifest.xml文件中声明的on .PendingIntent当从主屏幕移除app小部件时,我们还需要删除.这是在重写onDisabled()方法中完成的.请记住声明将调用每种方法之一的两个操作:APPWIDGET_UPDATE和APPWIDGET_DISABLED.见AndroidManifest.xml上面的摘录.

package com.example.anlogclocksettimeexample;

import java.util.Calendar;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;

public class TimeSettableAnalogClockAppWidget extends AppWidgetProvider {

    private PendingIntent service = null;

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
//      super.onUpdate(context, appWidgetManager, appWidgetIds);
        final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

        final Calendar time = Calendar.getInstance();
        time.set(Calendar.SECOND, 0);
        time.set(Calendar.MINUTE, 0);
        time.set(Calendar.HOUR, 0);

        final Intent intent = new Intent(context, TimeSettableAnalogClockService.class);

        if (service == null) {          
            service = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        }

        alarmManager.setRepeating(AlarmManager.RTC, time.getTime().getTime(), 1000 * 60 /* ms */, service);
    }

    @Override
    public void onDisabled(Context context) {
        final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(service);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一行onUpdate()方法安排重复事件每60秒发生一次,第一次更新立即发生.

AnalogClock仅绘制一次

使用上面的代码,只调用一次服务的最简单方法是及时安排单个事件而不是重复一个.alarmManager.setRepeating()用以下行简单替换呼叫:

alarmManager.set(AlarmManager.RTC, time.getTime().getTime(), service);
Run Code Online (Sandbox Code Playgroud)

结果

下面是一个自定义AnalogClock应用程序窗口小部件的屏幕截图,其时间只设置一次(注意状态栏中显示的模拟时钟时间和时间之间的差异):

在此输入图像描述