android原生widget 电量控制(PowerSave)设计浅析

1、General

 

抽象类StateTracker

每个按钮实现一个StateTracker的子类(亮度按钮特殊处理不实现该类):

WifiStateTracker

BluetoothStateTracker

GpsStateTracker

SyncStateTracker

 

2、创建流程:

1、将PowerSave widget 拖出来后,系统调用回调onUpdate

 

// Update each requested appWidgetId

        RemoteViews view = buildUpdate(context);

 

        for (int i = 0; i

           appWidgetManager.updateAppWidget(appWidgetIds[i], view);

        }

 

appWidgetManager.updateAppWidget(appWidgetIds[i],view)为调用系统函数不做解释。

 

BuildUpdate:

1、创建一个RemoteViews 指定layout

views =new RemoteViews(context.getPackageName(),R.layout.widget);

2、设置按键响应

views.setOnClickPendingIntent(R.id.btn_wifi,getLaunchPendingIntent(context,BUTTON_WIFI))

views.setOnClickPendingIntent(R.id.btn_wifi,getLaunchPendingIntent(context,BUTTON_BT))

………………..

3、获取各种Wifi BT等状态,更新图标

updateButtons

4、Done

 

updateButtons

sWifiState.setImageViewResources(context,views);

sBluetoothState.setImageViewResources(context,views);

……

setImageViewResources为抽象父类实现。

1、  获取按钮和按钮下面指示器的id

getButtonId()、getIndicatorId()此两者子类负责实现,提供给父类id信息

2、  获取指示器的位置(左中右),父类默认为中、wifi为重写该方法,返回左

3、  getTriState获取开、关、切换中三种状态 该方法调用子类的getActualState方法,负责返回所代表部件的状态。PS: getActualState返回的是五种状态之一:开、关、正在开、正在关、未知状态(异常)。getTriState将五种状态转换成三种状态,以供指示器显示。

4、  根据以上三步收集的信息 调用views.setImageViewResource绘出按钮以及指示器

创建流程至此结束。

 

2、widget如何响应按钮事件

由于widget里面是RemoteViews,所以没有OnClickListener,只能通过intent发送给Host来执行

       先来看下创建是设置的getLaunchPendingIntent,

launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);

       launchIntent.setData(Uri.parse("custom:" + buttonId));

        PendingIntent pi =PendingIntent.getBroadcast(context, 0 /* no requestCode */,

                launchIntent, 0 /* no flags*/);

可以看出,intent携带了buttonId的数据来区别到底是哪个按钮事件,然后getBroadcast表明,按键事件将通过broadcast事件来通知widget。在onReceive中

else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)){

   Uri data = intent.getData();

   int buttonId = Integer.parseInt(data.getSchemeSpecificPart());

    if(buttonId == BUTTON_WIFI) {

       sWifiState.toggleState(context);

   }          

   else if (buttonId == BUTTON_BRIGHTNESS) {

       toggleBrightness(context);

    }else if (buttonId == BUTTON_SYNC) {

       sSyncState.toggleState(context);

    }

}

ToggleState

1、获取当前部件的状态。getTriState,根据当前状态确定是否需要进行状态切换

2、如果需要状态切换,调用子类的requestStateChange,子类负责切换所代表部件的状态。由于切换状态需要与硬件、网络交互。耗时长,所以内部使用AsyncTask进行异步切换

 

3、widget如何感知外部状态的变化

当用户在设置里面更改了Wifi、BT等状态,widget如何能及时知道,并修改按钮的图片

 

当外部状态变化时,widget的onReceive将收到消息,如果该部件不是通过broadcast来发送消息的,那么就注册一个Observer来监视该部件的变化(如亮度按钮)

根据intent识别是哪个部件发生变化

String action =intent.getAction();

if(WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {

    sWifiState.onActualStateChange(context,intent);

} else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {

   sBluetoothState.onActualStateChange(context, intent);

}

………………..

updateWidget(context);

子类调用onActualStateChange,由于是外部发生变化,子类不需要其他操作,所以onActualStateChange实现没做什么事情。

updateWidget(context);内部调用buildUpdate来更新按钮状态


你可能感兴趣的:(android原生widget 电量控制(PowerSave)设计浅析)