如何在应用小部件中为Android AnalogClock设置时间? [英] How to set time to Android AnalogClock in app widget?

查看:112
本文介绍了如何在应用小部件中为Android AnalogClock设置时间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将自定义时间设置为放置在应用小部件中的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 Drawables 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_UPDATEAPPWIDGET_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆