android 桌面widget开发

   widget开发以桌面日历widget为例:
在这个例子中主要分为四个内容:
①、继承AppWidgetProvider类,命名为CalendarWidgetProvider,在该类中完成接收接收广播、启动更新时间的服务、更新widget显示。
②、在AndroidManifest.xml中声明广播接收类,和相应的action。
③、在res下创建xml文件夹,并在其中创建AppWidgetProviderInfo数据元的xml文件。在该xml文件中主要设定Widget大小和更新时间,由于系统默认是30分钟更新且设定小于30分钟更新不会生效,所以在CalendarWidgetProvider采用接收系统时间改变的广播用于更新Widget。
④、定义用于更新时间的Service类UpdateService,该类继承了Service,该服务中主要完成发送time_ticker广播。
⑤、定义一个用于获得日期和时间的工具类。
 
     首先定义一个继承AppWidgetProvider的类CalendarWidgetProviderAppWidgetProvider类是BroadcastReceiver的子类,所以它实质上是一个广播接收者。在CalendarWidgetProvider类中,主要完成三个功能:启动发送time_ticker的广播的服务,接收广播,更新widget显示。在该类中,首先应override onReceive() 方法,用于接收广播,在桌面日历应用中应接收四种广播,该广播都在AndroidManifest.xml文件中注册。
      <receiver
            android:name="com.nwd.android.calendarwidget.CalendarWidgetProvider"
            android:enabled="true"
            android:icon="@drawable/ic_launcher" >
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/calendarwidgetinfo" />

            <intent-filter>
                <action android:name="android.intent.action.DATE_CHANGED" />
                <action android:name="android.intent.action.TIME_SET" />
                <action android:name="com.nwd.android.calendarwidget.timetick" />
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
        </receiver>
< receiver > 中的name标志了接收广播的类 CalendarWidgetProvider < meta-data>adnroid:resource 指定了widget的大小等特性。calendardrawwidgetinfo文件如下:
<?xml version="1.0" encoding= "UTF-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="200dp"
    android:minHeight="100dp"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/main" >
</appwidget-provider>
    CalendarWidgetProvider 类如下
public class CalendarWidgetProvider extends AppWidgetProvider {

    // 系统日期改变接收的广播的action
    private static final String DATE_CHANGED = Intent.ACTION_DATE_CHANGED ;
    // 系统时间改变接收的广播的action
    private static final String TIME_CHANGED = Intent.ACTION_TIME_CHANGED ;
    // 接收UpdateService转发的TIME_TICK的广播
    private static final String TIME_TICK = "com.nwd.android.calendarwidget.timetick" ;
    // public static String TAG = "CalendarWidgetProvider";
    private RemoteViews mRv;
    public static final boolean DEBUG = true;
    private static final JLog LOG = new JLog("CalendarWidgetProvider" ,
            CalendarWidgetProvider.DEBUG, JLog. TYPE_DEBUG);

    @Override
    public void onEnabled(Context context) {
        // TODO Auto-generated method stub
        super.onEnabled(context);
        LOG.print("CalendarWidgetProvider.onEnabled()" );
        context.startService( new Intent(context, UpdateService.class));
    }

    /**
     * 接收到广播根据相应的action转换相应的View
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        super.onReceive(context, intent);
        String action = intent.getAction();
        LOG.print("CalendarWidgetProvider.onReceive() " + action);

        if (mRv == null) {
            mRv = new RemoteViews(context.getPackageName(), R.layout.main);
        }
        DateUtil util = DateUtil. getInstance(context);
        // 获取日期字符串
        String date = util.getDate();
        // 获取星期几
        String weekDay = util.getWeekDay();
        // 接收到DATE_CHANGED的系统广播
        if (DATE_CHANGED .equals(action)) {
            LOG.print("CalendarWidgetProvider.onReceive() " + date);
            updateDate( mRv, weekDay, date);
            LOG.print(date);
        }
        // 接收到TIME_CHANGED的系统广播
        if (TIME_CHANGED .equals(action)) {
            LOG.print("CalendarWidgetProvider.onReceive() " + date);
            updateDate( mRv, weekDay, date);
            updateTime(context, mRv);
            LOG.print(date);
        }
        // 接收到TIME_TICK的系统广播
        if (TIME_TICK .equals(action)) {
            updateTime(context, mRv);
            updateDate( mRv, weekDay, date);
        }
        AppWidgetManager appWidgetManager = AppWidgetManager
        . getInstance(context);
        int[] appIds = appWidgetManager.getAppWidgetIds(new ComponentName(
        context, CalendarWidgetProvider.class));
        appWidgetManager.updateAppWidget(appIds, mRv);
        LOG.print(date);
    }

    /**
     * 更新widget上面所有的view
     */
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        // TODO Auto-generated method stub
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        for (int i = 0; i < appWidgetIds.length; i++) {

            if (mRv == null) {
                mRv = new RemoteViews(context.getPackageName(), R.layout.main);
            }
//            Intent intent = new Intent(context, UpdateService.class);
//            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
//                    intent, 0);
            DateUtil util = DateUtil. getInstance(context);
            String date = util.getDate();
            String weekDay = util.getWeekDay();
            updateTime(context, mRv);
            updateDate( mRv, weekDay, date);
//             设置更新时间
//            AlarmManager alarm = (AlarmManager) context
//                    .getSystemService(Context.ALARM_SERVICE);
//            alarm.setRepeating(AlarmManager.RTC_WAKEUP,
//                    System.currentTimeMillis(), 60 * 1000, pendingIntent);
           
            //设置widget的点击事件,当点击时进入Calendar
            Intent LaunchCalendarIntent = new Intent();
            LaunchCalendarIntent.setClassName( "com.android.calendar",
                    "com.android.calendar.LaunchActivity" );
            PendingIntent luanchPendingIntent = PendingIntent.getActivity(
                    context, 0, LaunchCalendarIntent, 0);
            mRv.setOnClickPendingIntent(R.id.time_linearlayout,
                    luanchPendingIntent);
            appWidgetManager.updateAppWidget(appWidgetIds, mRv);
            LOG.print(date);
        }
    }

    // 更新widget上面的日期
    public void updateDate(RemoteViews rv, String weekDay, String date) {
        rv.setTextViewText(R.id. date, "" + date);
        rv.setTextViewText(R.id. week, "" + weekDay);
    }

    // 更新widget上面的时间
    public void updateTime(Context context, RemoteViews rv) {

        DateUtil util = DateUtil. getInstance(context);
        int hour = util.getHour();
        int minute = util.getMinute();
        if (!util.is24()) {
            if (hour > 12) {
                hour -= 12;
            }
            if (hour == 0) {
                hour = 12;
            }
        }
        if (minute < 10) {
            rv.setTextViewText(R.id. minute, "0" + minute);
        } else {
            rv.setTextViewText(R.id. minute, "" + minute);
        }
        rv.setTextViewText(R.id. hour, "" + hour);

    }

}
     在onEnabled()方法中,启动服务 UpdateService,该服务主要用来广播time_tick。onReceive() 方法根据不同的广播改变widget的显示。upDate()方法用来完成widget的更新,同时,在该方法中设置了整个widget的点击事件,当widget被点击时,会调用系统的日历,进入日历的显示界面。
     在该widget项目中还定义了两个类,上面提到的的服务UpdateService和一个工具类DateUtil。两个类的作用分别是:发time_tick广播,获取当前日期时间的工具。
UpdateService  类如下:
public class UpdateService extends Service {
    public static final boolean DEBUG = true;
    private static final JLog LOG = new JLog("UpdateService" , UpdateService.DEBUG , JLog.TYPE_DEBUG);
    private BroadcastReceiver receiver;

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null ;
    }

    /**
     * 创建服务并动态注册系统的ACTION_TIME_TICK服务
     */
    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        LOG.print("UpdateService.onCreate()" );
        // 实例化接收系统ACTION_TIME_TICK的BroadcastReceiver
        receiver = new BroadcastReceiver(){
            private static final String ACTION_TIME_TICK = Intent.ACTION_TIME_TICK ;
           
            @Override
            public void onReceive(Context context, Intent intent) {
                // TODO Auto-generated method stub
                LOG.print("UpdateService.onReceive()" );
               
                if(intent.getAction().equals(ACTION_TIME_TICK)){//注意:使用的是equals方法,不是"=="
                    Intent tmp = new Intent();
                    tmp.setAction("com.nwd.android.calendarwidget.timetick" );
                    LOG.print("TIME_TICK" );
                    context.sendBroadcast(tmp);
                }
            }
           
        };
        this.registerReceiver(receiver , new IntentFilter(Intent.ACTION_TIME_TICK ));
       
    }

    /**
     * 在onDestroy()方法里面重启UpdateService
     */
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        //this.unregisterReceiver(receiver);
        Intent intent = new Intent();
        intent.setClass( this, UpdateService.class);
        startService(intent);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub
        return START_STICKY ;
    }

}
DateUtil 类如下:
public class DateUtil {
    private Context context;
    // 记录系统时间格式(分为12小时制和24小时制)
    private SimpleDateFormat formatter;
    private static DateUtil instance;
   
    /**
     * 生成单例模型并初始化系统时间格式
     * @param context
     */
    private DateUtil(Context context){
        this.context = context;
        formatter = new SimpleDateFormat("MM/dd");
    }
   
    public boolean is24(){
        return DateFormat.is24HourFormat( context);
    }
   
   
    /**
     * 获取时间的小时数,默认为24小时制
     * @return
     */
    public int getHour(){
        Calendar c = Calendar. getInstance();
        return c.get(Calendar.HOUR_OF_DAY);
    }
   
    /**
     * 获取时间的分钟数
     * @return
     */
    public int getMinute(){
        Calendar c = Calendar. getInstance();
        return c.get(Calendar.MINUTE);
    }
   
    /**
     * 获取当前年份
     * @return
     */
    public int getYear(){
        Calendar c = Calendar. getInstance();
        return c.get(Calendar.YEAR);
    }
   
    /**
     * 获取当前月份
     * @return
     */
    public int getMonth(){
        Calendar c = Calendar. getInstance();
        return c.get(Calendar.MONTH);
    }
   
    /**
     * 获取所在月的天数
     * @return
     */
    public int getDayOfMonth(){
        Calendar c = Calendar. getInstance();
        return c.get(Calendar.DAY_OF_MONTH);
    }
   
    /**
     * 重新设置系统时间格式
     */
    public void setDateFormat(SimpleDateFormat formatter){
        this.formatter = formatter;
    }
   
    public static DateUtil getInstance(Context context){
        if(instance == null){
            instance = new DateUtil(context);
           
            return instance ;
        } else{
            return instance ;
        }
    }
   
    /**
     * 获取系统日期
     * @return 返回格式如2014/6/24
     */
    public String getDate(){
        Date curDate = new Date(System.currentTimeMillis());
        String date = formatter.format(curDate);
        return date;
    }
   
   
    /**
     *
     * @return 当前日期是星期几
     */
    public String getWeekDay(){
        String weekDay = "";
        Calendar c = Calendar. getInstance();
       
        int day = c.get(Calendar.DAY_OF_WEEK);
        String weekdays[] = context.getResources().getStringArray(R.array.weekdays);
        switch(day){
        case 1:
            weekDay = weekdays[0];
            break;
        case 2:
            weekDay = weekdays[1];
            break;
        case 3:
            weekDay = weekdays[2];
            break;
        case 4:
            weekDay = weekdays[3];
            break;
        case 5:
            weekDay = weekdays[4];
            break;
        case 6:
            weekDay = weekdays[5];
            break;
        case 7:
            weekDay = weekdays[6];
            break;
        default:
           
        }
       
        return weekDay;
    }
}
最后Layout布局文件如下:
<?xml version="1.0" encoding= "utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/time_linearlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:background="@android:color/holo_blue_bright"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="129dp"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/hour"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="60dp"
            android:layout_gravity="center_vertical"
            android:text="@string/hour"
            android:textColor="@android:color/white"
            android:textSize="60sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@string/semicolon"
            android:textColor="@android:color/white"
            android:textSize="60sp" />

        <TextView
            android:id="@+id/minute"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@string/minute"
            android:textColor="@android:color/white"
            android:textSize="60sp" />
    </LinearLayout >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="43dp"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/week"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="left"
            android:layout_marginLeft="20dp"
            android:text="@string/week"
            android:textColor="@android:color/white"
            android:textSize="25sp" />

        <TextView
            android:id="@+id/date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="95dp"           
            android:text="@string/date"
            android:textColor="@android:color/white"
            android:textSize="25sp" />
    </LinearLayout >

</LinearLayout>
  widget显示的效果





你可能感兴趣的:(android,日历,widget)