CoreLocation in iOS

CoreLocation in iOS11

Posted in iOS | Tagged | Leave a comment

iOS Grand Central Dispatch

GCD provides three main types of queues:

1.1 Main queue

Main queue runs on the main thread and is a serial queue.
This is a common choice to update the UI after completing work in a task on a concurrent queue. To do this, you’ll code one closure inside another. Targeting the main queue and calling async guarantees that this new task will execute sometime after the current method finishes.

// Get the main queue
let mainQueue = DispatchQueue.main

1.2 Global queues

This is a common choice to perform non-UI work in the background.
Global queques are Concurrent queues that are shared by the whole system. There are four such queues with different priorities : high, default, low, and background. The background priority queue is I/O throttled.

// Get the .userInitiated global dispatch queue
let userQueue = .userInitiated)
// Get the .default global dispatch queue
let defaultQueue =

When setting up the global concurrent queues, you don’t specify the priority directly. Instead you specify a Quality of Service (QoS) class property. This will indicate the task’s importance and guide GCD into determining the priority to give to the task.

The QoS classes are:

  • User-interactive
    This represents tasks that need to be done immediately in order to provide a nice user experience. Use it for UI updates, event handling and small workloads that require low latency. The total amount of work done in this class during the execution of your app should be small. This should run on the main thread.

  • User-initiated
    The represents tasks that are initiated from the UI and can be performed asynchronously. It should be used when the user is waiting for immediate results, and for tasks required to continue user interaction. This will get mapped into the high priority global queue. .userInitiated).async { // 1
  let overlayImage = self.faceOverlayImageFromImage(self.image)
  DispatchQueue.main.async { // 2
    self.fadeInNewImage(overlayImage) // 3
  • Utility
    This represents long-running tasks, typically with a user-visible progress indicator. Use it for computations, I/O, networking, continuous data feeds and similar tasks. This class is designed to be energy efficient. This will get mapped into the low priority global queue.

  • Background
    This represents tasks that the user is not directly aware of. Use it for prefetching, maintenance, and other tasks that don’t require user interaction and aren’t time-sensitive. This will get mapped into the background priority global queue.

1.3 Custom queues

Queues that you create which can be serial or concurrent. These actually trickle down into being handled by one of the global queues.

  • Serial Queue
    The only global serial queue is DispatchQueue.main, but you can create a private serial queue. Note that .serial is the default attribute for a private dispatch queue:
// Create mySerialQueue
let mySerialqueue = DispatchQueue(label: "com.tang.max")
  • Concurrent Queue
    A good choice when you want to perform background work serially and track it. This eliminates resource contention since you know only one task at a time is executing. Note that if you need the data from a method, you must inline another closure to retrieve it or consider using sync.
    To create a private concurrent queue, specify the .concurrent attribute.
// Create workerQueue
let workerQueue = DispatchQueue(label: "com.tang.max", qos: .background, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)

Synchronous vs. Asynchronous

With GCD, you can dispatch a task either synchronously or asynchronously.
A synchronous function returns control to the caller after the task is completed.
An asynchronous function returns immediately, ordering the task to be done but not waiting for it. Thus, an asynchronous function does not block the current thread of execution from proceeding on to the next function.

Delaying Task Execution

DispatchQueue allows you to delay task execution. Care should be taken not to use this to solve race conditions or other timing bugs through hacks like introducing delays. Use this when you want a task to run at a specific time.
Consider the user experience of your app for a moment. It’s possible that users might be confused about what to do when they open the app for the first time — were you? :]
It would be a good idea to display a prompt to the user if there aren’t any photos. You should also consider how the user’s eyes will navigate the home screen. If you display a prompt too quickly, they might miss it as their eyes linger on other parts of the view. A one-second delay before displaying the prompt should be enough to catch the user’s attention and guide them.

let delayInSeconds = 1.0 // 1
DispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds) { // 2
  let count =
  if count > 0 {
    self.navigationItem.prompt = nil
  } else {
    self.navigationItem.prompt = "Add photos with faces to Googlyify them!"

Part 2: Operation Queues

GCD is a low-level C API that enables developers to execute tasks concurrently. Operation queue, on the other hand, is high level abstraction of the queue model, and is built on top of GCD. That means you can execute tasks concurrently just like GCD, but in an object-oriented fashion. In short, operation queues just make developers’ life even simpler.

Unlike GCD, they don’t conform to the First-In-First-Out order. Here are how operation queues are different from dispatch queues:

  • Don’t follow FIFO: in operation queues, you can set an execution priority for operations and you can add dependencies between operations which means you can define that some operations will only be executed after the completion of other operations. This is why they don’t follow First-In-First-Out.
  • By default, they operate concurrently: while you can’t change its type to serial queues, there is still a workaround to execute tasks in operation queues in sequence by using dependencies between operations.
  • Operation queues are instances of class OperationQueue and its tasks are encapsulated in instances of Operation.

2.1 Operation

Tasks submitted to operation queues are in the form of Operation instances. You can simply think of Operation as a single unit of work.
Operation is an abstract class which can’t be used directly so you have to use Operation subclasses.

Here’s a quick comparison of the two that will help you decide when and where to use GCD or Operation:

  • GCD is a lightweight way to represent units of work that are going to be executed concurrently. You don’t schedule these units of work; the system takes care of scheduling for you. Adding dependency among blocks can be a headache. Canceling or suspending a block creates extra work for you as a developer! :]
  • Operation adds a little extra overhead compared to GCD, but you can add dependency among various operations and re-use, cancel or suspend them.
  • A stand alone Operation runs synchronously. To run it off the main queue, we have to dispatch it to a queue, ,either to a dispatch queue or an Operation
open class Operation : NSObject {
    open func start()
    open func main()
    open var isCancelled: Bool { get }
    open func cancel()
    open var isExecuting: Bool { get }
    open var isFinished: Bool { get }
    open var isConcurrent: Bool { get }

    @available(iOS 7.0, *)
    open var isAsynchronous: Bool { get }

    open var isReady: Bool { get }
    open func addDependency(_ op: Operation)
    open func removeDependency(_ op: Operation)
    open var dependencies: [Operation] { get }
    open var queuePriority: Operation.QueuePriority
    @available(iOS 4.0, *)
    open var completionBlock: (() -> Swift.Void)?

    @available(iOS 4.0, *)
    open func waitUntilFinished()
    @available(iOS, introduced: 4.0, deprecated: 8.0, message: "Not supported")
    open var threadPriority: Double
    @available(iOS 8.0, *)
    open var qualityOfService: QualityOfService

    @available(iOS 8.0, *)
    open var name: String?

In the iOS SDK, we are provided with two concrete subclasses of Operation. These classes can be used directly, but you can also subclass Operation and create your own class to perform the operations. The two classes that we can use directly are:

  • BlockOperation – A BlockOperation is just a wrapper of around the default global dispatch queue, it manages the concurrent execution of one or more blocks on the default global queue. This class provides an object oriented wrapper for the apps that are already using object Operation queues and don't want to create dispatch queues as well. But being an Operation, it has more features than a dispatch queue task. It can take advantage of Operation dependencies, KVO notifications and cancelling. A BlockOperation also behaves like a dispatch group, it marks itself as finished when all its blocks have finished executing. So you can use it to track a group of executing blocks. BlockOperation blocks run concurrently, synchronously, if you need to execute blocks serially, submit them directly to a private dispatch queue, or set them up with dependencies.
  • InvocationOperation – Use this class to initiate an operation that consists of invoking a selector on a specified object.

So what’s the advantages of Operation?

  • First, they support dependencies through the method addDependency(op: Operation) in the Operation class. When you need to start an operation that depends on the execution of the other, you will want to use Operation.

  • Secondly, you can change the execution priority by setting the property queuePriority with one of these values. The operations with high priority will be executed first.

    public enum OperationQueuePriority : Int {
        case VeryLow
        case Low
        case Normal
        case High
        case VeryHigh
  • You can cancel a particular operation or all operations for any given queue. The operation can be cancelled after being added to the queue. Cancellation is done by calling method cancel() in the Operation class. When you cancel any operation, we have three scenarios that one of them will happen:

    • Your operation is already finished. In that case, the cancel method has no effect.
    • Your operation is already being executing. In that case, system will NOT force your operation code to stop but instead, cancelled property will be set to true.
    • Your operation is still in the queue waiting to be executed. In that case, your operation will not be executed.
  • Operation has 3 helpful boolean properties which are finished, cancelled, and ready. finished will be set to true once operation execution is done. cancelled is set to true once the operation has been cancelled. ready is set to true once the operation is about to be executed now.

  • Any Operation has an option to set completion block to be called once the task being finished. The block will be called once the property finished is set to true in Operation.

For example:

@IBAction func didClickOnStart(sender: AnyObject) {
    queue = OperationQueue()

    queue.addOperationWithBlock { () -> Void in
        let img1 = Downloader.downloadImageWithURL(imageURLs[0])

            self.imageView1.image = img1
    queue.addOperationWithBlock { () -> Void in
        let img2 = Downloader.downloadImageWithURL(imageURLs[1])
            self.imageView2.image = img2

    queue.addOperationWithBlock { () -> Void in
        let img3 = Downloader.downloadImageWithURL(imageURLs[2])
            self.imageView3.image = img3

    queue.addOperationWithBlock { () -> Void in
        let img4 = Downloader.downloadImageWithURL(imageURLs[3])
            self.imageView4.image = img4


How we can use NSBlockOperation to do the same, but at the same time, giving us more functionalities and options such as setting completion handler. The didClickOnStart method is rewritten like this:

@IBAction func didClickOnStart(sender: AnyObject) {
    queue = OperationQueue()
    let operation1 = NSBlockOperation(block: {
        let img1 = Downloader.downloadImageWithURL(imageURLs[0])
            self.imageView1.image = img1
    operation1.completionBlock = {
        print("Operation 1 completed")
    let operation2 = NSBlockOperation(block: {
        let img2 = Downloader.downloadImageWithURL(imageURLs[1])
            self.imageView2.image = img2
    operation2.completionBlock = {
        print("Operation 2 completed")
    let operation3 = NSBlockOperation(block: {
        let img3 = Downloader.downloadImageWithURL(imageURLs[2])
            self.imageView3.image = img3
    operation3.completionBlock = {
        print("Operation 3 completed")
    let operation4 = NSBlockOperation(block: {
        let img4 = Downloader.downloadImageWithURL(imageURLs[3])
            self.imageView4.image = img4
    operation4.completionBlock = {
        print("Operation 4 completed")

For each operation, we create a new instance of NSBlockOperation to encapsulate the task into a block. By using NSBlockOperation, you’re allowed to set the completion handler. Now when the operation is done, the completion handler will be called. For simplicity, we just log a simple message to indicate the operation is done. If you run the demo, you would see something like this in console:

Operation 1 completed
Operation 3 completed
Operation 2 completed
Operation 4 completed

2.2 Canceling Operations

As mentioned before, NSBlockOperation allows you to manage the operations:


operation1.completionBlock = {
    print("Operation 1 completed, cancelled:\(operation1.cancelled) ")
// ...


General advice

  • One QoS for tasks accessing shared resource
  • Serial queue to access shared resource
  • Avoid Operation dependency cycles
  • Be careful when calling sync()
  • Never call sync() on the current queue
  • Never ever call sync from the main queue

Grand Central Dispatch Tutorial for Swift 3(1)
Grand Central Dispatch Tutorial for Swift 3(2)
iOS Concurrency: Getting Started with NSOperation and Dispatch Queues
Apple’s Concurrency Guide
iOS Concurrency repository on Github

Posted in iOS | Tagged , , , , | Leave a comment

RxSwift Scheduler

Where we call subscribeOn() in a chain doesn't really matter when to call it. Where we call observeOn() does matter.

subscribeOn() tells the whole chain which thread to start processing on. We should only call it once per chain. If we call it again lower down the stream it will have no effect.

observeOn() causes all operations which happen below it to be executed on the specified scheduler. We can call it multiple times per stream to move between different threads.

@IBAction func rxSchedulerTest(_ sender: UIButton) {
    print("==UI \(Thread.current)")
    Observable.create { (observer: AnyObserver<Int>) -> Disposable in
            print("==Observable \(Thread.current)")
            return Disposables.create()
        .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
        .map({ (n) -> Int in
            print("==A \(Thread.current)")
            return n + 10
        .map({ (m) -> String in
            print("==B \(Thread.current)")
            return String(m)
        .observeOn(ConcurrentDispatchQueueScheduler(qos: .utility))
        .map({ (text) -> String in
            print("==C \(Thread.current)")
            return "X" + text
        .subscribe(onNext: { (text) in
            print("==D \(Thread.current)")
            print("got \(text)")
        }, onError: nil, onCompleted: nil, onDisposed: nil)

the output is

==UI <NSThread: 0x6100000748c0>{number = 1, name = main}
==Observable <NSThread: 0x60800007d400>{number = 3, name = (null)}
==A <NSThread: 0x60800007d400>{number = 3, name = (null)}
==B <NSThread: 0x6100000748c0>{number = 1, name = main}
==C <NSThread: 0x60800007d400>{number = 3, name = (null)}
==D <NSThread: 0x6100000748c0>{number = 1, name = main}
got X11

RxSwift Schedulers:

  • ConcurrentDispatchQueueScheduler
  • ConcurrentMainScheduler
  • CurrentThreadScheduler
  • DispatchQueueSchedulerQOS
  • HistoricalScheduler
  • HistoricalSchedulerTimeConverter
  • MainScheduler
  • OperationQueueScheduler
  • SerialDispatchQueueScheduler
  • VirtualTimeConverterType
  • VirtualTimeScheduler


Posted in iOS, React | Tagged , , | Leave a comment

How to generate **.cer** and **.p12** file for iOS push notification

Every time I created a new app with push notifications, iOS, I'm sure I've got everything right and then something refused to work. So this time I'm writing it down so I can't possibly get it wrong again.

Generally, we need 2 files for push notification:
* .cer file
* .p12 file

Generate cer file

  1. Apple developer, Identifiers, select the App you want to generate:

    Click Edit:
  2. Go the detail page of the App, enable Push Notifications, click Create Certificate

    It depends which environment you want to create. For AppStore environment, please click the button of Production SSL Certificate.

  3. In next page, press continue, click choose File

  4. Download the certificate and click Done

Generate p12 file:

  1. Open Keychain Access, drag&drop the cer file you just generated above:

Oooops, there is no triangle icon before the App id. That means there is problem when we generated the cer file. Probably we used the wrong certSigningRequest file.
2. Redo the generating cer file, select the correct certSigningRequest file, now we can see the small lovely triangle icon:

Right click the App ID, select Export "Apple Development iOS Push Service: …."
3. Set File Format to Personal Information Exchange(p12), click save:

Set password and click OK

  1. Done

Congratulations, now you have both cer and p12 file


Posted in iOS, Mac, Mobile | Tagged , , , | 1 Comment


vi / vim 删除以及其它命令

Commands Comments
dd 删除一行
d$ 删除以当前字符开始的一行字符
D 与d$同义
d 回车删除2行
ndd 删除以当前行开始的n行
dw 删除以当前字符开始的一个字
ndw 删除以当前字符开始的n个字
d) 删除到下一句的开始
d} 删除到下一段的开始
ndw 或 ndW 删除光标处开始及其后的 n-1 个字符。
d0 删至行首。
d$ 删至行尾。
ndd 删除当前行及其后 n-1 行。
x 或X 删除一个字符。
Ctrl+u 删除输入方式下所输入的文本。
R 恢复u的操作
J 把下一行合并到当前行尾
V 选择一行
^V 按下^V后即可进行矩形的选择了
vaw 选择单词
viw 内部单词(无空格)
vas 选择句子
vis 选择句子(无空格)
vap 选择段落
vip 选择段落(无空格)
D 删除到行尾
dl 删除当前字符(与x命令功能相同)
d0 删除到某一行的开始位置
d^ 删除到某一行的第一个字符位置(不包括空格或TAB字符)
dw 删除到某个单词的结尾位置
d3w 删除到第三个单词的结尾位置
db 删除到某个单词的开始位置
dW 删除到某个以空格作为分隔符的单词的结尾位置
dB 删除到某个以空格作为分隔符的单词的开始位置
d7B 删除到前面7个以空格作为分隔符的单词的开始位置
d) 删除到某个语句的结尾位置
d4) 删除到第四个语句的结尾位置
d( 删除到某个语句的开始位置
d) 删除到某个段落的结尾位置
d{ 删除到某个段落的开始位置
d7{ 删除到当前段落起始位置之前的第7个段落位置
dd 删除当前行
d/text 删除从文本中出现“text”中所指定字样的位置,一直向前直到下一个该字样所出现的位置(但不包括该字样)之间的内容
dfc 删除从文本中出现字符“c”的位置,一直向前直到下一个该字符所出现的位置(包括该字符)之间的内容
dtc 删除当前行直到下一个字符“c”所出现位置之间的内容
D 删除到某一行的结尾
d$ 删除到某一行的结尾
5dd 删除从当前行所开始的5行内容
dL 删除直到屏幕上最后一行的内容
dH 删除直到屏幕上第一行的内容
dG 删除直到工作缓存区结尾的内容
d1G 删除直到工作缓存区开始的内容

在Vi 中移动光标

  k        上
h   l    左  右
  j        下
Commands Comments
^ 移动到该行第一个非空格的字符处
w 向前移动一个单词,将符号或标点当作单词处理
W 向前移动一个单词,不把符号或标点当作单词处理
b 向后移动一个单词,把符号或标点当作单词处理
B 向后移动一个单词,不把符号或标点当作单词处理
( 光标移至句首
) 光标移至句尾
{ 光标移至段落开头
} 光标移至段落结尾
H 光标移至屏幕顶行
M 光标移至屏幕中间行
L 光标移至屏幕最后行
0 到行首
$ 到行尾
gg 到页首
G 到页末
行号+G 跳转到指定行
n+ 光标下移n行
n- 光标上移n行
Ctrl+g 查询当前行信息和当前文件信息
fx 向右跳到本行字符x处(x可以是任何字符)
Fx 向左跳到本行字符x处(x可以是任何字符)
tx 和fx相同,区别是跳到字符x前
Tx 和Fx相同,区别是跳到字符x后
Ctrl+b 向上滚动一屏
Ctrl+f 向下滚动一屏
Ctrl+u 向上滚动半屏
Ctrl+d 向下滚动半屏
Ctrl+y 向上滚动一行
Ctrl+e 向下滚动一行
nz 将第n行滚至屏幕顶部,不指定n时将当前行滚至屏幕顶部。
Shift+3 向上查找当前光标所处单词
Shift+8 向下查找当前光标所处单词


Commands Comments
vi filename 打开或新建文件,并将光标置于第一行首
vi +n filename 打开文件,并将光标置于第n行首
vi + filename 打开文件,并将光标置于最后一行首
vi +/pattern filename 打开文件,并将光标置于第一个与pattern匹配的串处
vi -r filename 在上次正用vi编辑时发生系统崩溃,恢复filename
vi filename1 … filename2 打开多个文件,依次进行编辑
ZZ 退出vi并保存
:q! 退出vi,不保存
:wq 退出vi并保存


Commands Comments
. 重复上一次操作


Commands Comments
C-n 匹配下一个关键字
C-p 匹配上一个关键字


Commands Comments
o 在光标下方新开一行并将光标置于新行行首,进入插入模式。
O 同上,在光标上方。
a 在光标之后进入插入模式。
A 同上,在光标之前。
R 进入替换模式,直到按下Esc
set xxx 设置XXX选项。


Commands Comments
J 把下面一行合并到本行后面


Commands Comments
/pattern 从光标开始处向文件尾搜索pattern
?pattern 从光标开始处向文件首搜索pattern
n 在同一方向重复上一次搜索命令
N 在反方向上重复上一次搜索命令
% 查找配对的括号
f< 查找字符<
f[da[ 查找 [ 并删除 [ ] 之间的字符
Ctrl+V 列选择
%s/A/B 全局查找A并用B替换A
:s/p1/p2/g 将当前行中所有p1均用p2替代,若要每个替换都向用户询问则应该用gc选项
:n1,n2s/p1/p2/g 将第n1至n2行中所有p1均用p2替代
:g/p1/s//p2/g 将文件中所有p1均用p2替换

.*[]%~$ 在Vi中具有特殊含义,若需要查找则应该加上转义字符""


  • 设置高亮
Commands Comments
:set hlsearch 设置高亮
:set nohlsearch 关闭高亮
:nohlsearch 关闭当前已经设置的高亮
  • 增量查找
Commands Comments
:set incsearch 设置增量查找
:set noincsearch 关闭增量查找
  • 在Vi中删除
Commands Comments
x 删除当前光标下的字符
dw 删除光标之后的单词剩余部分。
d$ 删除光标之后的该行剩余部分。
dd 删除当前行。
c 功能和d相同,区别在于完成删除操作后进入INSERT MODE
cc 也是删除当前行,然后进入INSERT MODE
  • 更改字符
Commands Comments
rx 将当前光标下的字符更改为x(x为任意字符)
~ 更改当前光标下的字符的大小写
  • 键盘宏操作
Commands Comments
qcharacter 开始录制宏,character为a到z的任意字符, 例如 qd
q 终止录制宏
@character 调用先前录制的宏, 例如@d
N@character 执行宏N次, 例如8@d
  • 恢复误操作
Commands Comments
u 撤销最后执行的命令
U 修正之前对该行的操作
Ctrl+R Redo
  • 在Vi中操作Frame
Commands Comments
c-w c-n 增加frame
c-w c-c 减少frame
c-w c-w 切换frame
c-w c-r 交换两个frame
  • VIM中的块操作
Commands Comments
选块 先用v,C-v,V选择一块,然后用y复制,再用p粘贴。
yy 复制当前整行
nyy 复制当前行开始的n行内容
?nyy 将光标当前行及其下n行的内容保存到寄存器?中,其中?为一个字母,n为一个数字
?nyw 将光标当前行及其下n个词保存到寄存器?中,其中?为一个字母,n为一个数字
?nyl 将光标当前行及其下n个字符保存到寄存器?中,其中?为一个字母,n为一个数字
?p 将寄存器?中的内容粘贴到光标位置之后。如果?是用yy复制的完整行,则粘贴在光标所在行下面。这里?可以是一个字母,也可以是一个数字
?P 将寄存器a中的内容粘贴到光标位置之前。如果?是用yy复制的完整行,则粘贴在光标所在行上面。这里?可以是一个字母,也可以是一个数字
ay$ 复制光标位置到行末并保存在寄存器a中
ayft 复制光标位置到当前行第一个字母t并保存在寄存器a中

* 剪切/复制/粘贴


Commands Comments
all 列出所有选项设置情况
term 设置终端类型
ignorance 在搜索中忽略大小写
list 显示制表位(Ctrl+I)和行尾标志($)
number 显示行号
report 显示由面向行的命令修改过的数目
terse 显示简短的警告信息
warn 在转到别的文件时若没保存当前文件则显示NO write信息
nomagic 允许在搜索模式中,使用前面不带“\”的特殊字符
nowrapscan 禁止vi在搜索到达文件两端时,又从另一端开始
mesg 允许vi显示其他用户用write写到自己终端上的信息
Posted in Mobile | Tagged , | Leave a comment

Vim notes

Column selection:

Ctrl + V


Replace all A with B


Find in current line

find <


Remove content between 2 characters

For example, remove the content between [ and ]: [routeName]


Vim commands(go to the beginning of the line, find [, delete around ]):


Record/Play Macro command

Begin to record to Macro **d** register


Stop recording


For example, remove the content between [ and ], and record them


Play the macro:


Play the macro again:


Play the macro in 10 lines below:

Posted in Mobile | Tagged | Leave a comment

React Study

Learn Redux with Wesbos

const router = (

render(router, document.getElementById('root'));
Posted in Mobile, React | Tagged | Leave a comment

How to use Android Battery Historian

1. Install Docker:

2. Run Docker

docker run -p 5001:9999 --port 9999

3. Fetch battery report

To obtain a bug report from your development device running Android 7.0 and higher:

$ adb bugreport

For devices 6.0 and lower:

$ adb bugreport > bugreport.txt

Then the bugreport will be exported & downloaded to current folder

4. Open browser,

go http://localhost:5001/, load the bugreport file.

5. Reference

Posted in Android, Mac, Mobile | 1 Comment

Android perssions group

All dangerous Android system permissions belong to permission groups. If the device is running Android 6.0 (API level 23) and the app’s targetSdkVersion is 23 or higher, the following system behavior applies when your app requests a dangerous permission:

  • If an app requests a dangerous permission listed in its manifest, and the app does not currently have any permissions in the permission group, the system shows a dialog box to the user describing the permission group that the app wants access to. The dialog box does not describe the specific permission within that group. For example, if an app requests the READ_CONTACTS permission, the system dialog box just says the app needs access to the device’s contacts. If the user grants approval, the system gives the app just the permission it requested.
  • If an app requests a dangerous permission listed in its manifest, and the app already has another dangerous permission in the same permission group, the system immediately grants the permission without any interaction with the user. For example, if an app had previously requested and been granted the READ_CONTACTS permission, and it then requests WRITE_CONTACTS, the system immediately grants that permission.

Any permission can belong to a permission group, including normal permissions and permissions defined by your app. However, a permission’s group only affects the user experience if the permission is dangerous. You can ignore the permission group for normal permissions.

If the device is running Android 5.1 (API level 22) or lower, or the app’s targetSdkVersion is 22 or lower, the system asks the user to grant the permissions at install time. Once again, the system just tells the user what permission groups the app needs, not the individual permissions.

Posted in Android, Mobile | Leave a comment

Java Effective

Chapter 2. Creating and Destroying Objects

  • Item 1: Consider static factory methods instead of constructors
  • Item 2: Consider a builder when faced with many constructor parameters
  • Item 3: Enforce the singleton property with a private constructor or an enum type
  • Item 4: Enforce noninstantiability with a private constructor
  • Item 5: Avoid creating unnecessary objects
  • Item 6: Eliminate obsolete object references
  • Item 7: Avoid finalizers

Chapter 3. Methods Common to All Objects

  • Item 8: Obey the general contract when overriding equals
  • Item 9: Always override hashCode when you override equals
  • Item 10: Always override toString
  • Item 11: Override clone judiciously
  • Item 12: Consider implementing Comparable

Chapter 4. Classes and Interfaces

  • Item 13: Minimize the accessibility of classes and members
  • Item 14: In public classes, use accessor methods, not public fields
  • Item 15: Minimize mutability
  • Item 16: Favor composition over inheritance
  • Item 17: Design and document for inheritance or else prohibit it
  • Item 18: Prefer interfaces to abstract classes
  • Item 19: Use interfaces only to define types
  • Item 20: Prefer class hierarchies to tagged classes
  • Item 21: Use function objects to represent strategies
  • Item 22: Favor static member classes over nonstatic

Chapter 5. Generics

  • Item 23: Don’t use raw types in new code
  • Item 24: Eliminate unchecked warnings
  • Item 25: Prefer lists to arrays
  • Item 26: Favor generic types
  • Item 27: Favor generic methods
  • Item 28: Use bounded wildcards to increase API flexibility
  • Item 29: Consider typesafe heterogeneous containers

Chapter 6. Enums and Annotations

  • Item 30: Use enums instead of int constants
  • Item 31: Use instance fields instead of ordinals
  • Item 32: Use EnumSet instead of bit fields
  • Item 33: Use EnumMap instead of ordinal indexing
  • Item 34: Emulate extensible enums with interfaces
  • Item 35: Prefer annotations to naming patterns
  • Item 36: Consistently use the Override annotation
  • Item 37: Use marker interfaces to define types

Chapter 7. Methods

  • Item 38: Check parameters for validity
  • Item 39: Make defensive copies when needed
  • Item 40: Design method signatures carefully
  • Item 41: Use overloading judiciously
  • Item 42: Use varargs judiciously
  • Item 43: Return empty arrays or collections, not nulls
  • Item 44: Write doc comments for all exposed API elements

Chapter 8. General Programming

  • Item 45: Minimize the scope of local variables
  • Item 46: Prefer for-each loops to traditional for loops
  • Item 47: Know and use the libraries
  • Item 48: Avoid float and double if exact answers are required
  • Item 49: Prefer primitive types to boxed primitives
  • Item 50: Avoid strings where other types are more appropriate
  • Item 51: Beware the performance of string concatenation
  • Item 52: Refer to objects by their interfaces
  • Item 53: Prefer interfaces to reflection
  • Item 54: Use native methods judiciously
  • Item 55: Optimize judiciously
  • Item 56: Adhere to generally accepted naming conventions

Chapter 9. Exceptions

  • Item 57: Use exceptions only for exceptional conditions
  • Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors
  • Item 59: Avoid unnecessary use of checked exceptions
  • Item 60: Favor the use of standard exceptions
  • Item 61: Throw exceptions appropriate to the abstraction
  • Item 62: Document all exceptions thrown by each method
  • Item 63: Include failure-capture information in detail messages
  • Item 64: Strive for failure atomicity
  • Item 65: Don’t ignore exceptions

Chapter 10. Concurrency

  • Item 66: Synchronize access to shared mutable data
  • Item 67: Avoid excessive synchronization
  • Item 68: Prefer executors and tasks to threads
  • Item 69: Prefer concurrency utilities to wait and notify
  • Item 70: Document thread safety
  • Item 71: Use lazy initialization judiciously
  • Item 72: Don’t depend on the thread scheduler
  • Item 73: Avoid thread groups

Chapter 11. Serialization

  • Item 74: Implement Serializable judiciously
  • Item 75: Consider using a custom serialized form
  • Item 76: Write readObject methods defensively
  • Item 77: For instance control, prefer enum types to readResolve
  • Item 78: Consider serialization proxies instead of serialized instances
Posted in Android, Mobile | Tagged | Leave a comment