Android 4.0 ICS SystemUI浅析——StatusBar工作流程之时间日期设置

来源:互联网 发布:数据库故障应急预案 编辑:程序博客网 时间:2024/05/01 13:01

前面几篇文章:

       《Android 4.0 ICS SystemUI浅析——SystemUI启动流程

       《Android 4.0 ICS SystemUI浅析——StatusBar结构分析

       《Android 4.0 ICS SystemUI浅析——StatusBar加载流程分析

       《Android 4.0 ICS SystemUI浅析——StatusBar加载流程之Notification

       本文主要分析StatusBar上的Clock以及Date加载以及工作流程,这算是比较简单的了,不过它们的实现还是值得一探究竟的,那么果断开始吧!

       注:本文来自:http://blog.csdn.net/yihongyuelan 欢迎转载 请务必注明出处!

       首先还是看看我们前面文章有提到的StatusBar组成结构图,如图1

图1

         首先我们先找到SourceCode/framework/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java中的start()方法,至于为什么要找到这里,我们在前面的文章已有叙述,代码如下:

[java] view plaincopy
  1.  public void start() {  
  2.     // 因为我们前面已经分析过start方法,因此这里就不重复了,有兴趣的朋友请翻看前面的文章,这里主要引出Clock的初始化.  
  3.     ... ...  
  4.     // 这里根据switches[0]的值,决定知否加载Clock  
  5.     disable(switches[0]);  
  6.     setSystemUiVisibility(switches[1]);  
  7.     topAppWindowChanged(switches[2] != 0);  
  8.     // StatusBarManagerService has a back up of IME token and it's restored here.  
  9.     setImeWindowStatus(binders.get(0), switches[3], switches[4]);  
  10.     setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);  
  11.   
  12.     ... ...  
  13.   
  14.     mDoNotDisturb = new DoNotDisturb(mContext);  
  15. }  

         根据这里的disable(),通过Open Implementation跳转到PhoneStatusBar中的disable方法,代码如下:

[java] view plaincopy
  1. /** 
  2.  * State is one or more of the DISABLE constants from StatusBarManager. 
  3.  */  
  4. public void disable(int state) {  
  5.     final int old = mDisabled;  
  6.     final int diff = state ^ old;  
  7.     mDisabled = state;  
  8.     ... ...  
  9.     if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {  
  10.         boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;  
  11.         // 根据show的值(true/false)是否显示Clcok  
  12.         showClock(show);  
  13.     }  
  14.     ... ...  
  15.     }  
  16. }  

         因为我们只关心Clock,因此其余部分代码在这里就省略了。继续跟踪showClock方法,代码如下:

[java] view plaincopy
  1. public void showClock(boolean show) {  
  2.     // 这里就完成了clock的初始化了 这里的mStatusBarView实际上就是图1中的id/icons。可以通过查看mStatusBarView初始化知道。  
  3.     View clock = mStatusBarView.findViewById(R.id.clock);  
  4.     if (clock != null) {  
  5.         clock.setVisibility(show ? View.VISIBLE : View.GONE);  
  6.     }  
  7. }  

          初始化既然完成了,那么Clock是如何工作的呢?这就不得不找到Clock的实现了,那么该如何寻找呢?首先,找到clock的在id/icons中的布局文件,根据前文我们可以知道是msim_status_bar.xml,在其中可以看到:

[html] view plaincopy
  1. <com.android.systemui.statusbar.policy.Clock  
  2.     android:id="@+id/clock"  
  3.     android:textAppearance="@style/TextAppearance.StatusBar.Clock"  
  4.     android:layout_width="wrap_content"  
  5.     android:layout_height="match_parent"  
  6.     android:singleLine="true"  
  7.     android:paddingRight="6dip"  
  8.     android:gravity="center_vertical|left"  
  9.     />  
          我们可以看到clock是一个自定义View,以此我们可以找到其具体实现在:SourceCode/framework/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java中,代码如下:
[java] view plaincopy
  1. public class Clock extends TextView {  
  2.     ... ...  
  3.   
  4.     @Override  
  5.     protected void onAttachedToWindow() {  
  6.         super.onAttachedToWindow();  
  7.   
  8.         if (!mAttached) {  
  9.             mAttached = true;  
  10.             IntentFilter filter = new IntentFilter();  
  11.   
  12.             filter.addAction(Intent.ACTION_TIME_TICK);  
  13.             filter.addAction(Intent.ACTION_TIME_CHANGED);  
  14.             filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);  
  15.             filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);  
  16.   
  17.             getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());  
  18.         }  
  19.         updateClock();  
  20.     }  
  21.   
  22.     @Override  
  23.     protected void onDetachedFromWindow() {  
  24.         super.onDetachedFromWindow();  
  25.         if (mAttached) {  
  26.             getContext().unregisterReceiver(mIntentReceiver);  
  27.             mAttached = false;  
  28.         }  
  29.     }  
  30.   
  31.     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {  
  32.         @Override  
  33.         public void onReceive(Context context, Intent intent) {  
  34.             String action = intent.getAction();  
  35.             if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {  
  36.                 String tz = intent.getStringExtra("time-zone");  
  37.                 mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));  
  38.                 if (mClockFormat != null) {  
  39.                     mClockFormat.setTimeZone(mCalendar.getTimeZone());  
  40.                 }  
  41.             }  
  42.             updateClock();  
  43.         }  
  44.     };  
  45.   
  46.     final void updateClock() {  
  47.         mCalendar.setTimeInMillis(System.currentTimeMillis());  
  48.         setText(getSmallTime());  
  49.     }  
  50.   
  51.     ... ...  
  52.   
  53.     }  
  54. }  

          通过以上代码(省略了部分代码),我们可以看到,Clock实际上继承自TextView,TextView的内容更新需要SetText。因此这里通过广播的方式来实现了这一过程,更新Clock主要由方法updateClock()来完成,触发条件为接收到相应的广播。Clock的更新流程了:

      1.Clock类继承TextView;

      2.在初始化StatusBar时同时也注册了Clock中的广播;

      3.Clock中的广播等待接收并执行更新时间;

      通过以上方法,实际上就实现了一个可以自动更新内容的TextView。

     下面我将通过一个Demo来简单的模拟这个过程,Demo内容:通过点击按钮触发广播,广播接收器在自定义TextView中,在该TextView中完成内容的更新。效果如图2:

图2

       贴出实现代码,如下:

[java] view plaincopy
  1. public final class ClockView extends TextView {  
  2.   
  3.     private boolean update = false;  
  4.     public Context mContext;  
  5.     //调用Activity中的ACTION要一致  
  6.     public static final String ACTION = "com.seven.update";  
  7.   
  8.     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {  
  9.         @Override  
  10.         public void onReceive(Context context, Intent intent) {  
  11.             String action = intent.getAction();  
  12.             if (ACTION.equals(action)) {  
  13.                 updateClock();  
  14.             }  
  15.         }  
  16.     };  
  17.   
  18.     public ClockView(Context context, AttributeSet attrs) {  
  19.         super(context, attrs);  
  20.         this.mContext = context;   
  21.         setUpdates();  
  22.     }  
  23.   
  24.     //更新界面内容  
  25.     private final void updateClock() {  
  26.         if(update){  
  27.             update = false;  
  28.             setText("11:15 AM");  
  29.         }else {  
  30.             update = true;  
  31.             setText("22:22 PM");  
  32.         }  
  33.     }  
  34.   
  35.     //注册广播接收  
  36.     private void setUpdates() {  
  37.         IntentFilter filter = new IntentFilter();  
  38.         filter.addAction(ACTION);  
  39.         mContext.registerReceiver(mIntentReceiver, filter);  
  40.     }  
  41. }  

      布局文件如下:

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <TextView  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:text="@string/name" />  
  11.       
  12.     <com.seven.viewTest.ClockView   
  13.         android:id="@+id/myCV"  
  14.         android:layout_width="fill_parent"  
  15.         android:layout_height="wrap_content"  
  16.         android:textColor="#00ff00"  
  17.         android:textSize="30dip"  
  18.         android:text="@string/content"  
  19.         />  
  20.       
  21.     <Button   
  22.         android:id="@+id/myBtn"  
  23.         android:layout_width="fill_parent"  
  24.         android:layout_height="wrap_content"  
  25.         android:text="@string/send"  
  26.         />  
  27.   
  28. </LinearLayout>  
       调用Activity代码如下:
[java] view plaincopy
  1. public class UpdateActivity extends Activity{  
  2.       
  3.     private ClockView mDateView;  
  4.     private Button mButton;  
  5.     public static final String ACTION = "com.seven.update";  
  6.   
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  
  11.                 WindowManager.LayoutParams.FLAG_FULLSCREEN);  
  12.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  13.           
  14.         setContentView(R.layout.main);  
  15.           
  16.         mDateView = (ClockView) findViewById(R.id.myCV);  
  17.         mButton = (Button) findViewById(R.id.myBtn);  
  18.         mButton.setOnClickListener(new OnClickListener() {  
  19.             @Override  
  20.             public void onClick(View v) {  
  21.                 sendBroadcast(new Intent(ACTION));   
  22.             }  
  23.         });  
  24.     }  
  25. }  
           总结:关于Clock的加载以及工作流程比较简单,但其中通过自定义view实现自动更新TextView还是值得学习。Clock的工作流程和Date的工作流程是一致的,也就是它们都是通过广播这种方式来更新内容的。

       本文涉及到的代码以及图片资源下载请点击这里!