先上效果图:
玩了这么久的安卓,一直想要自己的一个桌面小控件,显示时间、温度之类的,今天雅致来了,就学习了,今天就写在这里了。
安卓桌面小控件大家都知道,即使源程序被用户抹杀掉、退出了程序,它依然在更新数据。这到底是为啥呢?原理很简单,这个小控件就是一个广播的原理,在此同时,我们需要新建一个服务类来更新这个小控件的UI数据,并且谷歌在为安卓特意有个广播的Action。后台服务来发出广播,这个小控件就接收更新数据,可以这样子理解。所以,即使源程序退出来了,它依然在后台更新数据啦。
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 : 加载到锁屏界面时对应的布局文件
代码如下:
<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>
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);
}
}
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>
自此,我们都没有用到主类,因为他是独自运行,离开了主类,服务在后台运行,怎么可能自己会停止更新数据呢!