代码下载http://download.csdn.net/detail/ldinvicible/5010177
一、桌面数字时钟控件效果图
二、
1、准备好一个Widget的显示布局文件 layout/widget.xml 内容如下
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="294dp" android:layout_height="72dp" android:background="@drawable/digtime" android:orientation="horizontal" > <TextView android:id="@+id/txt_time" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_marginLeft="8dp" android:layout_weight="3" android:gravity="center" android:textColor="#FFFFFF" android:textStyle="bold" android:textSize="50sp" /> <TextView android:id="@+id/txt_APM" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="right" android:layout_weight="1" android:layout_marginRight="14dp" android:textColor="#FFFFFF" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1" android:orientation="vertical" android:layout_marginRight="15dp" android:layout_gravity="center_horizontal"> <TextView android:id="@+id/txt_week" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="10dp" android:layout_gravity="left" android:textColor="#E8E118" android:textSize="18sp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="fill_parent" android:orientation="horizontal" android:layout_gravity="left" android:layout_marginTop="3dp"> <TextView android:id="@+id/txt_month" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="left" android:textColor="#E8E118" android:textSize="18sp" /> <TextView android:id="@+id/txt_day" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="right" android:textColor="#E8E118" android:textSize="18sp" android:layout_toRightOf="@id/txt_month" /> </LinearLayout> </LinearLayout> </LinearLayout>
2、准备好一个Widget的配置文件xml/provider_info.xml,该文件配置了widget可以占用的屏幕长宽、更新频率,所显示的布局文件(就是上面的那个布局文件)等.
<!-- android:minWidth:App Widget的最小宽度 android:minHeight:App Widget的最小高度 android:updatePeriodMillis:App Widget的更新频率 android:initialLayout:App Widget的初始化界面 --> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dp" android:minHeight="72dp" android:updatePeriodMillis="1000" android:initialLayout="@layout/appwidget_provider_clock" />
3、准备好一个处理widget请求的Java文件,继承了AppWidgetProvider类
package com.example.digitalclock; import java.util.Calendar; import java.util.Locale; import java.util.Timer; import java.util.TimerTask; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Message; import android.text.format.DateFormat; import android.util.Log; import android.widget.RemoteViews; public class ClockAppWidgetProvider extends AppWidgetProvider { private Context context; private AppWidgetManager appWidgetManager; private Timer timer; //月份 private String[] months = new String[]{"1 /", "2 /", "3 /", "4 /", "5 /", "6 /", "7 /", "8 /", "9 /", "10 /", "11 /", "12 /"}; //星期 private String[] weeks = new String[]{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { //创建定时器 timer = new Timer(); this.context = context; this.appWidgetManager = appWidgetManager; //进行周期性调度: 1s更新一次界面 timer.schedule(new TimerTask() { @Override public void run() { //通知更新界面 handler.sendEmptyMessage(0x123); } }, 0, 10); } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(msg.what == 0x123) { //构造RemoteViews对象 RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_clock); //构造显示时间日期 Calendar calendar = Calendar.getInstance(Locale.CHINA); calendar.setTimeInMillis(System.currentTimeMillis()); //构造当期显示时间 StringBuffer currentTime = new StringBuffer(""); int temp = calendar.get(Calendar.HOUR_OF_DAY); if(temp < 10) { currentTime.append("0").append(temp); } else { currentTime.append(temp); } temp = calendar.get(Calendar.MINUTE); if(temp < 10) { currentTime.append(" : ").append("0").append(temp); } else { currentTime.append(" : ").append(temp); } /*temp = calendar.get(Calendar.SECOND); if(temp < 10) { currentTime.append(":").append("0").append(temp); } else { currentTime.append(":").append(temp); } */ //设置显示当前时间 views.setTextViewText(R.id.txt_time, currentTime.toString()); //设置显示当前时间 AM PM String ampmValues; if(DateFormat.is24HourFormat(context)){ ampmValues = ""; } else{ if(calendar.get(Calendar.AM_PM) == 0){ ampmValues = "AM"; }else{ ampmValues = "PM"; } } views.setTextViewText(R.id.txt_APM, ampmValues); //设置显示当前月份 views.setTextViewText(R.id.txt_month, months[calendar.get(Calendar.MONTH)]); //设置显示当前星期 views.setTextViewText(R.id.txt_week, weeks[calendar.get(Calendar.WEEK_OF_MONTH)]); //设置显示当前日期 views.setTextViewText(R.id.txt_day, String.valueOf(calendar.get(Calendar.DAY_OF_MONTH))); //将当前的ClockAppWidgetProvider包装成ComponentName对象 ComponentName componentName = new ComponentName(context, ClockAppWidgetProvider.class); //更新App Widget appWidgetManager.updateAppWidget(componentName, views); } } }; }
4、androidMainfest文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.digitalclock" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="digitalclock" android:excludeFromRecents="true"> <intent-filter android:priority="1"> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <!-- 注册ClockAppWidgetProvider广播接收器 --> <receiver android:name=".ClockAppWidgetProvider"> <!-- 广播接收的action:当appwidget改变时 --> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <!-- 设置元数据:将ClockAppWidgetProvider类和AppWidgetProviderInfo对象appwidget_provider_time关联起来 --> <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_provider_time"/> </receiver> </application> </manifest>
以上桌面数字时钟控件就已经完成
参考http://blog.csdn.net/huliang7777/article/details/8448417
关于以上数字时钟有几个bug
1、到一定时间后,时间不在走,即停止更新
2、按setting中的设置时间选项,先使用12小时制,在反复按am、pm按钮,在返回到home界面,时间停止更新。
猜测:1、可能是handle message有性能问题()---也不是很清楚。
2、后来我使用了timer定时器直接更新界面appwidget,可是还是有问题,时间不走。
3、在后来使用了timer定时器在加上注册广播机制,可是很奇怪,依然不行。
4、最后使用了启动一个服务,在注册广播更新appwidget,代码见如下:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.digitalclock" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16" /> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <service android:name=".TimeService" android:enabled="true" > <intent-filter> <action android:name="com.example.digitalclock.TimeService" /> </intent-filter> </service> <!-- 注册ClockAppWidgetProvider广播接收器 --> <receiver android:name=".ClockAppWidgetProvider"> <!-- 广播接收的action:当appwidget改变时 --> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> <action android:name="com.wd.appWidgetUpdate"></action> <action android:name="android.intent.action.TIME_CHANGED"></action> <action android:name="android.intent.action.TIME_TICK"></action> <action android:name="android.intent.action.TIME_SET"></action> </intent-filter> <!-- 设置元数据:将ClockAppWidgetProvider类和AppWidgetProviderInfo对象appwidget_provider_time关联起来 --> <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_provider_time"/> </receiver> </application> </manifest>
package com.example.digitalclock; import java.util.Calendar; import java.util.Locale; import java.util.TimeZone; import java.util.Timer; import java.util.TimerTask; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.Message; import android.text.format.DateFormat; import android.util.Log; import android.widget.RemoteViews; public class ClockAppWidgetProvider extends AppWidgetProvider { private Context context; private AppWidgetManager WidgetManager; private Timer timer; static String TAG = "ClockAppWidgetProvider"; private RemoteViews views; int[] appWidgetIds; private static Timer myTimer; // 定义我们要发送的事件 private final String broadCastString = "com.wd.appWidgetUpdate"; // 月份 // 星期 private String[] months = new String[] { "01/", "02/", "03/", "04/", "05/", "06/", "07/", "08/", "09/", "10/", "11/", "12/" }; private String[] weeks = new String[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; // private String[] weeksid = new String[]{"Minggu", "Senin", "Selasa", // "Rabu", "Kamis", "Jumat", "Sabtu"}; private String[] weeksid = new String[] { "Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab" }; private String[] days = new String[] { "0", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "29", "30", "31" }; public void updateAppWidget(Context context) { // 构造RemoteViews对象 views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_clock); // 构造显示时间日期 Calendar calendar = Calendar.getInstance(TimeZone.getDefault()); calendar.setTimeInMillis(System.currentTimeMillis()); // 构造当期显示时间 StringBuffer currentTime = new StringBuffer(""); int temp = calendar.get(Calendar.HOUR_OF_DAY); // 设置显示当前时间 if (DateFormat.is24HourFormat(context)) { if (temp < 10) { currentTime.append("0").append(temp); } else { currentTime.append(temp); } } else// 12小时制 { Log.i(TAG, "00000000 temp ==" + temp); if (calendar.get(Calendar.AM_PM) == 0 && temp == 0) { currentTime.append(temp + 12); Log.i(TAG, "1111111111111111"); } else { Log.i(TAG, "2222222222222222222"); if (temp < 13) { if (temp < 10) { currentTime.append("0").append(temp); } else { currentTime.append(temp); } } else { temp -= 12; if (temp < 10) { currentTime.append("0").append(temp); } else { currentTime.append(temp); } } } } temp = calendar.get(Calendar.MINUTE); if (temp < 10) { currentTime.append(":").append("0").append(temp); } else { currentTime.append(":").append(temp); } Log.i(TAG, "currentTime.toString()" + currentTime.toString()); views.setTextViewText(R.id.txt_time, currentTime.toString()); // 设置显示当前时间 AM PM String ampmValues; if (DateFormat.is24HourFormat(context)) { ampmValues = ""; } else { if (calendar.get(Calendar.AM_PM) == 0) { ampmValues = "AM"; } else { ampmValues = "PM"; } } views.setTextViewText(R.id.txt_APM, ampmValues); // 设置显示当前月份 views.setTextViewText(R.id.txt_month, months[calendar.get(Calendar.MONTH)]); // 设置显示当前星期 // Locale locale = getResources().getConfiguration().locale; String language = Locale.getDefault().getLanguage(); if (language.endsWith("in")) { views.setTextViewText(R.id.txt_week, weeksid[calendar.get(Calendar.DAY_OF_WEEK) - 1]); } else { views.setTextViewText(R.id.txt_week, weeks[calendar.get(Calendar.DAY_OF_WEEK) - 1]); } // views.setTextViewText(R.id.txt_week, // String.valueOf(calendar.get(Calendar.DAY_OF_WEEK))); // 设置显示当前日期 if (calendar.get(Calendar.DAY_OF_MONTH) < 10) { views.setTextViewText(R.id.txt_day, days[calendar.get(Calendar.DAY_OF_MONTH)]); } else { views.setTextViewText(R.id.txt_day, String.valueOf(calendar.get(Calendar.DAY_OF_MONTH))); } /* * final int N = appWidgetIds.length; for(int i = 0; i < N; i++){ int * appWidgetId = appWidgetIds[i]; * WidgetManager.updateAppWidget(appWidgetIds, views); } * * final AppWidgetManager gm = AppWidgetManager.getInstance(context); if * (appWidgetIds != null) { Log.i(TAG, "appWidgetIds != null"); * gm.updateAppWidget(appWidgetIds, views); } else { Log.i(TAG, * "appWidgetIds == null"); gm.updateAppWidget(new * ComponentName(context, this.getClass()), views); } */ // 将当前的ClockAppWidgetProvider包装成ComponentName对象 // ComponentName componentName = new ComponentName(context, // ClockAppWidgetProvider.class); // 更新App Widget // AppWidgetManager.updateAppWidget(componentName, views); // 将该界面显示到插件中 AppWidgetManager appWidgetManager = AppWidgetManager .getInstance(context); ComponentName componentName = new ComponentName(context, ClockAppWidgetProvider.class); appWidgetManager.updateAppWidget(componentName, views); } @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub // 当判断到是该事件发过来时, 我们就获取插件的界面, 然后将index自加后传入到textview中 // System.out.println("onReceive"); Log.i(TAG, "onReceive"); Log.i(TAG, "intent.getAction()" + intent.getAction()); if (intent.getAction().equals(broadCastString) || intent.getAction().equals( "android.intent.action.TIME_CHANGED") || intent.getAction().equals("android.intent.action.TIME_TICK") || intent.getAction().equals("android.intent.action.TIME_SET")) { { // updateAppWidget(context); } } super.onReceive(context, intent); } @Override public void onEnabled(Context context) { // TODO Auto-generated method stub //super.onEnabled(context); // 在插件被创建的时候这里会被调用, 所以我们在这里开启一个timer 每秒执行一次 //MyTask mMyTask = new MyTask(context); //myTimer = new Timer(); //myTimer.schedule(mMyTask, 1000, 1000); //System.out.println("onEnabled2"); context.startService(new Intent(context, TimeService.class)); } class MyTask extends TimerTask { private Context mcontext = null; private Intent intent = null; public MyTask(Context context) { // 新建一个要发送的Intent mcontext = context; intent = new Intent(); intent.setAction(broadCastString); intent.setAction("android.intent.action.TIME_CHANGED"); intent.setAction("android.intent.action.TIME_TICK"); intent.setAction("android.intent.action.TIME_SET"); } @Override public void run() { System.out.println("2"); // 发送广播(由onReceive来接收) mcontext.sendBroadcast(intent); } } @Override public void onDisabled(Context context) { // TODO Auto-generated method stub context.startService(new Intent(context, TimeService.class)); } @Override public void onDeleted(Context context, int[] appWidgetIds) { // TODO Auto-generated method stub super.onDeleted(context, appWidgetIds); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { context.startService(new Intent(context, TimeService.class)); // 创建定时器 timer = new Timer(); this.context = context; WidgetManager = appWidgetManager; this.appWidgetIds = appWidgetIds; // 在插件被创建的时候这里会被调用, 所以我们在这里开启一个timer 每秒执行一次 // MyTask mMyTask = new MyTask(context); // myTimer = new Timer(); // myTimer.schedule(mMyTask, 1000, 1000); // 进行周期性调度: 1s更新一次界面 /*TimerTask task = new TimerTask(){ @Override public void run() { // TODO Auto-generated method stub updateAppWidget(ClockAppWidgetProvider.this.context); } }; timer.schedule(task, 1000, 1000); */ /* timer.schedule(new TimerTask() { public void run() { // 通知更新界面 //handler.sendEmptyMessage(0x123); updateAppWidget(ClockAppWidgetProvider.this.context); } }, 0, 1000);*/ /* handler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub handler.sendEmptyMessage(0x123); handler.postDelayed(this, 1000); } }); */ } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 0x123) { // 构造RemoteViews对象 views = new updateAppWidget(context); } } }; }
package com.example.digitalclock; import java.util.Calendar; import java.util.Locale; import java.util.TimeZone; import android.app.Service; import android.appwidget.AppWidgetManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; import android.text.format.DateFormat; import android.util.Log; import android.widget.RemoteViews; public class TimeService extends Service { static String TAG = "ClockAppWidgetProvider"; private RemoteViews views; // 月份 // 星期 private String[] months = new String[] { "01/", "02/", "03/", "04/", "05/", "06/", "07/", "08/", "09/", "10/", "11/", "12/" }; private String[] weeks = new String[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; // private String[] weeksid = new String[]{"Minggu", "Senin", "Selasa", // "Rabu", "Kamis", "Jumat", "Sabtu"}; private String[] weeksid = new String[] { "Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab" }; private String[] days = new String[] { "0", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "29", "30", "31" }; @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub Log.i(TAG, "onCreate"); startClockListener(); } @Override public void onDestroy() { // TODO Auto-generated method stub unregisterReceiver(this.timeReceiver); } @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub super.onStart(intent, startId); } private BroadcastReceiver timeReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { Log.i(TAG, "onReceive 11111 intent.getAction()"+intent.getAction()); if ("android.intent.action.TIMEZONE_CHANGED".equals(intent.getAction()) ||"android.intent.action.TIME_TICK".equals(intent.getAction()) ||"android.intent.action.TIME_CHANGED".equals(intent.getAction()) ||"android.intent.action.TIME_SET".equals(intent.getAction())) { updateAppWidget(); } } }; public void startClockListener() { Log.i(TAG, "startClockListener"); IntentFilter localIntentFilter = new IntentFilter(); localIntentFilter.addAction("android.intent.action.TIME_TICK"); localIntentFilter.addAction("android.intent.action.TIME_CHANGED"); localIntentFilter.addAction("android.intent.action.TIMEZONE_CHANGED"); localIntentFilter.addAction("android.intent.action.TIME_SET"); registerReceiver(this.timeReceiver, localIntentFilter); } public void updateAppWidget() { Log.i(TAG, "updateAppWidget"); // 构造RemoteViews对象 views = new RemoteViews(getApplicationContext().getPackageName(), R.layout.appwidget_provider_clock); // 构造显示时间日期 Calendar calendar = Calendar.getInstance(TimeZone.getDefault()); calendar.setTimeInMillis(System.currentTimeMillis()); // 构造当期显示时间 StringBuffer currentTime = new StringBuffer(""); int temp = calendar.get(Calendar.HOUR_OF_DAY); // 设置显示当前时间 if (DateFormat.is24HourFormat(getApplicationContext())) { if (temp < 10) { currentTime.append("0").append(temp); } else { currentTime.append(temp); } } else// 12小时制 { Log.i(TAG, "00000000 temp ==" + temp); if (calendar.get(Calendar.AM_PM) == 0 && temp == 0) { currentTime.append(temp + 12); Log.i(TAG, "1111111111111111"); } else { Log.i(TAG, "2222222222222222222"); if (temp < 13) { if (temp < 10) { currentTime.append("0").append(temp); } else { currentTime.append(temp); } } else { temp -= 12; if (temp < 10) { currentTime.append("0").append(temp); } else { currentTime.append(temp); } } } } temp = calendar.get(Calendar.MINUTE); if (temp < 10) { currentTime.append(":").append("0").append(temp); } else { currentTime.append(":").append(temp); } Log.i(TAG, "currentTime.toString()" + currentTime.toString()); views.setTextViewText(R.id.txt_time, currentTime.toString()); // 设置显示当前时间 AM PM String ampmValues; if (DateFormat.is24HourFormat(getApplicationContext())) { ampmValues = ""; } else { if (calendar.get(Calendar.AM_PM) == 0) { ampmValues = "AM"; } else { ampmValues = "PM"; } } views.setTextViewText(R.id.txt_APM, ampmValues); // 设置显示当前月份 views.setTextViewText(R.id.txt_month, months[calendar.get(Calendar.MONTH)]); // 设置显示当前星期 // Locale locale = getResources().getConfiguration().locale; String language = Locale.getDefault().getLanguage(); if (language.endsWith("in")) { views.setTextViewText(R.id.txt_week, weeksid[calendar.get(Calendar.DAY_OF_WEEK) - 1]); } else { views.setTextViewText(R.id.txt_week, weeks[calendar.get(Calendar.DAY_OF_WEEK) - 1]); } // views.setTextViewText(R.id.txt_week, // String.valueOf(calendar.get(Calendar.DAY_OF_WEEK))); // 设置显示当前日期 if (calendar.get(Calendar.DAY_OF_MONTH) < 10) { views.setTextViewText(R.id.txt_day, days[calendar.get(Calendar.DAY_OF_MONTH)]); } else { views.setTextViewText(R.id.txt_day, String.valueOf(calendar.get(Calendar.DAY_OF_MONTH))); } /* * final int N = appWidgetIds.length; for(int i = 0; i < N; i++){ int * appWidgetId = appWidgetIds[i]; * WidgetManager.updateAppWidget(appWidgetIds, views); } * * final AppWidgetManager gm = AppWidgetManager.getInstance(context); if * (appWidgetIds != null) { Log.i(TAG, "appWidgetIds != null"); * gm.updateAppWidget(appWidgetIds, views); } else { Log.i(TAG, * "appWidgetIds == null"); gm.updateAppWidget(new * ComponentName(context, this.getClass()), views); } */ // 将当前的ClockAppWidgetProvider包装成ComponentName对象 // ComponentName componentName = new ComponentName(context, // ClockAppWidgetProvider.class); // 更新App Widget // AppWidgetManager.updateAppWidget(componentName, views); // 将该界面显示到插件中 AppWidgetManager appWidgetManager = AppWidgetManager .getInstance(getApplicationContext()); ComponentName componentName = new ComponentName(getApplicationContext(), ClockAppWidgetProvider.class); appWidgetManager.updateAppWidget(componentName, views); } }
其他地方更以前一样