桌面控件Widget的使用

开发者文档中详细介绍了Widget的使用方法

 file:///D:/Program%20Files%20(x86)/Andriod/android-sdks/docs/guide/topics/appwidgets/index.html

最终效果展示:

1. 首先建立AppWidgetProvider的实体类(AppWidgetProvider class implementation)MyWidget

public class
    AppWidgetProvider
    extends BroadcastReceiver

2. AppWidgetProvider 继承 BroadcastReceiver,所以要在清单文件中进行注册(Declaring an App Widget in the Manifest)

<receiver android:name="com.itheima.mobilesafe.receiver.MyWidget" >
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>

    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/appwidget_info" />
</receiver>

3. android:resource="@xml/appwidget_info" 为Widget控件的资源描述(Adding the AppWidgetProviderInfo Metadata)

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/process_widget"
    android:minHeight="72dp"
    android:minWidth="294dp"
    android:updatePeriodMillis="1800000" >

</appwidget-provider>

4. android:initialLayout="@layout/process_widget" 为Widget的布局文件(Creating the App Widget Layout)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/widget_bg_portrait"
    android:gravity="center_vertical" >

    <LinearLayout
        android:layout_width="0.0dip"
        android:layout_height="fill_parent"
        android:layout_marginLeft="5.0dip"
        android:layout_weight="1.0"
        android:background="@drawable/widget_bg_portrait_child"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:paddingBottom="3.0dip"
        android:paddingTop="3.0dip" >

        <TextView
            android:id="@+id/process_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10.0dip"
            android:text="正在运行的软件:15个"
            android:textAppearance="@style/widget_text" />

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="1.0dip"
            android:layout_marginTop="1.0dip"
            android:background="@drawable/widget_bg_portrait_child_divider" />

        <TextView
            android:id="@+id/process_memory"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10.0dip"
            android:text="可用内存:391.80MB"
            android:textAppearance="@style/widget_text" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_vertical" >

            <ImageView
                android:layout_width="20.0dip"
                android:layout_height="20.0dip"
                android:src="@drawable/ic_launcher" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/app_name"
                android:textColor="@color/textColorPrimary" />
        </LinearLayout>

        <Button
            android:id="@+id/btn_clear"
            android:layout_width="90.0dip"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginTop="5.0dip"
            android:background="@drawable/function_greenbutton_selector"
            android:text="一键清理"
            android:textColor="@color/function_greenbutton_textcolor_selector" />
    </LinearLayout>

</LinearLayout>

5. 在服务(UpdateWidgetService)中更新Widget(Using the AppWidgetProvider Class)

服务为四大组件之一,需要在清单文件注册.
<service android:name="com.itheima.mobilesafe.service.UpdateWidgetService" />

服务开启时设置定时更新Widget

@Override
    public void onCreate() {

	// 获取Widget的管理器
	awm = AppWidgetManager.getInstance(this);
	startWidgetUpdate();
	super.onCreate();
}
定时5秒更新桌面Widget
/**
 * 定时5秒更新Widget
 */
private void startWidgetUpdate() {
    timer = new Timer();
    task = new TimerTask() {
	@Override
	public void run() {
	    Log.i(TAG, "更新Widgit");
	    // 更新另外一个进程的操作。ipc调用,进程间通讯(inner process communication)
	    RemoteViews views = new RemoteViews(getPackageName(), R.layout.process_widget);
	    // 指定要更新的是哪一个widget
	    ComponentName provider = new ComponentName(getApplicationContext(), MyWidget.class);
	    views.setTextViewText(R.id.process_count, "正在运行进程数:"+SystemInfoUtils.getRunningProcessCount(getApplicationContext())+"个");
	    views.setTextViewText(R.id.process_memory, "可用内存:"+Formatter.formatFileSize(getApplicationContext(), SystemInfoUtils.getAvailRam(getApplicationContext())));
	    //设置"一键清理"按钮的点击事件,因为在不同的进程之间,所以采用延期意图
	    //一个延期的意图 发送自定义的广播
	    Intent intent = new Intent();
	    intent.setAction("com.itheima.mobilesafe.killall");
	    //FLAG_UPDATE_CURRENT如果两次点击第一次没有执行,第二次将第一次覆盖
	    PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
	    views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);
	    awm.updateAppWidget(provider, views);
	}
    };
    timer.schedule(task, 0, 5000);// 每隔5秒钟执行一次。
}
服务关闭时关闭定时器,释放资源
@Override
public void onDestroy() {

    //服务停止关闭屏幕广播接受者
    unregisterReceiver(offReceiver);
    unregisterReceiver(onReceiver);
    offReceiver = null;
    onReceiver = null;

    super.onDestroy();
}

6. 点击按钮“一键清理”的时候,因为该空间属于桌面程序,所以只能通过延期意图的方式进程间通讯

发送自定义广播intent.setAction("com.itheima.mobilesafe.killall");

7. 编写广播接受者KillAllReceiver,接受广播,执行操作

广播为四大组件之一,在清单文件注册

<receiver android:name="com.itheima.mobilesafe.receiver.KillAllReceiver">
    <intent-filter>
        <action android:name="com.itheima.mobilesafe.killall"/>
    </intent-filter>
</receiver>

当广播到来,杀死所有能杀死的进程

@Override
public void onReceive(Context context, Intent intent) {
    Log.i(TAG, "接收到自定义广播,杀死所有进程");
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> infos = am.getRunningAppProcesses();
    for (RunningAppProcessInfo info : infos) {
	am.killBackgroundProcesses(info.processName);
	Log.i(TAG, info.processName+"被杀死了");
    }
}

8. 那么就带来一个问题,我们在什么时候开启服务(UpdateWidgetService)比较合适?

当然可以程序一运行就开启服务,如果不添加桌面Widget这不就是一种资源浪费?那么来研究下Widget的生命周期:

第一个widget被创建

06-25 07:50:00.923: I/System.out(8130): onEnabled     (第一个widget被创建的时候 执行 onenable 适合做widget初始化)

06-25 07:50:00.923: I/System.out(8130): onreceiver

06-25 07:50:00.923: I/System.out(8130): onUpdate     只要有新的widget被创建都会调用update方法。 当时间片到了。

06-25 07:50:00.923: I/System.out(8130): onreceiver

第二个widget被创建 (新的创建)

06-25 07:51:11.605: I/System.out(8130): onUpdate

06-25 07:51:11.605: I/System.out(8130): onreceiver

移除一个widget

06-25 07:51:56.966: I/System.out(8130): onDeleted

06-25 07:51:56.966: I/System.out(8130): onreceiver

最后一个被移除

06-25 07:52:19.936: I/System.out(8130): onDeleted

06-25 07:52:19.936: I/System.out(8130): onreceiver

06-25 07:52:19.936: I/System.out(8130): onDisabled   最后一个widget被移除 适合 应用程序的销毁 反初始化 擦屁股

06-25 07:52:19.936: I/System.out(8130): onreceiver

 
发现第一个创建会执行onEnabled,最后一个移除会执行onDisabled,则可以在onEnable中开启更新服务,在onDisable中关闭更新服务。
@Override
public void onEnabled(Context context) {
    // 创建桌面Widget的时候开启更新服务
    Log.i(TAG, "开启Widget更新服务");
    Intent intent = new Intent(context, UpdateWidgetService.class);
    context.startService(intent);
    super.onEnabled(context);
}
@Override
public void onDisabled(Context context) {
    // 移除所有Widget的时候关闭更新服务
    Log.i(TAG, "关闭Widget更新服务");
    Intent intent = new Intent(context, UpdateWidgetService.class);
    context.stopService(intent);
    super.onDisabled(context);
}

以防服务更新死掉,在定时30分钟更新时再次将服务激活

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    // 设定时间更新Widget时,再次激活服务
    Log.i(TAG, "定时Widget更新服务");
    Intent intent = new Intent(context, UpdateWidgetService.class);
    context.startService(intent);
    super.onUpdate(context, appWidgetManager, appWidgetIds);
}

9. 那么当手机处于待机状态下我们是不需要更新桌面Widget的,则应当监听屏幕锁闭和屏幕开启的广播

在屏幕锁闭的情况下,关闭定时器释放资源,屏幕开启的广播到来开启定时器,定时更新。
在代码内注册广播接受者
//屏幕锁定内部类广播接受者
private class InnerScreenOffReceiver extends BroadcastReceiver {
    private static final String TAG = "InnerScreenOffReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
	Log.i(TAG, "屏幕锁定");
	// 屏幕锁定取消定时器
	if(timer != null && task != null) {
	    timer.cancel();
	    task.cancel();
	    timer = null;
	    task = null;
	}
    }
}
//屏幕锁定内部类广播接受者
private class InnerScreenOnReceiver extends BroadcastReceiver {
    private static final String TAG = "InnerScreenOnReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "屏幕解锁");
        // 屏幕开启建立定时器
        if(timer == null && task == null) {
            startWidgetUpdate();
        }
    }
}
服务开启时注册广播
@Override
public void onCreate() {
    //注册屏幕锁闭广播接受者
    offReceiver = new InnerScreenOffReceiver();
    IntentFilter offFilter = new IntentFilter();
    offFilter.addAction(Intent.ACTION_SCREEN_OFF);
    registerReceiver(offReceiver, offFilter);
    //注册屏幕开启广播接受者
    onReceiver = new InnerScreenOnReceiver();
    IntentFilter onFilter = new IntentFilter();
    onFilter.addAction(Intent.ACTION_SCREEN_ON);
    registerReceiver(onReceiver, onFilter);

    // 获取Widget的管理器
    awm = AppWidgetManager.getInstance(this);
    startWidgetUpdate();
    super.onCreate();
}
服务停止时反注册广播
@Override
public void onDestroy() {
    // 服务停止关闭定时操作
    if(timer != null && task != null) {
        timer.cancel();
        task.cancel();
        timer = null;
        task = null;
    }

        // 服务停止关闭屏幕广播接受者
        unregisterReceiver(offReceiver);
        unregisterReceiver(onReceiver);
        offReceiver = null;
        onReceiver = null;

        super.onDestroy();
}

自此,桌面Widget设置已完成,下面是UpdateWidgetService用到的得到运行进程数以及得到可用内存的工具类

/**
 * 得到系统内存信息的工具类
 *
 * @author zwenkai
 *
 */
public class SystemInfoUtils {

    /**
     * 得到运行的进程总个数
     *
     * @param context
     * @return 运行进程个数
     */
    public static int getRunningProcessCount(Context context) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        return am.getRunningAppProcesses().size();
	}

    /**
     * 得到可用内存数
     *
     * @param context
     * @return
     */
    public static long getAvailRam(Context context) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        MemoryInfo outInfo = new MemoryInfo();
        am.getMemoryInfo(outInfo);
        return outInfo.availMem;
    }
}

桌面控件Widget的使用,布布扣,bubuko.com

时间: 2024-11-06 10:25:03

桌面控件Widget的使用的相关文章

ubuntu使用conky添加桌面控件

周末没事好好玩一下ubuntu,首先就想用windows的桌面. 桌面快捷方式就是把/usr/share/applications/下面的应用启动文件拷贝到桌面: 下面主要说说如何添加桌面控件.我用的是Conky 看看效果,其实还有很多其他的控件,只是需要另外下载: 安装方法: 首先得安装Conky: sudo apt-get install conky-all 然后安装GUI管理器: sudo add-apt-repository ppa:teejee2008/ppa sudo apt-get

[Android5 系列二] 1. 全实例之控件(Widget)

前言 android.view.View 视图类是widgets 的基类, 有很多的扩展类, 包括文本视图TextView.图像视图ImageView.进度条ProgressBar .视图组ViewGroup 等. 具体的结果如下图: 创建Android Project 这里使用的是Eclipse 的IDE 来进行Android 开发. 官方推荐的IDE已经是基于IntelliJ IDEA  的studio了. 1. File --> New --> Android --> Androi

C# windows 桌面控件的扩展

今天一同事 需要一个Windows from下 GridView的嵌套的控件,于是就去找了以前自己写的一些form 控件,发现居然没有人下载.同时查找以前的下载包也比较费时,于是乎就搞一个文章. 运行效果如下:

android中常用的小控件------Widgets的使用

好久没有写博客了,都不知博客怎么写了,最近突然想写博客,以帮助更多的人,却又不知道写什么好呢? 好吧  我承认我有点懒惰了,可是程序猿是不应该懒惰的哦,俺要做个好孩子. 好了言归正传,开始介绍下今天的主要内容吧! Widgets一个桌面的小控件    个人认为是很常用的,不知道大神们是不是这么觉得的呢?比如说你开发的一款音乐播放器的软件,可把基本的上一曲和下一曲.暂停的几个功能放在这个小控件里面将它显示在桌面上来,这样就很方便啦,你想要下一曲.上一曲.暂停播放的时候,就不用再打开播放器了,而是直

Qt5 UI信号、槽自动连接的控件重名

Qt5 UI信号.槽自动连接的控件重名 来源 http://blog.csdn.net/goldenhawking/article/details/51865909 对Qt5稍有熟悉的童鞋都知道信号.槽的自动连接机制.该机制使得qt designer 设计的UI中包含的控件,可以不通过显式connect,直接和cpp中的相应槽相关联.该机制的详细文章见 http://doc.qt.io/qt-5/designer-using-a-ui-file.html#automatic-connection

kivy学习---控件

------控件 控件Widget是kivy图形界面中的基本元素.控件提供了一个画布canvas,这是用来在屏幕上进行绘制的.控件接收事件,并对事件作出反应. 一个控件的子控件会以children属性的形式表达,这个属性是kivy中的一个列表属性ListProperty.可以用以下方法来操作控件树: ·add_widget():添加一个控件作为子控件 ·remove_widget():从子控件列表中去掉一个控件 ·clear_widget():清空一个控件的所有子控件. 控件索引:控件绘制的顺序

如何在Android实现桌面清理内存简单Widget小控件

如何在Android实现桌面清理内存简单Widget小控件 我们经常会看到类似于360.金山手机卫士一类的软件会带一个widget小控件,显示在桌面上,上面会显示现有内存大小,然后会带一个按键功能来一键清理内存,杀死后台进程的功能,那么这个功能是如何实现的呢,我们今天也来尝试做一个类似的功能的小控件. 效果图: 一.UI部分的编写: 参照Google的文档,首先在建立一个类继承AppWidgetProvider import android.appwidget.AppWidgetProvider

如果写一个android桌面滑动切换屏幕的控件(二)

在viewgroup执行: public void snapToScreen(int whichScreen) { whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); boolean changingScreens = whichScreen != mCurrentScreen; mNextScreen = whichScreen; int mScrollX = this.getScrollX(); fin

如果写一个android桌面滑动切换屏幕的控件(三)

下面我们把这个控件内嵌到Layout中做一些动画和展示,效果图: 这个子控件可以上下移动,可以左右滑动,如果上下滑动距离大于左右滑动距离,则必须上下滑动 这样来写onTouch事件: @Override public boolean onTouchEvent(MotionEvent ev) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMov