为什么android.util.log会提供五种不同级别的打印输出方式?(打印输出在Logcat窗口)比如:Log.v()用于打印比较琐碎的信息;Log.d()用于打印调试信息;Log.i()用于打印比较重要的数据信息;Log.w()用于打印一些警告信息,提示程序可能存在的潜在风险;Log.e()打印程序中错误信息。-->个人理解:可在应用程序中的任何地方使用以上五种不同的Log输出方式,但是建议“有目的和区分度”地使用,只有这样才能够方便使用其过滤功能,并能够分析程序的执行路径(在不同的路径使用不用的级别输出Log)。
Android应用程序的AndroidManifest.xml文件,在注册activity时,使用的label标签指定活动(Activity)中标题栏内容。标题栏是显示在活动最顶的;此外,给主活动指定的label不仅会成为标题栏中的内容,还会成为启动器Launcher中应用显示的名称。
活动Activity部分,总结:四种状态(针对于Activity存在于任务栈中的状态:运行状态、暂停状态、停止状态和销毁状态)、三种生存期(针对于生命周期而言:完整生存期、可见生存期和前台生存期)和七个回调方法(onCreate() onStart() onResume() onPause() onStop() onDestory() onRestart()),以及四种启动模式(Standard-->SingleTop-->SingleTask-->SingleInstance)。
多个Activity之间传递值时,使用包名作为前缀(确保唯一性),例如: public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
不要BroadcastReceiver的onReceive()中执行过多的逻辑或者进行任何的耗时操作,因为广播接受者中是不允许开启线程的,当onReceive()运行了较长时间而没有结束时,程序就会报错。广播接受者更多的是扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或者启动一个服务等。
广播是一种跨进程的通信方式(应用程序能够接受系统广播)。
正是由于广播机制是一种跨进程的通信方式,很有可能会导致程序的不安全性。为了解决广播的安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能够字应用程序内部进行传递,并且广播接受者也只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。
使用本地广播的几点优势:
1. 明确地知道正在发送的广播不会离开我们的程序,不需要担心机密数据泄露;
2. 其他程序无法将广播发送到我们的程序内部,不需要担心会有安全漏洞的隐患;
3. 发送本地广播比起发送系统全局广播会带来更高效率。
Android系统提供三种方式用于简单地实现数据持久化功能,即:文件存储、SharedPreference存储以及数据库存储。除了这三种方式之外,还可以将数据保存到手机的SD卡上,不过使用前三种方式相对简单,且比起存储到SD卡中会更加安全。
文件存储方式:不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中的,比较适合用于存储一些简单的文本信息或二进制数据。如果想使用文件存储的方式来保存一些复杂的文本数据,就需要定义一套自己的格式规范,方便以后将数据从文件中重新解析出来。
Context类提供openFileOutput()用于将数据存储到指定的文件中,所有文件默认保存到/data/data/<packagename>/files/目录下。
文件存储方式不适合用于保存一些较为复杂的文本数据。
三种方式得到SharedPreferences实例:
1. Context类中的getSharedPreferences()
方法接收两个参数,前者为SharedPreferences文件名,后者为操作模式。SharedPreferences文件都是存放在/data/data/<packagename>/shared_prefs/目录下的。MODE_PRIVATE模式表示只有当前应用程序才可以对这个文件进行读写操作;MODE_MULTI_PROCESS模式(This constant was deprecated in API level 23.)一般用于会在多个进程中对同一个SharedPreferences文件读写。MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE两种模式:This constant was deprecated in API level 17. 官方已经不再推荐使用这种方式实现进程间的数据共享。而推荐使用更加安全可靠的内容提供器技术。
2. Activity类中的getPreferences()
使用这个方法时,会自动将当前的类名作为SharedPreferences文件名。
3. PreferenceManager类中的getDefaultSharedPreferences()
是一个静态方法,自动使用当前应用程序的包名作为前座来命名SharedPreferences文件。
SharedPreferences文件是使用XML的格式来对数据进行管理的。
SQLite数据库文件会存放到/data/data/<packagename>/databases/目录下。使用数据库存储数据,一般包含两个部分:数据库,以及存储在数据库中的表——table。
如果想要使用adb工具,需要将adb tool所在的路径配置到系统环境变量中;如果需要操作数据库,首先进入到数据库所在的目录,然后输入:sqlite3 database_name。
数据库操作支持事务处理,也就是让事务支持的业务逻辑执行完毕时才产生想要的效过,若中途崩溃,则退回到启动事务的起点。
ContentProvider内容提供者可以选择只对哪一个部分数据进行共享,从而保证隐私数据的安全性。
内容提供者一般有两种使用方式:一是使用现有的内容提供者来读取和操作相应程序的数据;二是创建自己的内容提供者给我们程序中的数据提供外部访问接口。
Service:Android的后台运行功能,也就是说,应用程序即使在关闭的情况下仍然可以再后台继续运行;IOS是不支持后台的,当应用程序不在前台运行时就会进入到挂起状态。服务Service是Android中实现后台运行的解决方案,适合去执行那些不需要和用户交互而且还要求长期运行的任务。服务的运行不依赖于任何用户界面,即使当程序被切换到后台,或者用户打开了另一个应用程序,服务仍然能保持正常运行。
需要注意的是,服务并不是运行在一个独立地应用程序中的,而是依赖于创建服务时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止运行。
实际上服务并不会自动开启线程,所有代码都是默认运行在主线程中的。也就是说,我们需要在服务内部手动创建子线程,并在这里执行具体的任务,否则就有可能出现主线程被阻塞的的情况。
Android的UI是线程不安全的。如果想要更新应用程序里的UI元素,则必须在主线程中进行,否则就会出现异常。如果确实需要在子线程执行耗时任务,然后根据任务的执行结果来更新相应的UI控件,该如何处理?
Android中的异步和同步机制:Synchronous同步和Asynchronous异步的概念最初来自通信领域。通信同步指客户端在发出请求后,必须要在服务端有回应后客户端才继续发送其他请求,所有的请求都会在服务端得到同步,直到服务端发返回请求;通信异步指客户端在发送请求后,不必等待服务端的回应就可以发送下一个请求,对所有的请求动作来说将会在服务端得到异步,这条请求的链路就像是一个请求队列,所有的请求动作在这里都不会得到同步。
异步消息处理机制解决子线程中进行UI操作的问题。Android中的异步消息处理主要有四个部分组成,Message(用于在不同线程之间交换数据,是在线程之间传递的消息)、Handler(主要用于发送和处理消息的)、MessageQueue(用于存放所有通过Handler发送的消息,每个线程都会有一个MessageQueue)和Looper(是每个线程中的MessageQueue的管家,每个线程只会有一个Looper对象)。
另一个工具:AsyncTask,背后的实现原理也是基于异步消息处理机制,只是Android进行了封装。
停止Service的方式:在Activity中决定服务何时启动和停止,startService()和stopService()用于服务的启动和停止。此外,在服务中调用自己的stopSelf()可以实现服务的停止。
活动和服务的通信:在活动中指挥服务去干什么,服务就去干什么;通过bindService()实现活动和服务的交互。
服务中的代码默认运行在主线程中,如果直接在服务里去处理一些耗时的逻辑,就很容易出现ANR。因此,需要在服务中创建子线程,然后在这里去处理那些耗时的逻辑。一般是在onStartCommand()中创建并开启子线程,并在其中调用stopSelf()停止服务。
Android专门提供了IntentService(),用于解决上述的两个步骤。复写onHandleIntent(),并在其中执行耗时操作,因为这个方法中的内容会在子线程中执行,而不必担心ANR的问题。在执行完上述方法后,会自动结束去执行onDestory()。上述IntentService实例集开启线程和自动停止于一身。
实践P376 中的定时任务。
使用Intent实例传递自定义对象,必要条件:自定义类必须实现Serializable或者Parcelable接口。不同之处在于:前者是将对象进行序列化,后者则将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型。虽然后者在实现上会显得复杂,但效率会更好,所以推荐使用后者。
编写测试用例,创建测试工程,进行单元测试,实践P468的单元测试功能。