Android自定义View之widget桌面小控件: 我可以控件时间啦


先上效果图:

实现原理


玩了这么久的安卓,一直想要自己的一个桌面小控件,显示时间、温度之类的,今天雅致来了,就学习了,今天就写在这里了。


安卓桌面小控件大家都知道,即使源程序被用户抹杀掉、退出了程序,它依然在更新数据。这到底是为啥呢?原理很简单,这个小控件就是一个广播的原理,在此同时,我们需要新建一个服务类来更新这个小控件的UI数据,并且谷歌在为安卓特意有个广播的Action。后台服务来发出广播,这个小控件就接收更新数据,可以这样子理解。所以,即使源程序退出来了,它依然在后台更新数据啦。


新建一个wigdet的配置xml文件。


android:initialLayout="@layout/new_app_widget"表示的 是你要展
示的布局。


android:minHeight="300dp"表示的是控件的最小控件的高度的大小。


android:minWidth="400dp"表示的是控件最小的 宽度展示大小。


android:updatePeriodMillis="8640000" 它定义了 widget 的更新频率。实际的更新时机不一定是精确的按照这个时间发生的。建议更新尽量不要太频繁,最好是低于1小时一次。 或者可以在配置 Activity 里面供用户对更新频率进行配置。 实际上,当updatePeriodMillis的值小于30分钟时,系统会自动将更新频率设为30分钟!关于这部分,后面会详细介绍。
注意: 当更新时机到达时,如果设备正在休眠,那么设备将会被唤醒以执行更新。如果更新频率不超过1小时一次,那么对电池寿命应该不会造成多大的影响。 如果你需要比较频繁的更新,或者你不希望在设备休眠的时候执行更新,那么可以使用基于 alarm 的更新来替代 widget 自身的刷新机制。将 alarm 类型设置为 ELAPSED_REALTIME 或 RTC,将不会唤醒休眠的设备,同时请将 updatePeriodMillis 设为 0。


android:minWidth : 最小宽度
android:minHeight : 最小高度
android:updatePeriodMillis : 更新widget的时间间隔(ms),”86400000”为1个小时
android:previewImage : 预览图片
android:initialLayout : 加载到桌面时对应的布局文件
android:resizeMode : widget可以被拉伸的方向。horizontal表示可以水平拉伸,vertical表示可以竖直拉伸
android:widgetCategory : widget可以被显示的位置。home_screen表示可以将widget添加到桌面,keyguard表示widget可以被添加到锁屏界面。
android:initialKeyguardLayout : 加载到锁屏界面时对应的布局文件


Android自定义View之widget桌面小控件: 我可以控件时间啦_第1张图片


新建一个资源文件


Android自定义View之widget桌面小控件: 我可以控件时间啦_第2张图片


代码如下:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#09C"
    android:orientation="vertical"
    android:id="@+id/new_app_widget"
    android:padding="@dimen/widget_margin">

    <TextView
        android:id="@+id/tv_nowtime"
        android:layout_marginTop="30dp"
        android:gravity="center"
        android:text="更新时间 2017-01-24 13:16:25"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#ffffff"
        android:textSize="24sp"
        android:textStyle="bold|italic"/>


    <LinearLayout
        android:layout_marginTop="30dp"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <LinearLayout
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:background="#09C"
            android:contentDescription="@string/appwidget_text"
            android:text="@string/temper"
            android:textColor="#ffffff"
            android:textSize="24sp"
            android:textStyle="bold|italic" />
        <TextView
            android:id="@+id/tv_temper"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:background="#09C"
            android:contentDescription="@string/appwidget_text"
            android:textColor="#ffffff"
            android:textSize="24sp"
            android:textStyle="bold|italic" />
    LinearLayout>

        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="8dp"
                android:background="#09C"
                android:contentDescription="@string/appwidget_text"
                android:text="@string/hum"
                android:textColor="#ffffff"
                android:textSize="24sp"
                android:textStyle="bold|italic" />
            <TextView
                android:id="@+id/tv_hum"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="8dp"
                android:background="#09C"
                android:contentDescription="@string/appwidget_text"
                android:textColor="#ffffff"
                android:textSize="24sp"
                android:textStyle="bold|italic" />
        LinearLayout>LinearLayout>


    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="8dp"
                android:background="#09C"
                android:contentDescription="@string/appwidget_text"
                android:text="@string/formal"
                android:textColor="#ffffff"
                android:textSize="24sp"
                android:textStyle="bold|italic" />
            <TextView
                android:id="@+id/tv_formal"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="8dp"
                android:background="#09C"
                android:contentDescription="@string/appwidget_text"
                android:textColor="#ffffff"
                android:textSize="24sp"
                android:textStyle="bold|italic" />
        LinearLayout>

        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="8dp"
                android:background="#09C"
                android:contentDescription="@string/appwidget_text"
                android:text="@string/PM25"
                android:textColor="#ffffff"
                android:textSize="24sp"
                android:textStyle="bold|italic" />
            <TextView
                android:id="@+id/tv_PM25"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="8dp"
                android:background="#09C"
                android:contentDescription="@string/appwidget_text"
                android:textColor="#ffffff"
                android:textSize="24sp"
                android:textStyle="bold|italic" />
        LinearLayout>
    LinearLayout>
LinearLayout>

新建一个服务类WidgetService.java


import com.example.xuhong.floatwindows_master.R;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;


/*
 *  项目名:  FloatWindows-master 
 *  包名:    xml
 *  文件名:   WidgetService
 *  创建者:   XuHong
 *  创建时间:  2017/1/23 19:44
 *  描述:    服务绑定
 *
 */
public class WidgetService extends Service {


    //定时器
    private Timer timer;
    //获取系统时间
    private SimpleDateFormat mFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    @Override
    public void onDestroy() {
        super.onDestroy();
        timer=null;
        Log.i("MainActivity","定时器不可用");
    }
    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("MainActivity","服务开始了");
        timer=new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                upData();
                Log.i("MainActivity","定时器开始了");
            }
        },0,1000);
    }

    private void upData() {

        //自定义随机数
        Random random =new Random();
        String humRandom =Integer.toString(random.nextInt(50)) ;
        String temRandom1=Integer.toString(random.nextInt(30)) ;
        String formalRandom1=Integer.toString(random.nextInt(100)) ;
        String pm25Random1=Integer.toString(random.nextInt(60)) ;


        RemoteViews rv= new RemoteViews(getPackageName(), R.layout.new_app_widget);
        String data = mFormat.format(new Date());
        rv.setTextViewText(R.id.tv_nowtime,data);
        rv.setTextViewText(R.id.tv_hum,humRandom);
        rv.setTextViewText(R.id.tv_temper,temRandom1);
        rv.setTextViewText(R.id.tv_formal,formalRandom1);
        rv.setTextViewText(R.id.tv_PM25,pm25Random1);
        Log.i("MainActivity","时间:"+data);


        //这里获得当前的包名,并且用AppWidgetManager来向NewAppWidget.class发送广播。
        AppWidgetManager manager = AppWidgetManager.getInstance(getApplicationContext());
        ComponentName cn =new ComponentName(getApplicationContext(),NewAppWidget.class);
        manager.updateAppWidget(cn,rv);
    }
}

widget小控件实体类


import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/*
 *  项目名:  FloatWindows-master 
 *  包名:    xml
 *  文件名:   NewAppWidget
 *  创建者:   XuHong
 *  创建时间:  2017/1/23 21:32
 *  描述:    小组件
 */
public class NewAppWidget extends AppWidgetProvider {


    //  接收到任意广播时触发,并且会在上述的方法之前被调用。 
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
    }


    // 当 widget 更新时被执行。
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        Log.i("MainActivity","开始了更新");
    }

    // 当 widget 被删除时被触发。
    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);

        context.stopService(new Intent(context,WidgetService.class));
        Log.i("MainActivity","删除成功!");
    }


    // 当第1个 widget 的实例被创建时触发
    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
        Intent mTimerIntent = new Intent(context,WidgetService.class);
       context.startService(mTimerIntent);
        Log.i("MainActivity","创建成功!");
    }


    //  当最后1个 widget 的实例被删除时触发。  
    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
        Intent mTimerIntent = new Intent(context,WidgetService.class);
        context.stopService(mTimerIntent);
        Log.i("MainActivity","删除成功!");


    }
}

配置清单文件(非常重要)


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.xuhong.floatwindows_master">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>

        
        <receiver android:name="xml.NewAppWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
            intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/new_app_widget_info" />
        receiver>

        
        <service android:name="xml.WidgetService">service>
    application>

manifest>

自此,我们都没有用到主类,因为他是独自运行,离开了主类,服务在后台运行,怎么可能自己会停止更新数据呢!


你可能感兴趣的:(自定义UI)