为什么80%的码农都做不了架构师?>>>   

接上一篇博文:``继续分析AlarmClock类的各个方法:

还是先从简单的开始吧:

(1)updateAlarm(),代码如下:

private void updateAlarm(boolean enabled,Alarm alarm) {Alarms.enableAlarm(this, alarm.id, enabled);if (enabled) {SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes,alarm.daysOfWeek);}}

更新Alarm状态。

值得注意的上,在前一篇博文也出现了Alarms.enableAlarm()方法,

但是其实这个enableAlarm()方法实际上是根据enabled的状态来更新alarm的。

并不是单纯的启用alarm的。

如果enabled参数为false的话,实际是停用些alarm,

上面的方法,在设置的alarm状态之后。如果是启用的话,弹出一条Toast来提醒用户。

这个方法在用户点击闹钟列表项的选择框时调用。是一个点击事件的回调函数,在AlarmTimeAdapter中的bindView方法中,如下:

View indicator = view.findViewById(R.id.indicator);// 为选择框设置初始的状态
// Set the initial state of the clock "checkbox"
final CheckBox clockOnOff =
(CheckBox) indicator.findViewById(R.id.clock_onoff);
clockOnOff.setChecked(alarm.enabled);// 在单选框的外部(指单选框周围的margin部分)单击也应该改变状态。
// Clicking outside the "checkbox" should also change the state.indicator.setOnClickListener(new OnClickListener() {public void onClick(View v) {clockOnOff.toggle();// 切换选择框状态updateAlarm(clockOnOff.isChecked(), alarm);//更新alarm状态。}});

我觉得很有必要将上面的R.id.indicator所代码布局代码贴上来,如下:

<com.android.deskclock.DontPressWithParentLayoutandroid:id="@+id/indicator"style="@style/alarm_list_left_column"android:gravity="center"android:orientation="vertical"><CheckBoxandroid:id="@+id/clock_onoff"android:focusable="false"android:clickable="false"android:duplicateParentState="true"android:layout_height="wrap_content"android:layout_width="wrap_content"android:layout_gravity="center" /></com.android.deskclock.DontPressWithParentLayout>

上面的布局使用了一个自定义的布局类,

这个自定义的布局要达到的效果是,当你点击CheckBox与DontPressWithParentLayout之间的区域时,不需要引发其它的视觉效果,即不会改变整个DontPressWithParentLayout布局的背景。

代码如下:

/*** 这是一个允许其父类本身被pressed但是不需要正在被pressed的状态。这样一来,在alarm列表的时间可以被pressed但不需要改变indicator的背景。
===========================* Special class to to allow the parent to be pressed without being pressed* itself. This way the time in the alarm list can be pressed without changing* the background of the indicator.*/
public class DontPressWithParentLayout extends LinearLayout {public DontPressWithParentLayout(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic void setPressed(boolean pressed) {// 如果父类类被pressed不要设置为pressed// If the parent is pressed, do not set to pressed.if (pressed && ((View) getParent()).isPressed()) {return;}super.setPressed(pressed);}
}

(2)CursorAdapter子类AlarmTimeAdapter分析。

CursorAdapter类的简单介绍。

相信我们都对于BaseAdapter比较了解了吧,

那么先来看看CursorAdapter的签名吧,

public abstract class CursorAdapter extends BaseAdapter implements Filterable,CursorFilter.CursorFilterClient {
}

当我们扩展BaseAdapter的时候,我们主要是要重写BaseAdapter#getView()方法。

但是在CursorAdapter中这个方法它已经帮我们实现了,但是让我们去实现另外两个方法。

先看下CursorAdapter中的getView()方法吧,如下:

/*** @see android.widget.ListAdapter#getView(int, View, ViewGroup)*/public View getView(int position, View convertView, ViewGroup parent) {if (!mDataValid) {throw new IllegalStateException("this should only be called when the cursor is valid");}if (!mCursor.moveToPosition(position)) {throw new IllegalStateException("couldn't move cursor to position " + position);}View v;if (convertView == null) {v = newView(mContext, mCursor, parent);} else {v = convertView;}bindView(v, mContext, mCursor);return v;}

上面代码的逻辑也是我们通过实现getViw()的逻辑 ,先是对数据进行错误检查。

然后,如果view为空则调用newView()构造一个view,否则使用之前构造的。

然后调用bindView()将数据绑定上去。OK,如果使用过BaseAdapter的话是不是很熟悉啊!

那下面再来仔细看看,newView()和bindView()这两个方法吧。

(2.1)public View newView(Context context,Cursor cursor,ViewGroup parent)

代码如下:

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {View ret = mFactory.inflate(R.layout.alarm_time, parent, false);DigitalClock digitalClock =(DigitalClock) ret.findViewById(R.id.digitalClock);digitalClock.setLive(false);return ret;
}

首先进入我们眼中的是DigitalClock,看下DigitalClock的类型,如下:

public class DigitalClock extends RelativeLayout

哦,原来是一个RelativeLayout的子类。对于DigitalClock我们就暂时了解这么多,后面会单独分析。

(2.2) public void bindView(View view, Context context, Cursor cursor)

@Overridepublic void bindView(View view, Context context, Cursor cursor) {final Alarm alarm = new Alarm(cursor);View indicator = view.findViewById(R.id.indicator);// Set the initial state of the clock "checkbox"final CheckBox clockOnOff =(CheckBox) indicator.findViewById(R.id.clock_onoff);clockOnOff.setChecked(alarm.enabled);// Clicking outside the "checkbox" should also change the state.indicator.setOnClickListener(new OnClickListener() {public void onClick(View v) {clockOnOff.toggle();updateAlarm(clockOnOff.isChecked(), alarm);}});// 上面部分的代码上updateAlarm()时已经有比较详细的分析了。DigitalClock digitalClock =(DigitalClock) view.findViewById(R.id.digitalClock);// 设置闹钟显示的标签 final Calendar c = Calendar.getInstance();c.set(Calendar.HOUR_OF_DAY, alarm.hour);c.set(Calendar.MINUTE, alarm.minutes);digitalClock.updateTime(c);// 设置重要闹钟的时间,如果不重要则不显示// Set the repeat text or leave it blank if it does not repeat.TextView daysOfWeekView =(TextView) digitalClock.findViewById(R.id.daysOfWeek);final String daysOfWeekStr =alarm.daysOfWeek.toString(AlarmClock.this, false);if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) {daysOfWeekView.setText(daysOfWeekStr);daysOfWeekView.setVisibility(View.VISIBLE);} else {daysOfWeekView.setVisibility(View.GONE);}// 设置此闹钟的备注标签// Display the labelTextView labelView =(TextView) view.findViewById(R.id.label);if (alarm.label != null && alarm.label.length() != 0) {labelView.setText(alarm.label);labelView.setVisibility(View.VISIBLE);} else {labelView.setVisibility(View.GONE);}}};

上面的代码也比较清晰简单,无非就是,如果对应内容不为空的话,则设置并显示,否则隐藏对应控件。

下面的布局代码:

<!-- A layout that displays the time.  Shows time, am/pm (if 12-hour),and an optional line below, used for day/days of week --><com.android.deskclock.DigitalClock android:id="@+id/digitalClock"android:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center_vertical"android:layout_weight="1"android:layout_gravity="center_vertical"android:orientation="vertical"android:paddingLeft="16dip"android:paddingRight="16dip"><LinearLayoutandroid:id="@+id/time_wrapper"android:layout_width="match_parent"android:layout_height="wrap_content"android:baselineAligned="true"><com.android.deskclock.AndroidClockTextView android:id="@+id/timeDisplay"android:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingRight="6dip"android:textAppearance="?android:attr/textAppearanceMedium"useClockTypeface="false"/><com.android.deskclock.AndroidClockTextView android:id="@+id/am_pm"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textAppearance="?android:attr/textAppearanceMedium"android:paddingRight="10dip"android:textStyle="bold"useClockTypeface="false"/><TextView android:id="@+id/label"android:layout_width="0dip"android:layout_height="wrap_content"android:layout_weight="1"android:paddingLeft="8dip"android:textAppearance="?android:attr/textAppearanceSmall"android:textColor="?android:attr/textColorSecondary"android:textStyle="bold"android:gravity="right"android:singleLine="true"/></LinearLayout><TextView android:id="@+id/daysOfWeek"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/time_wrapper"android:paddingTop="2dip"android:textAppearance="?android:attr/textAppearanceSmall"android:textColor="?android:attr/textColorTertiary"/></com.android.deskclock.DigitalClock>

上面布局代码中,有用到了com.android.deskclock.AndroidClockTextView 这个扩展了TextView的子类。

而这个使用自定义子类的目的是为了使用专门的字体。。

/*** 使用特殊的AndroidClock字体来显示文本。*/
public class AndroidClockTextView extends TextView

要了,到最这个类的最后时刻了,

(3)onCreate(Bundle icicle)

代码如下:

@Overrideprotected void onCreate(Bundle icicle) {super.onCreate(icicle);mFactory = LayoutInflater.from(this);mPrefs = getSharedPreferences(PREFERENCES, 0);mCursor = Alarms.getAlarmsCursor(getContentResolver());updateLayout();}

我上网查了下icicle的意思,如下:

icicle  冰柱,冰棍儿

popsicle, ice-sucker, ice lolly, icicle

呵呵,我想我们以后命名也可以多用吃的来命名,这样程序是不是会吸引人些呢?

上面方法的代码,比较清楚。

LayoutInflater.from(this)来获得LayoutInflater对象。

当然也可以通过getSystemService()来获得。

然后是获得当前偏好文件管理对象。getSharedPreferences(PREFERNCES,0);

0是默认的打开模式,即等于

MODE_PRIVATE

然后从Alarm的Dao类中,即从Alarms类中获得所有的Alarm的Cursor对象。

Alarms会在我后面的博文中详细分析。

然后就是,

(3)updateLayout()

代码,比较长,但是还是清楚明白的。

private void updateLayout() {setContentView(R.layout.alarm_clock);mAlarmsList = (ListView) findViewById(R.id.alarms_list);AlarmTimeAdapter adapter = new AlarmTimeAdapter(this, mCursor);mAlarmsList.setAdapter(adapter);mAlarmsList.setVerticalScrollBarEnabled(true);mAlarmsList.setOnItemClickListener(this);mAlarmsList.setOnCreateContextMenuListener(this);View addAlarm = findViewById(R.id.add_alarm);if (addAlarm != null) {addAlarm.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {addNewAlarm();}});// Make the entire view selected when focused.addAlarm.setOnFocusChangeListener(new View.OnFocusChangeListener() {public void onFocusChange(View v, boolean hasFocus) {v.setSelected(hasFocus);}});}View doneButton = findViewById(R.id.done);if (doneButton != null) {doneButton.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {finish();}});}View settingsButton = findViewById(R.id.settings);if (settingsButton != null) {settingsButton.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {startActivity(new Intent(AlarmClock.this, SettingsActivity.class));finish();}});}ActionBar actionBar = getActionBar();if (actionBar != null) {actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);}}

方法第1行,设置布局资源。

第2行获得闹钟ListView对象。

第3行,构造AlarmTimeAdapter,

第4行,为listView对象设置adapter

第5行,listView启用ListView的垂直滑动条。

第6行,设置listView中闹钟项的单击事件。

第7行,设置listView中闹钟的长按监听。

下面的代码,基本是同样的模式,

查找某一个View,如果不为空则设置点击事件。

然后有一个获得ActionBar,如果actionBar不为空的话,

actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);

这个方法的特点是,前面所指定的选项呢,是将要设置的,但是如果前面第一参数里出现了选项,没有出现在第二个参数中,那么此选项将被认为是disable的。

ActionBar是android3之后才新出的组件。值得我们去学习。使用。

(4)onDestroy()

方法如下:

@Overrideprotected void onDestroy() {super.onDestroy();ToastMaster.cancelToast();if (mCursor != null) {mCursor.close();}}

上面方法,主要执行两个操作,将数据库的Cursor关闭(如果不为空的话)

取消Toast。ToastMaster是此应用自定义的一个封装类,代码比较简单。

一般在我们使用数据库的时候,都应该在最后正确的关闭数据库。

上面的方法就是这样做的。

到此这个类的分析,暂时到这里了。

其中还有一些地方肯定没有分析得很好,希望各位如果看到了这里,发现不足,欢迎给我些指点。谢谢

转载于:https://my.oschina.net/banxi/blog/79032

学习Android闹钟源代码(三)-AlarmClock类分析(part2)相关推荐

  1. Android闹钟动画,学习Android闹钟源代码(三)-AlarmClock类分析(part1)

    android的时钟,也就是闹钟应用,从桌面的widget直接点进去的会打开AlarmClock这个Activity. 好像我平常都不上图的,今天就上两张图先. 一张是应用界面图如下:(改天再上传了, ...

  2. java用构造方法定义book类_JAVA基础学习之路(三)类定义及构造方法

    类的定义及使用 一,类的定义 classBook {//定义一个类intprice;//定义一个属性intnum;public static int getMonney(int price, intn ...

  3. java定义构造方法_JAVA基础学习之路(三)类定义及构造方法

    类的定义及使用 一,类的定义 classBook {//定义一个类intprice;//定义一个属性intnum;public static int getMonney(int price, intn ...

  4. JAVA基础学习之路(三)类定义及构造方法

    类的定义及使用 一,类的定义 class Book {//定义一个类int price;//定义一个属性int num;public static int getMonney(int price, i ...

  5. 如何学习Android的源代码

          做了1年2年的android app开发好多人觉得自己陷入了瓶颈期,这个时候感觉自己一般的app都可以开发出来,完成领导想要的功能,各种第三方库基本都熟练使用了,感觉没什么可学习的了,我也 ...

  6. 学习android 画板源代码,Android实现画画板案例

    郑州app开发画画板案例.布局代码是三个button和一个imagesview下面是图片. 布局代码就不展示了.下面是java代码. package cn.xhhkj.image; import an ...

  7. 由浅入深 学习 Android Binder(十一) binder线程池

    Android Binder系列文章: 由浅入深 学习 Android Binder(一)- AIDL 由浅入深 学习 Android Binder(二)- bindService流程 由浅入深 学习 ...

  8. 由浅入深 学习 Android Binder(一)- AIDL

    Android Binder系列文章: 由浅入深 学习 Android Binder(一)- AIDL 由浅入深 学习 Android Binder(二)- bindService流程 由浅入深 学习 ...

  9. 给小白分享几个学习Android的网站

    给小白分享几个学习Android的网站 前言 文档类 Android开发者联盟 Android中文社区 解答类 CSDN 简书 博客园 源码类 GitHub中文社区 码云 系统化学习类 阳光沙滩学院 ...

  10. Volley简单学习使用五—— 源代码分析三

    一.Volley工作流程图: 二.Network     在NetworkDispatcher中须要处理的网络请求.由以下进行处理: NetworkResponse networkResponse = ...

最新文章

  1. 广州创龙TMS320C6748 DSP开发板免费申请试用
  2. oracle 得到一个树,Related to Oracle SQL 关于树形数据的遍历
  3. ant react 上传_react之ant design mobile如何只能上传一张图片
  4. 先进先出算法_结构与算法(02):队列和栈结构
  5. Maven定制化打包后的包名(加入时间戳)
  6. 几万条数据的excel导入到mysql_【记录】2万多条数据的Excel表格数据导入mysql数据库...
  7. fbx模型加载的材质球路径
  8. 华为A1路由器虚拟服务器,华为a1路由器怎么设置
  9. Python爆力破解rar密码并对比多线程的效率
  10. 阿里云配置 https
  11. 多旅行商问题(MTSP)的相关论文总结
  12. Gary Marcus:AI 可以从人类思维中学习的11个启示
  13. Exchange如何配置安装导入SSL数字证书
  14. C++中std::endl的作用
  15. 记录使用Elasticsearch报错:FORBIDDEN/12/index read-only / allow delete (api)];]; nested exception is Elasti
  16. 在Activity中获取另一个XML文件的控件
  17. 01 Android Studio学习第一天
  18. Go :运行linkx测试(附完整源码)
  19. asp.net MVC使用EF框架进行分页讲解
  20. UNIAPP富文本编辑器editor组件图标不显示的问题解决

热门文章

  1. 安庆集团-冲刺日志(第四天)
  2. 2021年总结:厚积薄发,突破自我
  3. 个人微信支付接口,非二清,无需APP,支持H5
  4. 用友vs金蝶产品分析(云星空与YonSuite)
  5. python--给图片加水印
  6. 动环监控系统发展趋势
  7. 解决ThinkPad E580因AMD显卡导致系统崩溃的问题
  8. curl api接口获取当前IP地址
  9. SpingCloud获取当前服务ip地址
  10. 蚂蚁金服CTO程立:创新发展数字时代金融关键技术