《Android 4高级编程》学习摘要

  • 文件(如位图或者音频文件)通常是不存储在数据库的表中的。使用一个代表存储路径的字符串或者更好的方式是使用一个完全限定的URI来存储文件的路径。
    强烈建议所有的表都应该包含一个自动增加的键字段,作为每一行的唯一索引字段。如果计划使用ContentProvider来共享表,就必须具有唯一的ID字段。
  • 当你认为要查找的列在所有情况下都存在时,使用getColumnIndexOrThrow是一种很好的做法,当列在一些情况下不存在时,使用getColumnIndex并检查结果是否为-1是比捕获异常更加高效的方法。
  • 数据库实现应该发布一些提供了列名称的静态常量,这些静态常量通常在数据库的合同类或者Content Provider内公开
  • 技术使用结果Cursor后关闭它非常重要,这样可以防止内存泄露,并降低应用程序的资源负载。
  • 数据库操作的insert方法的第二个参数为null列侵入(null column hack),如果想在一个SQLite数据库中添加一个空行,在传入一个空的ContentValues对象的同时,还必须传入一个值可以显示设置为null的列的名称。一般来说,确保代码不会尝试在一个SQLite数据库中插入空的ContentValues对象是一种很好的做法。
  • 每个Content Provider都应该使用一个公有的静态CONTENT_URI属性来可公开它的授权,使其更容易被找到。
  • 考虑到效率因素,在应用程序运行的时候,最好打开Content Provider,如果系统需要额外的资源,应用程序将会关闭,与之关联的数据库也会关闭,所以再任何时候都没必要手动关闭数据库。
  • UriMacher对象用于完善事务处理和查询请求,而SQLiteQueryBuilder是执行基于行查询的便利辅助类。
  • 要初始化一个新的Loder,需要调用LoaderManager的initLoaer方法,这个过程通常在宿主Activity的onCreate方法(对于Fragment,则是onActivityCreated)中完成的。
  • 如果标识符对应的Loader不存在,在关联的LoderCallback的onCreateLoader处理程序中创建这个Loader。LoaderManager会处理你初始化的任何一个Loader的生命周期以及底层的查询和Cursor。
  • 创建Activity后,更新onCreate处理程序来初始化Loader,当Activity重新启动后,更新onResume处理程序来重新启动Loader。
  • 通常情况下用户不希望把重复的查询添加到”返回栈“中,所以最好将基于ListView的搜索Activity设置为Single Top模式,这样就会保证同一个实例会被重复使用,而不是每一个搜索都创建一个实例。
  • 通常会使用Data表来添加、删除或修改已有的联系人账户存储的数据,使用RawContacts表来创建和管理账户,并使用Contact和Data表来查询数据库以提取联系人详情。
  • OnStartCommand处理程序是在API LEVEL5之后引入的,代替了现在已经不再建议使用的onStart事件。它提供了与onStart方法一样的功能,但是还允许你告诉系统,如果系统在显式调用stopService或stopSelf之前终止了Service,那么应该如何重新启动Service。现在实现onStart处理程序等同于重写onStartComman并返回START_STICKY
  • 实现Service的标准模式是从onStartCommand中创建和运行一个新线程,用来在后台执行处理,并在线程完成后终止这个service。
  • Android应用程序(正常情况下)不共享内存,但是在某些情况下,应用程序可能希望与运行不同应用程序进程中的Service进行交互(和绑定)。AIDL使用系统级的原语定义了Service的接口,允许Android跨进程传递对象。
  • 当在GUI环境中使用后台线程的时候,在尝试创建和修改UI元素之前同步子线程和主应用程序(GUI)线程十分重要。如果在Activity中运行,那么也可以使用runOnUiThread方法,它可以强制一个方法在与ActivityUI相同的线程中执行。可以使用Handler类将方法发布到创建该Handler的线程上,使用Handler类的Post方法将更新从后台线程发布到用户界面上。
  • 对于那些只在应用程序的生命周期内发生的定式操作,将Handler类和Timer以及Thread组合起来使用是一种比使用Alarm更好的方法,因为这样做允许Android更好地控制系统资源。通过将调度事件移出应用程序的控制范围,Alarm提供一种缩短应用程序生命周期的机制。
  • setInexactRepeating方法能够帮助减少电源消耗,在运行时,Android会同步多个没有精确指定时间间隔的重复Alarm,并同时触发它们。设置定期重复Alarm会对电池电量产生显著的影响,最好将Alarm频率限制为最低可接受频率,只在必要时唤醒设备,并且尽可能使用没有精确指定时间间隔的重复Alarm。
  • 如果任意的Activity使用了(默认的)Theme.Holo主题,并且它的应用程序的目标(或最小)SDK版本在11或更高,那么它的操作栏是启用的。
  • 操作栏是在Android3.0中引入的,在运行3.0之前的平台中,一种选择是创建不同的布局,这种布局需要实现自己的自定义操作栏——通常是以Fragment的形式——以提供了你的功能。溢出菜单也是3.0中引入的,它们代替了硬件菜单栏和相关联的选项菜单。
  • 图标菜单和操作栏中的菜单栏不能显示复选框、单选按钮或者快捷键,因此最好不要依赖于图标菜单或者操作中的复选框和单选按钮,因为它们将是不可见的。
  • 要想给Activity添加一个菜单,需要重写它的onCreateOptionsMenu处理程序。在Android3.0之前,当Activity的菜单第一次显示的时候会触发这个处理程序;在3.0及以上版本中,每次Activity布局完成后创建操作栏的时候触发该处理程序。
  • 如果在Fragment中创建的菜单项,可以选择在Activity或者Fragment的onOptionsItemSelected处理程序中处理它们。注意,Activity会首先收到选中的菜单项,如果Activity处理了并返回true,Fragment将不会再收到这个菜单项。
  • 子菜单不能用作操作,Android也不支持嵌套的子菜单。
  • 当目标设备运行的是Android3.0或者以上版本时,最好使用弹出菜单而不是上下文菜单。
  • 隐藏系统栏在Android3.0与4.0所使用的标志不同。
  • Dialog Fragment是在Android3.0中引入的,它代替了已经不再使用的Activity.onCreateDialog和Activity.onPrepareDialog处理程序,而Dialog Fragment包含在Android支持包中,从而在Android1.6版本以后的平台中,都可以在项目中使用它。要想使用Dialog Fragment可以扩展DialogFragment类,注意只能重写onCreateView和onCreateDialog中的一个,如果重写两个,将导致抛出一个异常。
  • 一般来说,应用程序只有在其中的一个Activity处于激活状态时才可以显示Toast。
  • Notification Builder是在Android3.0中引入的,是为较新的Android平台构造Notification的首选方式。
  • RemoteViews是这样一种机制,它允许嵌入和控制一个内嵌在独立应用程序中的布局。比较常用的情况是创建主屏幕上的微件。RemoteViews类用作在另一个应用程序的进程中托管的View层次的代理,从而允许修改运行在另一个应用程序中的View的属性或运行该View的方法。
  • 对于Android3.0以前的版本,不仅要分配给Notification一个contentView属性,还要设置contentIntent,否则在触发Notification的时候会抛出一个异常。
  • 前台Service必须具有持续的Notification。
  • 由于连续的Notification干扰性较强,因此在第三方应用程序中尽量少使用它。这也就是为什么在Notification Builder中没有对应的方法用来设置连续Notification标志。
  • 在任意时刻,剪贴板只能包含一个ClipData对象。复制一个新的对象会替换之前持有的剪贴板对象。
  • 所有硬件按钮和按键的按下事件都是由处于活动状态的Activity或者当前的前台View的onKeyDown和onKeyUp处理程序进行处理的。主页键是唯一的例外,它被保留用来保证用户永远都不会被锁定在一个应用程序中。
  • getLastKnownLocation并不要求Location Provider更新当前位置。如果设备最近没有更新当前位置,那么getLastKnownLocation返回的位置可能不存在或者已过期。
  • Android支持有限数量的同步Media Player对象,如果不释放它们,将会在系统耗尽资源时导致运行时异常。所以完成播放时应调用release释放相关资源。
  • 创建音频对象的时候如果调用MediaPlayer的create方法返回的MediaPlayer对象已经调用了prepare,因此不再调用该方法十分重要。也可以使用new MediaPlayer()拿到一个MediaPlayer对象,再使用setDataSource方法,这种方式在开始播放之前调用prepare方法十分关键。
  • SurfaceView类是SurfaceHolder对象的包装器,后者是Surface的包装器,而Surface用于支持来自于后台线程的可视化更新。
  • SurfaceHolder是异步创建的,因此必须等待直到SurfaceCreated处理程序被触发,然后再通过实现SurfaceHolder.Callback接口获得返回的SurfaceHolder对象。
  • 直到Android4.0,用于后台数据传输的用户首选项是在应用程序级实施的,这意味着对于4.0以前的平台,你自己必须负责遵循用户的首选项来允许后台数据传输。如果禁用了后台数据传输,那么你的应用程序将当且仅当在它处于活动状态并位于前台时传输数据。在4.0及更高的版本,getBackgroundDataSetting已被弃用,并且总是返回true。现在这些首选项是在系统级实施的,意味着如果数据传输对你的应用程序不可用,那么尝试数据或者检查网络连接状态的操作都将失败,设备将呈现为离线状态
  • NFC在Android2.3中引入,是一种非接触式的技术,用于在短距离(通常小于4厘米)内少量数据的传输

版权声明

![Creative Commons BY-NC-ND 4.0 International License](/images/cc.png)

Lam’s Blog by Binghe Lin is licensed under a Creative Commons BY-NC-ND 4.0 International License.
林炳河创作并维护的Lam’s Blog采用创作共用保留署名-非商业-禁止演绎4.0国际许可证

本文首发于Lam’s Blog - Knowledeg as Action,版权所有,侵权必究。

本文永久链接:http://linbinghe.com/2017/882e7bb0.html