如何在应用小部件中为Android AnalogClock设置时间? [英] How to set time to Android AnalogClock in app widget?
问题描述
如何将自定义时间设置为放置在应用小部件中的Android AnalogClock
?
How to set custom time to Android AnalogClock
placed in app widget?
作为替代方案,我正在考虑重写默认的AnalogClock,以通过代码设置时间.换句话说,我将创建自定义时钟,它从默认的View或AnalogClock扩展.然后将我的自定义Clock放在小部件布局UI上.
As an alternative I was thinking to override default AnalogClock to set the time through codes. Or in other words, I would create my custom Clock which extends from default View or AnalogClock. Then put my custom Clock on widget layout UI.
这可能吗?恐怕我们只能在RemoteViews上拥有自己的自定义组件.
Is this possible? I'm afraid we are limited on RemoteViews to have our own custom Component.
更新: 这是我最初遵循vArDo提供的解决方案的错误日志.
UPDATE: This is error log I have following the solution given by vArDo at first.
推荐答案
简介
无法在应用小部件中包含自定义视图. 根据文档只能使用很小的预定义视图子集在布局中.因此,正如您所提到的,不可能创建自己的AnalogClock
视图(如我在其他答案中所示)并将其包含在应用小部件中.
Intro
It's not possible to include custom views in app widgets. According to documentation only small predefined subset of views can be used in layout. So, as you've mentioned, it's not possible to create your own AnalogClock
view (as I've shown in my other answer) and include it in app widget.
但是,还有其他方法可用于在应用小部件中创建自定义AnalogClock
.在这种实现方式中,直接在AnalogClock
中设置时间应该不是问题.
However there are other means that can be used to create custom AnalogClock
in app widget. In such implementation setting time directly in AnalogClock
should not be a problem.
其中一种方法是将自定义AnalogClock
绘制到ImageView
中(这是应用程序小部件中允许的视图之一).重复PendingIntent
是使用Service
每60秒(通过RemoteViews
)将其拖入ImageView
.
One of the ways to accomplish this is draw custom AnalogClock
into ImageView
(which is one of the allowed views in app widgets). Repeating PendingIntent
is using Service
to draw into ImageView
every 60 seconds (via RemoteViews
).
请记住,每60秒通过RemoteViews
调用Service
动作来更新 app小部件并不是很轻便.在 Jelly Bean 上,示例实现在夜间使用了2%的电池(屏蔽,平均网络强度).但是,我一直每15秒更新一次屏幕,当涉及到模拟时钟时,这不是必需的.因此,一个粗略的估计是,每分钟更新一次的应用小部件在晚上将消耗大约0.5%的电池电量-这对您的用户来说可能很重要.
Keep in mind that invoking Service
action to update app widget via RemoteViews
every 60 seconds is not so lightweight on battery. On Jelly Bean example implementation used 2% of battery during night (screen off, average network strength). However, I've been updating the screen every 15 seconds, which is not necessary when it comes to analog clocks. So a rough estimate would be that an app widget with one update per minute will consume about 0.5% of battery juice during night - this might be significant for your users.
首先,您必须创建Service
,该图将吸引到视图中显示的ImageView
中.绘图代码几乎取自AnalogClock
实现,并根据需要进行重新排列.首先,没有检查时间是否已更改-这是因为Service
仅在我们也决定时(例如,每60秒)才被调用.第二点变化是我们从方法中的资源创建Drawable
.
First of all you'll have to create Service
that will draw into ImageView
present in your view. Drawing code is pretty much taken from AnalogClock
implementation and rearrange according to needs. First of all, there are no checks on whether time has changed - this is because Service
will be invoked only when we decide too (e.g. every 60 seconds). Seconds change is that we create Drawable
s from resources in the method.
另一个变化是代码使用Canvas
将模拟时钟引入本地Bitmap
:
Another change is that code draws analog clock into local Bitmap
using 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);
更新通过RemoteViews
被吸引到ImageView
中.汇总更改,然后将其推送到主屏幕上的应用程序小部件中-请参阅文档了解详情).在我们的情况下,只有一种更改,这是通过特殊方法完成的:
Update is drawn into ImageView
via RemoteViews
. Changes are aggregated and then pushed into app widget on home screen - see docs for details). In our case there is only one change, and it is done through special method:
remoteViews.setImageViewBitmap(R.id.imageView1, appWidgetBitmap);
请记住,要使代码正常工作,您必须声明可绘制模拟时钟的可用空间.根据widget_provider.xml
中声明的内容,可以确定ImageView
的尺寸.请注意,在绘制之前,您必须将dp
单位转换为px
单位:
Bare in mind that for code to work you have to declare what is available space for drawing your analog clock. Based on what is declare in your widget_provider.xml
, you can determine the dimensions of ImageView
. Note that you'll have to convert dp
unit to px
unit, before drawing:
// 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);
我在此处粘贴了Service
子类的完整代码.
I've pasted full code of Service
subclass here.
还在顶部,您将找到负责设置将要显示的时间的代码-根据需要进行修改:
Also at the top you'll find the code that is responsible for setting time that will be displayed - modify as needed:
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;
也不要忘记在您的AndroidManifest.xml
文件中声明此Service
和应用程序小部件,例如:
Also don't forget to declare this Service
and app widget in your AndroidManifest.xml
file, e.g.:
<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"/>
计划更新是在AppWidgetProvider
子类的onUpdate()
方法中完成的-在AndroidManifest.xml
文件中声明的on.从主屏幕删除应用程序小部件时,我们还需要删除PendingIntent
.这是通过覆盖的onDisabled()
方法完成的.记住要声明两个将调用每个方法之一的动作:APPWIDGET_UPDATE
和APPWIDGET_DISABLED
.请参见上面的AndroidManifest.xml
摘录.
Scheduling updates is done in onUpdate()
method of your AppWidgetProvider
subclass - the on that is declare in your AndroidManifest.xml
file. We'll also need to remove PendingIntent
when app widget is removed from home screen. This is done in overridden onDisabled()
method. Remember to declare both actions that will call one of each methods: APPWIDGET_UPDATE
and APPWIDGET_DISABLED
. See excerpt from AndroidManifest.xml
above.
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);
}
}
onUpdate()
方法的最后一行将重复事件安排为每60秒发生一次,并立即进行第一次更新.
Last line of onUpdate()
method schedules a repeating event to happen every 60 seconds, with first update to happen right away.
使用上面的代码,仅调用一次服务的最简单方法是及时安排单个事件,而不是重复一个事件.简单地将alarmManager.setRepeating()
调用替换为以下行:
Using above code the simplest way to invoke service only once is to schedule single event in time instead of repeating one. Simple replace alarmManager.setRepeating()
call with following line:
alarmManager.set(AlarmManager.RTC, time.getTime().getTime(), service);
结果
以下是使用自定义AnalogClock
应用程序小部件设置为仅设置一次时间的屏幕截图(注意模拟时钟时间与状态栏中显示的时间之间的差异):
Results
Below is a screen shot with custom AnalogClock
app widget that had time set only once (note difference between analog clock time and time shown in status bar):
这篇关于如何在应用小部件中为Android AnalogClock设置时间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!