前面几篇文章:
《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()方法,至于为什么要找到这里,我们在前面的文章已有叙述,代码如下:
public void start() { // 因为我们前面已经分析过start方法,因此这里就不重复了,有兴趣的朋友请翻看前面的文章,这里主要引出Clock的初始化. ... ... // 这里根据switches[0]的值,决定知否加载Clock disable(switches[0]); setSystemUiVisibility(switches[1]); topAppWindowChanged(switches[2] != 0); // StatusBarManagerService has a back up of IME token and it's restored here. setImeWindowStatus(binders.get(0), switches[3], switches[4]); setHardKeyboardStatus(switches[5] != 0, switches[6] != 0); ... ... mDoNotDisturb = new DoNotDisturb(mContext); }
根据这里的disable(),通过Open Implementation跳转到PhoneStatusBar中的disable方法,代码如下:
/** * State is one or more of the DISABLE constants from StatusBarManager. */ public void disable(int state) { final int old = mDisabled; final int diff = state ^ old; mDisabled = state; ... ... if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) { boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0; // 根据show的值(true/false)是否显示Clcok showClock(show); } ... ... } }
因为我们只关心Clock,因此其余部分代码在这里就省略了。继续跟踪showClock方法,代码如下:
public void showClock(boolean show) { // 这里就完成了clock的初始化了 这里的mStatusBarView实际上就是图1中的id/icons。可以通过查看mStatusBarView初始化知道。 View clock = mStatusBarView.findViewById(R.id.clock); if (clock != null) { clock.setVisibility(show ? View.VISIBLE : View.GONE); } }
初始化既然完成了,那么Clock是如何工作的呢?这就不得不找到Clock的实现了,那么该如何寻找呢?首先,找到clock的在id/icons中的布局文件,根据前文我们可以知道是msim_status_bar.xml,在其中可以看到:
<com.android.systemui.statusbar.policy.Clock android:id="@+id/clock" android:textAppearance="@style/TextAppearance.StatusBar.Clock" android:layout_width="wrap_content" android:layout_height="match_parent" android:singleLine="true" android:paddingRight="6dip" android:gravity="center_vertical|left" />我们可以看到clock是一个自定义View,以此我们可以找到其具体实现在:SourceCode/framework/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java中,代码如下:
public class Clock extends TextView { ... ... @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (!mAttached) { mAttached = true; IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_TIME_TICK); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); getContext().registerReceiver(mIntentReceiver, filter, null, getHandler()); } updateClock(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mAttached) { getContext().unregisterReceiver(mIntentReceiver); mAttached = false; } } private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { String tz = intent.getStringExtra("time-zone"); mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz)); if (mClockFormat != null) { mClockFormat.setTimeZone(mCalendar.getTimeZone()); } } updateClock(); } }; final void updateClock() { mCalendar.setTimeInMillis(System.currentTimeMillis()); setText(getSmallTime()); } ... ... } }
通过以上代码(省略了部分代码),我们可以看到,Clock实际上继承自TextView,TextView的内容更新需要SetText。因此这里通过广播的方式来实现了这一过程,更新Clock主要由方法updateClock()来完成,触发条件为接收到相应的广播。Clock的更新流程了:
1.Clock类继承TextView;
2.在初始化StatusBar时同时也注册了Clock中的广播;
3.Clock中的广播等待接收并执行更新时间;
通过以上方法,实际上就实现了一个可以自动更新内容的TextView。
下面我将通过一个Demo来简单的模拟这个过程,Demo内容:通过点击按钮触发广播,广播接收器在自定义TextView中,在该TextView中完成内容的更新。效果如图2:
图2
贴出实现代码,如下:
public final class ClockView extends TextView { private boolean update = false; public Context mContext; //调用Activity中的ACTION要一致 public static final String ACTION = "com.seven.update"; private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION.equals(action)) { updateClock(); } } }; public ClockView(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; setUpdates(); } //更新界面内容 private final void updateClock() { if(update){ update = false; setText("11:15 AM"); }else { update = true; setText("22:22 PM"); } } //注册广播接收 private void setUpdates() { IntentFilter filter = new IntentFilter(); filter.addAction(ACTION); mContext.registerReceiver(mIntentReceiver, filter); } }
布局文件如下:
<?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="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/name" /> <com.seven.viewTest.ClockView android:id="@+id/myCV" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#00ff00" android:textSize="30dip" android:text="@string/content" /> <Button android:id="@+id/myBtn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/send" /> </LinearLayout>调用Activity代码如下:
public class UpdateActivity extends Activity{ private ClockView mDateView; private Button mButton; public static final String ACTION = "com.seven.update"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); mDateView = (ClockView) findViewById(R.id.myCV); mButton = (Button) findViewById(R.id.myBtn); mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { sendBroadcast(new Intent(ACTION)); } }); } }总结:关于Clock的加载以及工作流程比较简单,但其中通过自定义view实现自动更新TextView还是值得学习。Clock的工作流程和Date的工作流程是一致的,也就是它们都是通过广播这种方式来更新内容的。
本文涉及到的代码以及图片资源下载请点击这里!