Sean's Note: 2014

2014年12月28日 星期日

Setting up TortoiseGit with GitHub

安裝環境

  1. 安裝 TortoiseGit 1.8.12.0。
  2. 安裝 Git for Windows 1.9.5。

建立 Git 的 repository

  1. 在要作為 repository 的資料夾上按右鍵 "Get Create repository here...",跳出視窗時
    不需勾選 "Make it Bare",完成後資料夾裡就會出現一個 .git 的隱藏資料夾。
  2. 在 Git 的 Settings -> Git 裡設定 User Info。

Commit 到 Local 端

  1. 在資料夾上按滑鼠右鍵 "Git Commit -> "master"...",此時只是 commit 程式碼到  Local 端而已,還沒 commit 到 GitHub。

Push/Pull 到 GitHub

  1. 先到 GitHub 上建立一個新的 repository。
  2. 點進該新的 repository 後,右側欄可以看到 clone URL 的選項,複製 SSH 的。
  3. 在 Git 的 Settings -> Remote 裡加入一個新的 remote,名字隨便取,URL 貼上剛剛所複製的。

    SSH URL
  4. 要上傳程式碼到 GitHub 之前,要先建立 key,在 TortoiseGit 的資料夾裡找到 "PuTTYgen" 後開啟,滑鼠在中間空白的區域亂滑以建立 key,然後 "Save private key" 到某個地方。

    PuTTY Key Generator
  5. 再把 Public Key 給 copy 下來,到 GitHub 的 Settings -> Personal settings -> SSH keys -> Add SSH key,然後貼上。
  6. 在 TortoiseGit 的資料夾裡找到 "Pageant" 開啟,加入剛剛建立的 private key。

    Pageant
  7. 終於,可以開始 Push 程式碼啦!?
    在資料夾上按滑鼠右鍵 "TortoiseGit" -> "Push ...",跳出 Push 的視窗,OK 送出。

    Push
  8. 如果遇到 error: failed to push some refs to '...........'
    git did not exit cleanly (exit code 1),那就先把 repository 從 GitHub Pull 回來一次,就可以 Push 了!
git did not exit cleanly (exit code 1)


2014年12月27日 星期六

[Eclipse] Java was started but returned exit code=13

至從把 Java 從 7 更新到 8 後,開 Eclipse 突然出現了錯誤:

Java was started but returned exit code=13

後來發現 java 更新到 32bit 的版本,但 Eclipse 用的是 64bit 的版本,

所以在重裝一次 64bit 的 Java 8 就好了。

exit code=13

2014年12月22日 星期一

[讀書筆記] Effective Objective-C - Chapter 2

2. Objects, Messaging, and the Runtime

Item 6: Understand Properties

  1. Four categories of attributes can be applied: 
    1. Atomicity: atomic(default)/nonatomic
    2. Read/Write: readwrite/readonly
    3. Memory-Management Semantics: assign, strong, weak, unsafe_unretained, copy
    4. Methods Names: getter=<name>, setter=<name>
  2. If you implement your own accessors, you should make them adhere to specified attributes yourself.
  3. Never use use your own accessors in an init(or dealloc) method.
  4. All properties are declared nonatomic on iOS because the locking introduces such an overhead on iOS, and it doesn't ensure thread safety.

Item 7: Access Instance Variables Primarily Directly When Accessing Them Internally

  1. Prefer to read data directly through instance variables internally and to write data through properties internally. 
Additional Study: Should I Use a Property or an Instance Variable?

Item 8: Understand Object Equality

  1. Use isEqualToString: is faster than calling isEqual:.
  2. Objects that are equal must have the same hash, but objects that have the same hash do not necessarily have to be equal.
  3. Be aware of what can happen when you mutate on object that's in a collection.

Item 9: Use the Class Cluster Pattern to Hide Implementation Detail

  1. Factory pattern is one way of creating a class cluster.
  2. There is no abstract base class for Objective-C. Instead, convention foe how to use a class should be made in documentation.
  3. Most of collection classes are class clusters, such as NSArray and NSMutableArray.
  4. Should use isKindOfClass: rather than class when comparing class cluster.

Item 10: Use Associated Objects to Attach Custom Data to Existing Classes

  1. objc_setAssociatedObject, objc_getAssociatedObject
  2. The accessing of associated objects is functionally similar to imaging that the object is an NSDictionary. An import difference is that key is treated purely as an opaque pointer. Thus, it's common to use static global variables for the keys.
  3. Can be used on delegate protocol methods.
  4. Can easily introduce hard-to-find bugs. 

Item 11: Understand the Role of objc_msgSend
  1. void objc_msgSend(id self, SEL cmd, ...)
  2. The function loos through the list of methods implemented by the receiver's class. It caches the result in a fast map, one for each class.

Item 12: Understand Message Forwarding

  1. It's not compile-time error to send a message to a class that it doesn't understand, since methods can be added to classes at runtime. When it receives a method that it doesn't understand, an object goes through message forwarding.
  2. The forwarding pathways are split into two avenues:
    Dynamic Method Resolution
    +(BOOL)resolveInstanceMethod:(SEL)selector
    +(BOOL)resolveClassMethod:(SEL)selector

    Replacement Receiver
    -(id)forwardingTargetForSelector:(SEL)selector
    Full Forwarding Mechanism
    -(void)forwardInvocation:(NSInvocation*)invocaiton

Item 13: Consider Method Swizzling to Debug Opaque Methods

  1. Swizzling is the process of swapping one method implementation for another, usually to add functionality to the original implementation. 
  2. class_getInstanceMethod, method_exchangeImplementaitons
  3. Useful for debugging.

Item 14: Understand What a Class Object Is

  1. Always prefer introspection methods were possible, rather than direct comparison of class objects, since the object may implement message forwarding.

 

2014年12月11日 星期四

[讀書筆記] Effective Objective-C - Chapter1

1. Accustoming Yourself to Objective-C

Item 1: Familiarize Yourself with Objective-C's Roots

  1. It uses messaging structure with dynamic binding rather than function calling.
  2. Memory for objects is always allocated in heap space and never on the stack.
  3. Some variables like CGRect not holding Objective-C objects are using stack space.

Item 2: Minimize Importing Headers in Headers

  1. Use forward declaration to decrease compile time. EX: @class EOCEmployer;
  2. Using forward declaration also alleviates the problem of both classes referring to each other.

Item 3: Prefer Literal Syntax over the Equivalent Methods

  • Literal Arrays
    NSArray *arrayA = [NSArray arrayWithObjects:object1, object2, object3, nil];NSArray *arrayB = @[object1, object2, object3];
    If object2 is nil, the literal array, array B, will cause the exception to be thrown, However, arrayA will still be created but will contain only object1.
  • Literal Arrays
    Similar to above.
  • Limitations
    If a mutable variant is required, a mutable copy must be taken.
    EX: NSMutableArray *mutable = [@[@1, @2, @3, @4, @5] mutableCopy]; 

Item 4: Prefer Typed Constants to Preprocessor #define

  1. Type constants have type information(More readable).
  2. The usual convention for constants is to prefix with the letter k for constants that are local to a translation unit. For constants that are exposed outside of a class, it's usual to prefix with the class name.

Item 5: Use Enumerations for States, Options, and Status Codes

  1. C++11 brought some changes like the capability to dictate the underlying type used to store variables of the enumerated type.

2014年12月4日 星期四

ViewPager shows nothing with PagerAdapter

除了要 Override 並實作 instantiateItem 方法之外,
不要忘了 Override isViewFromObject
@Override
public boolean isViewFromObject(View view, Object object) {
    return view==object;
}

2014年11月18日 星期二

[iOS8] How to show menu(Cut, Copy, Paste or custom action) when long pressing the cell of UITableView?

如果是用 UITableViewCell,只需要 override 三個方法:

//
// CustomUITableView.m
//

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

//
// CustomUITableView.m
//

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

-(BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    return YES;
}

//  Need to override even perform nothing.
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    if (action == @selector(copy:)) {
        UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
        UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard];
        [pasteBoard setString:cell.textLabel.text];
    }
}

長按 cell 後就會跳出 Cut, Copy 和 Paste:

圖1. UIMenuController

但如果要設定自己的 menu item 如果不 subclass UITableCellView,長按 cell 也只會跳出 

Cut, Copy 和 Paste,不會看到自己透過 setMenuItems 所加入的 UIMenuItem。

這時就需要 subclass UITableCellView:

//
// CustomUITableView.m
//

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    UIMenuItem *testMenuItem = [[UIMenuItem alloc] initWithTitle:@"Test" action:@selector(test:)];    
    [[UIMenuController sharedMenuController] setMenuItems: @[testMenuItem]];
    [[UIMenuController sharedMenuController] update];
}

//
// CustomUITableViewCell.m
//

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender{
     NSLog(@"CustomTableViewCell: %@\n", NSStringFromSelector(action));
    // There will be lots of default items if don't check.
    if (action == @selector(copy:) || action == @selector(test:))
        return YES;
    return NO;
}

// It's said need to be overrode from forums, but test ok without overriding it.
//-(BOOL)canBecomeFirstResponder {
//    return YES;
//}

/// this methods will be called for the cell menu items
-(void) test: (id) sender {
    NSLog(@"CustomTableViewCell: test!");
}

2014年11月14日 星期五

Class Extensions Extend the Internal Implementation

常會看到在 .h 和 .m 檔裡都有 @interface 的敘述,一開始覺得很納悶,@interface
不是只要寫在 .h 就好了嗎?不過仔細看又略有不同,在 .m 的 @interface 敘述後面還多了
小括號 ()。

// Classname.m

@interface Classname() {
    id _instanceVar;
}

@property NSObject *extraProperty;

@end

原來這種用法叫做類別延伸 (class extenstion)。好處在於可以定義額外的 property, 實體
變數(需要定義在大括號裡)和方法來擴充類別,而在這個匿名的 category 所以定義的方法,
必須在這個類別的 implementation 區段實作。這些 private 的方法和 property 讓類別延伸也符合了 OO 中封裝 (Encapsulation) 的精神,不需要將實作的資料和內容被看見。
另外一個常見的 property 用法便是對外宣告為 readonly 對內為 readwrite:

// XYZPerson.h

@interface XYZPerson : NSObject
...
@property (readonly) NSString *uniqueIdentifier;
- (void)assignUniqueIdentifier;
@end

// XYZPerson.m 

@interface XYZPerson ()
@property (readwrite) NSString *uniqueIdentifier; // readwrite 是 default 的屬性所以也可省略不寫
@end

@implementation XYZPerson
...
@end

2014年11月12日 星期三

How to get asset's information from the device?

在 iOS 4.0 之後,ALAsset 這個類別提供了 - valueForProperty 方法來取得 asset 的資訊,

文件裡定義了八種:

NSString *const ALAssetPropertyType ;
NSString *const ALAssetPropertyLocation ;
NSString *const ALAssetPropertyDuration ;
NSString *const ALAssetPropertyOrientation ;
NSString *const ALAssetPropertyDate ;
NSString *const ALAssetPropertyRepresentations ;
NSString *const ALAssetPropertyURLs ;
NSString *const ALAssetPropertyAssetURL;
咦?怎麼沒有名稱 Name 呢?

想要取得名稱和檔案大小其他的資訊得透過 ALAssetRepresentation 來取得。

ALAssetRepresentation *rep = [asset defaultRepresenttion];
[rep filename];
[rep size];

What is the use of "#pragma mark" in codes?

程式中的 #pragma mark 本身對程式碼並無意義,僅用來幫助組織編排程式,

方便將一群方法分類,以便於在 Jump bar 中快速查詢。

例如:

#pragma mark - 即是加一條分隔線。
#pragma mark Initialization 即是將以下的方法列於 Initialization 標題之下。

圖1. Jump bar

2014年11月11日 星期二

[Xcode 6.1] Be careful with the order of "First Item" and "Second Item" when editing constraint

根據官方的文件, space constraint 的數學公式如下:

FirstItem.Attribute1 = (SecondItem.Attribute2 * Multiplier) + Constant

所以對調 "First Item" 跟 "Second Item" 的結果將會不同,

以圖1 為例 Superview.Trailing = (Text Filed.Trailing * 1 ) + 10,

代表有一個 Text Filed 元件的右邊將會置於父視圖的右邊數來 10 個單位距離。

圖1. Space Constraint
但若將兩者對調,將變成 Text Filed.Trailing = ( Superview.Trailing* 1 ) + 10,

最後的結果,Text Filed 元件右邊的位置將會超出父視圖的範圍。

Ref: https://developer.apple.com/library/ios/recipes/xcode_help-IB_auto_layout/chapters/EditingConstraintAttributesintheAttributesInspector.html

[Xcode Common Errors] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' ...

當 console 出現下列訊息時:

Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?

檢查看看第一個 View Controller 的 Attributes Inspector 頁面 "Is Initial View Controller"

是否忘了勾選?

圖1. Attributes Inspector

2014年10月30日 星期四

Object-C 語法摘要

類別、物件及方法

  1. Case Sensitive
  2. C:
    print("Hello %d", 1);
    Object-C:
    NSLog(@"Hello %i", 1); // NSLog 會自動換行
  3. C:
    a.print(2);
    Object-C:
    [ClassOrInstance method : params] -> [a print : 2];
  4. C:
    ClassA* A = new A();
    Object-C:
    ClassA* A = [[ClassA alloc] init];
    ClassA* A = [ClassA new];
  5. Object-C 支援 id 泛型, NSLog 用 "%p"。

迴圈、制定決策

  1. if, while, for, switch 的用法幾乎和 C 沒什麼不同。
    Note: 只有當 if (0) 的時侯為條件不成立,包括 nil 和 NO。
  2. BOOL 是用 YES/NO 表示,而不是 true/false。

類別、繼承

  1. Accessor Method 可以直接用下列語法表示:
    @interface ...
    @property int a;

    @implementation ...
    @synthesize a;   // XCode 4.5 之後 @synthesize 可省略
  2. 宣告於介面區段是屬於 public 的,而實作區段的的變數是屬於 private 的。
  3. 可用 #import "XYPoint.h" 也可用 @class XYPoint; 來引用類別,而使用
    @class 指令比較有效率,因為編譯器不需要處理整個 XYPoint.h。

類目與協定

  1. 多了 category 跟 protocol 的用法。( protocol 類似於 Java 的 interface)

Blocks


  1. 以 ^ 為開頭。
  2. 多當作 callback 來使用。
  3. 宣告在 blocks 之前的區域變數可以在 block 內引用(唯讀),除非在宣告變數時加上 __block。
  4. 在 block 裡引用 self 將會造成 Memory cycles,試著使用 weak reference:
    __weak MyClass *weakSelf self;


Ref: 精通 Object-C 程式設計 第六版

2014年10月24日 星期五

[Android 5.0] Vector Drawables

從 Android 5.0 開始,Drawable 新增了可縮放向量圖形 (SVG) 的用法,

優點是可以任意縮放圖片卻不會失真。

只要在 XML 檔裡定義即可使用,下面是官方所提供的範例(改成紅色的):

<!-- res/drawable/heart.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- intrinsic size of the drawable -->
    android:height="256dp"
    android:width="256dp"
    <!-- size of the virtual canvas -->
    android:viewportWidth="32"
    android:viewportHeight="32">

  <!-- draw a path -->
  <path android:fillcolor="#ff0000" 
           android:pathdata="M20.5,9.5
                             c-1.955,0,-3.83,1.268,-4.5,3
                             c-0.67,-1.732,-2.547,-3,-4.5,-3
                             C8.957,9.5,7,11.432,7,14
                             c0,3.53,3.793,6.257,9,11.5
                             c5.207,-5.242,9,-7.97,9,-11.5
                             C25,11.432,23.043,9.5,20.5,9.5z">
  </path>
</vector>
圖1. Heart


Vector 詳細有哪些屬性可以設定,可以參考新增的 VectorDrawables 類別

pathdata 中語法和 SVG 的語法一樣 M 指的是 moveto,C 是 curveto,z 是 closepath,

大寫為絕對位置,小寫為相對位置,更多 pathdata 的用法可以直接參考 SVG 的文件

畫了個西瓜來當練習:

<!-- res/drawable/heart.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
           android:height="256dp" 
           android:viewportheight="32" 
           android:viewportwidth="32" 
           android:width="256dp" >

  <!-- watermelon-->
  <path android:fillcolor="#ff0000" 
           android:strokecolor="#086D08" 
           android:strokewidth="1"
           android:pathdata="M3,3 
                             C3,13 23,13 23,3"  />
  
  <!-- seed-->
  <path android:fillcolor="#000000" 
           android:strokecolor="#000000" 
           android:strokewidth="0.5"
           android:pathdata="M5,4 
                            a0.2,0.2 0 1,0 0.4,0 
                            a0.2,0.2 0 1,0 -0.4,0"  />
  
  <!-- seed-->
  <path android:fillcolor="#000000" 
           android:strokecolor="#000000" 
           android:strokewidth="0.5"
           android:pathdata="M8,6 
              a0.2,0.2 0 1,0 0.4,0 
              a0.2,0.2 0 1,0 -0.4,0"  />
  
  <!-- seed-->
  <path android:fillcolor="#000000"
           android:strokecolor="#000000" 
           android:strokewidth="0.5" 
           android:pathdata="M12,8 
              a0.2,0.2 0 1,0 0.4,0 
              a0.2,0.2 0 1,0 -0.4,0"  />
    
  <!-- seed-->
  <path android:fillcolor="#000000" 
           android:strokecolor="#000000" 
           android:strokewidth="0.5"
           android:pathdata="M14,5 
                            a0.2,0.2 0 1,0 0.4,0 
                            a0.2,0.2 0 1,0 -0.4,0"  />
    
  <!-- seed-->
  <path android:fillcolor="#000000" 
           android:strokecolor="#000000" 
           android:strokewidth="0.5"           
           android:pathdata="M18,6 
                            a0.2,0.2 0 1,0 0.4,0 
                            a0.2,0.2 0 1,0 -0.4,0"  />
    
  <!-- seed-->
  <path android:fillcolor="#000000" 
           android:strokecolor="#000000" 
           android:strokewidth="0.5"
           android:pathdata="M20,4 
                             a0.2,0.2 0 1,0 0.4,0 
                             a0.2,0.2 0 1,0 -0.4,0"  />


圖2. Watermelon


2014年10月22日 星期三

Use Enum to implement finite state machine

範例:
public enum StateMachine {
 
    INITIAL {
        @Override
        public StateMachine next() {
            return SECOND;
        }
    },
    SECOND {
        @Override
        public StateMachine next() {
            return THIRD;
        }
    }
    // ... other states
    
    public abstract StateMachine next();
    
    // ... other methods
}

2014年10月15日 星期三

How to prevent the view from restoring it's state after restart?

View 有個屬性 android:saveEnabled,預設為 true,只要把它設成 false,
系統就不會幫你回復它的狀態(View.onSaveInstanceState() 不會被呼叫),
另外要注意的是,該 flag 僅對自己有效,不會影響其 childs。

Ref: http://developer.android.com/reference/android/view/View.html#attr_android:saveEnabled


2014年10月1日 星期三

Running C/C++ on Android with NDK [Updated]

需要準備的環境

  1. Eclipse + Android SDK: 基本的 Android 開發環境
  2. Android NDK: 讓 Android 能透過 JNI 去執行 C/C++ 語言的必要套件
  3. Eclipse NDK: Eclipse 的 plugin 套件,方便管理與建立 NDK 的專案
    Work with: https://dl-ssl.google.com/android/eclipse/
    安裝好之後要設定 Android NDK 的路徑:
    Window -> Preferences -> Android -> NDK -> NDK Location:

    如果 NDK Path 擺在 Program Files 或 Program Files (x86) 底下,在 Build Project 時,
    可能會出現以下錯誤:
    "C:\\Program Files (x86)\\Android\\android-ndk-r10b\\ndk-build.cmd" all
    ERROR: NDK path cannot contain any spaces!

    解決方法:
    C:\Program Files -> C:\progra~1
    C:\Program Files (x86) -> C:\progra~2
Note: NDK r9 的版本之後已內建 toolchains,所以不需要另外安裝 Cygwin。

新建一個專案


新增一個  C:\Program Files (x86)\Android\android-ndk32-r10b\samples\hello-jni 專案,

然後在 Project 上按右鍵 -> Android Tools -> Add Native Support...

除錯


除錯時要將 Project -> Properties -> C/C++ Build -> Builder Settings -> Build Command:

加上 ndk-build NDK_DEBUG=1,建置時才會產生除錯所需要的檔案。

在這之後可能會遇到兩個問題:
  1. 無法在 .c 或 .cpp 檔上設置中斷點?
    Run -> Breakpoint Types  -> C/C++ Breakpoints
  2. 設完中斷點後,卻沒有停在中斷點上?
    No symbol table is loaded. Use the "file" command.
    由於 GDB debugger 需要一點時間運算,而 GDB 可能還沒載入 Library 的 Symbol,
    如果中斷點設得太早可能會被忽略,
    解決的辦法請參考:
    http://www.codeproject.com/Articles/493043/Why-your-Android-NDK-breakpoints-might-fail-and-ho

2014年9月12日 星期五

New Android Application - appcompat_v7

至從更新 ADT 到某版之後,每次建立新專案都會自動蹦出一個 appcompat_v7 專案,
後來找到解決的方式,只要在建立新專案時,最低 SDK 版本 (Minimum Required SDK)
指定為 API 14(即 Android 4.0),就不會出現appcompat_v7。

2014年8月11日 星期一

How to get an unique ID from Android device?

我們有時候會想要取得一組 UID,來判斷是否為不同的 Android 裝置,除了

Java 本身提供的 UUID,是不是還有其他的方法呢?

以下整理了五種方法(Test with Sony ZL 4.4.2):
  1. UUID
    利用 UUID 類別的方法 randomUUID() 產生一組 128-bit 組成的 UUID:
    String uuid = UUID.randomUUID().toString();
    Log.d(TAG, "UUID: " + uuid); // UUID: faffffe6-a504-4252-b92a-c5b555811123
    

  2. IMEI/MEID/ESN
    利用 TelephonyManager 類別的方法 getDeviceId(),在 GSM 的手機上取得 IMEI 或
    在 CDMA 的手機上取得 MEID 或 ESN 的值:
    // Required permission: android.permission.READ_PHONE_STATE
    
    TelephonyManager telManager=(TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
    String imei = telManager.getDeviceId();
    Log.d(TAG, "IMEI: " + imei); // IMEI: 3553XXXXXXXXXXX
    
    

  3. Android ID
    取得由靜態類別 Secure 的靜態變數 ANDROID_ID 所表示的 16進位字串。
    String androidID = Secure.getString(this.getBaseContext().getContentResolver(), Secure.ANDROID_ID)
    Log.d(TAG, "Android ID: " + imei); // Android ID: 826458105eXXXXXX
    
    
    Note: 有些廠商的手機的 Android ID 有重複出現的情況,而且一但使用者回復原廠設定
    時,此 ID 有可能會改變。

  4. Wifi Mac
    透過 WifiInfo 類別的方法 getMacAddress() 取得 Mac Address:
    // Required permission: android.permission.ACCESS_WIFI_STATE
    
    WifiManager wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
    WifiInfo wifiInfo = wifiManager.getConnectionInfo();
    Log.d(TAG, "MacAddress: " + wifiInfo.getMacAddress()); // MacAddress: b4:XX:XX:XX:42:fc
    
    
    Note: 沒有開啟 Wifi 時可能會回傳 null,但 Sony ZL 是都要的到。

  5. Serial
    透過 Build 類別的靜態變數 SERIAL 取得手機的硬體序號:
    String buildSerial = android.os.Build.SERIAL;
    Log.d(TAG, "BuildSerial: " + buildSerial); // BuildSerial: EP7323XXXX
    
    
    Note: API Level 9 以上才支援,不保證每台裝置都有。

Ref: http://android-developers.blogspot.tw/2011/03/identifying-app-installations.html

RFC 1867 - Form-based File Upload in HTML

在 RFC 1867 被提出之前,Form 的 INPUT 的類別僅有八種: CHECKBOX, HIDDEN, IMAGE,
PASSWORD, RADIO, RESET, SUBMIT, TEXT。在這之中似乎少了 FILE 可以讓使用者上傳檔
案。於是這份 RFC 便提出了兩個提案:
  1. 使 INPUT 多一個 FILE 的選項。
  2. 允許 INPUT 有一 ACCEPT 的屬性,指定可上傳的檔案類別。
由於原本的 application/x-www-form-urlencoded ,在傳輸大量的位元資料效率不彰,
所以也定義了新的 MIME 類別 multipart/form-data。
當撰寫 HTML 的程式設計師想向使用者請求一或多個檔案便可以寫成:
 <FORM ACTION="http://server.dom/cgi/handle" 
  ENCTYPE="multipart/form-data"
  METHOD=POST>
  What is your name? <INPUT TYPE=TEXT NAME=submitter>
  What files are you sending? <INPUT TYPE=FILE NAME=pics>

multipart/form-data 根據表單欄位包含了許多個部分,每個部分都應帶有:
  • Header: content-disposition: form-data; name="xxxxx",name 即是該欄位在表單中的名稱。
  • boundart: 自定義但不能出現在內文的的邊界字串。

實際從 Client 端傳回 Server 端的資料如下:
Content-type: multipart/form-data, boundary=AaB03x

        --AaB03x
        content-disposition: form-data; name="field1"

        Joe Blow
        --AaB03x
        content-disposition: form-data; name="pics"; filename="file1.txt"
        Content-Type: text/plain

         ... contents of file1.txt ...
        --AaB03x--

如果使用者選擇了多個檔案,如多選了一個 file2.gif,則資料如下:
Content-type: multipart/form-data, boundary=AaB03x
       
        --AaB03x
        content-disposition: form-data; name="field1"

        Joe Blow
        --AaB03x
        content-disposition: form-data; name="pics"
        Content-type: multipart/mixed, boundary=BbC04y

        --BbC04y
        Content-disposition: attachment; filename="file1.txt"

        Content-Type: text/plain

        ... contents of file1.txt ...
        --BbC04y
        Content-disposition: attachment; filename="file2.gif"
        Content-type: image/gif
        Content-Transfer-Encoding: binary

          ...contents of file2.gif...
        --BbC04y--
        --AaB03x--

 Ref:
  1. http://www.faqs.org/rfcs/rfc1867.html
  2. http://blog.zhaojie.me/2011/03/html-form-file-uploading-programming.html 

2014年7月16日 星期三

[Python] 跟檔案有關的常用函式

os.path.join('c' 'folder') # 'c\\folder'
os.path.join('c:' 'folder') # 'c:folder'

# Get file name.
os.path.basename('C:\\Windows\\123.txt') # '123.txt'

# Get file path and file extension.
filePath, fileExtension = os.path.splitext('C:\\Windows\\123.txt') # 'C:\\Windows\\123', '.txt'

# Get directory path.
os.path.dirname('C:\\Windows\\123.txt') # 'C:\\Windows'

# Get modify time from epoch time.
os.path.getmtime('C:') # 1409646173.7839031

# Traverse a directory.
for root, subdirs, files in os.walk("C:\\Pictures"):
  print root, subdirs, files 

2014年7月4日 星期五

[Python] How to get the last day of the month

想要知道某個特定月份有幾天,可以直接呼叫 calendar.monthrange(2014, 2),

會回傳第一天是禮拜幾和該月有幾天。

範例:
import calendar
calendar.monthrange(2014, 2)
# (5, 28) # 禮拜六,28天
calendar.monthrange(2014, 3)
# (5, 31) # 禮拜六,31天
calendar.monthrange(2014, 4)
# (1, 30) # 禮拜二,30天

2014年5月13日 星期二

Can's see the newly created picture in Android's default gallery.

當我們寫了一個會儲存圖片在裝置上的 APP 時,卻在開啟 Android gallery 或其他專門
瀏覽圖片的 APP 時看不到圖片,是因為系統還沒將其掃進 MediaStore,想必如果系統
不斷的掃描檔案和操作資料庫是相當耗資源與沒有效率的。所以,Android 會在每次
開機時做一次掃描,如果 APP 想要系統對某個檔案做即時的掃描,可以加上下面的

程式碼:
MediaScannerConnection.scanFile(activity, new String[]{path}, null, 
    new MediaScannerConnection.OnScanCompletedListener() {
        @Override
        public void onScanCompleted(final String path, final Uri uri) {
           ...
        }
    }
); 

Ref: http://developer.android.com/reference/android/media/MediaScannerConnection.html

2014年5月10日 星期六

Launch Mode for Activity

Activity 的 launch mode 可以透過 android:launchMode 來設定,總共有四種 launch mode:
  1. standard
    這是 default 的 launch mode,Activity 每次都會建立一個新的實體。
    EX1: A -> B(standard),在 B 啟動 B,A -> B -> B。
    EX2: A(standard) -> B,返回上層,Activity A 會被重新建立。
  2. singleTop
    如果當下的 Activity 在 stack 的最上面,則不會建立新的實體,反之則會。
    EX1: A(singleTop) -> B -> C,在 C 啟動 A,A -> B -> C -> A。
    EX2: A(singleTop) -> B,返回上層,Activity A 不會被重新建立。
  3. singleTask
    不會建立新的實體,而且總是在 stack 中的最前頭(下層)。
    (Google 說總是在 stack 中的最前頭(下層) 也不全然正確)
    EX1: A -> B(singleTask) -> C -> D ,在 D 啟動 B,A -> B,C 和 D 會被移除。
  4. singleInstance
    不會建立新的實體,而且是 stack 中唯一的 Activity。
    EX1: A -> B -> C ,在 C 啟動 D(singleInstance),[A -> B -> C] -> [D]。

2014年5月1日 星期四

Android 4.4 behavior changes for read/write external storage

在 Android 4.4 之後,應用程式不再可以任意的寫入 SD 卡:
我寫了一個間單的應用程式 (com.example.test) 跑在 HP 平板(Android 4.4) 上做測試。
呼叫新的 API getExternalFilesDirs(null) 去要在 SD 卡上的私有儲存資料夾,
得到了路徑: /storage/sdcard1/Android/data/com.example.test/files
在這個資料夾下做了一些操作,發現有以下的行為:
  1. 我的 test app 可以對該資料夾寫入跟讀取。 
  2. 該資料夾下的檔案可以被電腦端或其它應用程式如 “ES File Explorer” 瀏覽到。
  3. “ES File Explorer” 不能移除該資料夾下的檔案。 (無法被其它應用程式修改)
  4. 電腦端可以移除該資料夾下的檔案。 (可以被電腦端修改)
  5. 當移除我的應用程式後,該資料夾也會被移除。
Read More: https://developer.android.com/about/versions/android-4.4.html#Behaviors

2014年4月29日 星期二

How to get place and wheather information by latitude and longitude

How to get place information?


我們可以用 Facebook API 和 Foursquare API 來取得附近地點的資訊。

這裡主要介紹怎麼使用 Foursquare API,Foursquare 是一間提供社群服務的網站公司,

其所提供的 API目前是屬於免費的。

部分的版權說明:

Access to the API is currently provided for free, but Foursquare reserves the right to charge for access to the API in the future, at its sole discretion. If we do charge a fee for using the API or any feature thereof, you do not have any obligation to continue to use the API or the applicable feature.”

詳細的版權說明可參考: https://foursquare.com/legal/api/platformpolicy

使用步驟如下:
  1. 先到 Foursquare API 註冊一個帳號。
  2. 登入後,點選 My Apps -> CREATE A NEW APP,建立並填寫 app 的相關資訊。
  3. 建立完成後,會得到一組 Client IDClient Secret
  4. 接著我們只要送出一個 HTTPS request:
    https://api.foursquare.com/v2/venues/search?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&v=20140430&ll=24.983163,121.536084
  5. 傳回的 response 就是附近地點啦!
    以上面的 request 為例,第一個回傳的地點就是 “XXX 燒臘小館”,
    回傳的資訊還包含了該地點的 phone, address, latitude, longitude, distance(36m), category name(Asian Restaurant) 等。
Note: Foursquare API 在中國可使用。

How to get weather information?


我們可以用 Weather Underground 所提供的 Weather API 來取得天氣資訊。

Weather Underground 是一間提供全球氣象資訊的網站公司,

其所提供的 API 根據流量來決定費用。

部分的版權說明:

“(a.)KEY; MONITORING. There is a daily limit and minute rate limit to the number of requests that can be made to the API for free. You may exceed this threshold only if you are or become a fee paying subscriber. WUL will monitor your daily usage of the API to determine if you have exceeded the free-use threshold by using an application programming interface key (the “Key”). Refer to the “Key Settings” page for product pricing, package features, and rate limit levels.”

詳細的版權說明可參考: http://www.wunderground.com/weather/api/d/terms.html

使用步驟如下:
  1. 先到 Weather API 註冊一個帳號。
  2. 登入後,點選 Key Settings,先選擇服務方案,再填寫 app 的相關資訊。
  3. 建立完成後,會得到一組 Key ID
  4. 接著我們只要送出一個 HTTP request:
    http://api.wunderground.com/api/69f520a20f42ecd9/conditions/settings/lang:TW/q/24.983163,121.536084.json
    (69f520a20f42ecd9 為官網提供的測試 ID 可直接使用)
  5. 傳回的 response 就是詳細的天氣資訊啦!
    以上面的 request 為例,會回傳微雨(weather)、21.4(temp_c)、東北偏東(wind_dir)、
    85%(relative_humidity) 等資訊。


2014年4月24日 星期四

Capturing HTTP traffic with Fiddler

在使用 RESTful API 諸如 Facebook API、Google API 或 Foursquare API
等等開發程式時,有時候會想要攔截 HTTP request 和 response 的值來
除錯,而這時候就可以使用 Fidder 來查看。
需要設定的步驟如下:
  1. 開起手機端的 Wifi 與 PC 端連上同樣的網域。
  2. 將手機端 Wifi 的 "Proxy 主機名稱" 設成 PC 端的 IP;port 設 8888。
  3. 如果要攔截 HTTPS request,需要在手機上安裝憑證。安裝的方法,
    只要開啟手機上任意的瀏覽器,在網址列輸入 PC 端的 IP 位置,如圖1
    所示,點選 FiddlerRoot certificate 下載憑證後,即可攔截 HTTPS request。
         
圖1. 手機上的 Chrome

2014年4月16日 星期三

[VS] 相對路徑

在使用任何函式用到相對路徑時,會有兩種情況:
  1. 直接跑 build 好的執行檔,這個路徑是相對於該執行檔的。
  2. 透過 VS 去執行時,這個路徑是相對於 $(ProjectDir) 的。想要相對於該執行檔,
    可以到專案的 Properties -> Configuration Properties -> Debugging -> Working Directory 設定執行檔的路徑。

[VS2010] MSVCRT.lib(crtexe.obj) : error LNK2001: unresolved external symbol _main

MSVCRT.lib(crtexe.obj) : error LNK2001: unresolved external symbol _main

如果 VC 遇到這種錯誤,大概你程式裡寫的 Win32 Application,

但建立專案的時候選成 Win32 Console Application。

此時,只要將專案的 Properties -> Configuration Properties -> Linker -> System -> SubSystem

改為 Windows (/SUBSYSTEM:WINDOWS) 即可。

2014年4月15日 星期二

[VS] VC++ Directories setting path

[VS2005]

Tools->Options->VC++ Directories

Path: %LocalAppData%\Microsoft\VisualStudio\8.0\VCComponents.dat

[VS2010]

Tools->Options->VC++ Directories (Deprecated)

如果第一次安裝有勾選載入舊版的設定,該設定會寫在 Path1

Path1: %LocalAppData%\Microsoft\MSBuild\v4.0\Microsoft.Cpp.Win32.user.props

Path2: C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets\v100\Microsoft.Cpp.Win32.v100.props

2014年3月27日 星期四

Running C/C++ on Android with NDK

需要準備的環境

  1. Eclipse + Android SDK: 基本的 Android 開發環境
  2. Android NDK: 讓 Android 能透過 JNI 去執行 C/C++ 語言的必要套件
  3. Eclipse NDK: Eclipse 的 plugin 套件,方便管理與建立 NDK 的專案
    Work with: https://dl-ssl.google.com/android/eclipse/
    安裝好之後要設定 Android NDK 的路徑:
    Window -> Preferences -> Android -> NDK -> NDK Location:
  4. Eclipse CDT: Eclipse 的 plugin 套件,可以在 Eclipse 上管理與開發 C/C++ 專案
    Work with: http://download.eclipse.org/tools/cdt/releases/juno (For Juno)
    Work with: http://download.eclipse.org/tools/cdt/releases/kepler (For Kepler)
  5. Cygwin: 用來編譯 C/C++
    Ref: http://blog.csdn.net/javatiger427/article/details/6115693
註1: NDK(Native Development Kit)
註2: CDT(C/C++ Development Tooling)

新建一個專案


步驟可參考下列網址:
http://www.pupuliao.info/2013/05/%E5%9C%A8eclipse%E9%80%8F%E9%81%8Ejni-%E8%B7%91cc-for-android-hello_world%E7%AF%87/

文中設定 Builder 的部分可略過,只是為了存檔的同時也能重新自動建置。

而且遇到有空白字元的路徑更為麻煩,可將文中 Arguments 的部分換成如下:

--login -c "cd /cygdrive/d/sample &&  rm -r obj && /cygdrive/c/Progra~1/Android/android-ndk-r9d/ndk-build"

另外,我們也可以透過按下小鎚子的圖示來手動建置。

除錯


除錯時要將 Project -> Properties -> C/C++ Build -> Builder Settings -> Build Command:

加上 ndk-build NDK_DEBUG=1,建置時才會產生除錯所需要的檔案。

在這之後可能會遇到兩個問題:
  1. 無法在 .c 或 .cpp 檔上設置中斷點?
    Run -> Breakpoint Types  -> C/C++ Breakpoints
  2. 設完中斷點後,卻沒有停在中斷點上?
    No symbol table is loaded. Use the "file" command.
    由於 GDB debugger 需要一點時間運算,而 GDB 可能還沒載入 Library 的 Symbol,
    如果中斷點設得太早可能會被忽略,
    解決的辦法請參考:
    http://www.codeproject.com/Articles/493043/Why-your-Android-NDK-breakpoints-might-fail-and-ho

2014年3月26日 星期三

Develop C/C++ with Eclipse CDT

Setup

連結中的網址講的還蠻詳細的:
http://www3.ntu.edu.sg/home/ehchua/programming/howto/eclipsecpp_howto.html

唯一要補充的是,如果沒有加上 C:\cygwin\bin 或 C:\cygwin64\bin 到系統的環境變數中,

會引發下列錯誤:
  1. 在 include 的地方會有 "Unresolved Inclusion Error"。
  2. 用 Eclipse 的 Run 去執行時,會跑不起來。
  3. 直接跑  exe 執行檔,會跳出找不到 cygwin1.dll 的錯誤視窗。
如果想避免新加的環境變數影響到其他程式,替代的方法是

在 Window -> Preferences -> C/C++ -> Make -> New Make Projects 時指定 PATH 的路徑: 

Debug

想在 CDT 的環境下 debug,需要對  Window -> Preferences -> C/C++ ->
Debug -> Common Source Lookup 做一些設定:


2014年3月12日 星期三

[隨身硬碟] TOSHIBA Canvio Slim II 500G USB 3.0

在 Y 購物上買的 ,價格還算平易近人 NT.1899,

跑完 CrystalDiskMark 的結果令人相當滿意!

TOSHIBA Canvio Slim II USB3.0

USB2.0 的評測結果

USB3.0 的評測結果

[隨身硬碟] The Performance of Transcend StoreJet USB2.0 320G (TS320GSJ25M)

這顆硬碟應該是五六年前買的吧,現在還跑得好好的,

因為買了新的 USB 3.0 硬碟,順便測看看這顆的速度。

Transcend  TS320GSJ25M
評測結果

2014年3月5日 星期三

Toast's layout path

系統的 Toast Layout 定義檔存放在:

{SDKBASEDIR}/platforms/{API VERSION}/data/res/layout/transient_notification.xml

以 android-17 為例:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="?android:attr/toastFrameBackground"> 

    <TextView
        android:id="@android:id/message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_gravity="center_horizontal"
        android:textAppearance="@style/TextAppearance.Small"
        android:textColor="@color/bright_foreground_dark"
        android:shadowColor="#BB000000"
        android:shadowRadius="2.75"
        />

</LinearLayout>

2014年1月24日 星期五

Failed to install ADB interface driver on Win8 and Win8.1

有些手機或平板裝置與電腦用 USB 連接時,並不會自動安裝 ADB interface driver,

必須得手動安裝。(目前遇過會自動安裝的有: Samsung Galaxy R, Sony Xperia ZL)

在 Win7 上手動安裝沒什麼問題,安裝在 Win8 和 Win8.1 卻出現下面的錯誤視窗:

該檔案可能已損毀或被竄改
是因為 Win8 和 Win8.1 預設會檢查驅動程式是否有驗證過,所以只要把這個檢查

先關掉就行了!

關掉的方法如下:
  1. 將滑鼠移到螢幕的右下角,選擇 "設定" -> "變更電腦設定"
  2. 選擇 "更新與復原" -> "復原"
  3. 在復原頁面選擇進階啟動的 "立即重新啟動",重新開機後就會出現如下的畫面

    選擇選項
  4. 選擇 "疑難排解" -> 進階選項" -> "啟動設定" -> "重新啟動",看到啟動設定的畫面

    啟動設定
  5. 按下 F7,"停用驅動程式強制簽章" (Disable driver signature enforcement)
  6. 現在 ADB interface driver 可以正常安裝了!

[Android][Eclipse] 環境架設 (2014 更新版)

這是給想要獨立安裝 SDK 和 Eclipse 的使用者教學:


  1. 安裝 Android SDK (選擇 GET THE SDK FOR AN EXISTING IDE)。
  2. 再下載 Eclipse (目前的版號是 4.3 Kepler or 4.4 Luna) ,開啟時要 "以系統管理員身分執行" 因為 ADT 套件會想要在 SDK 的路徑下建立目錄和檔案,所以需要權限。
  3. 到 Help -> Install New Software... ,就會彈出下載視窗,點選 Add ,在欄位裡輸入,
    Name:Android (可自訂名稱)Locationhttps://dl-ssl.google.com/android/eclipse/ (伺服器位置)即可下載 Android Developer Tools 套件
  4. Restart Eclipse.
  5. 開啟後,Android SDK Manager 會自動跳出協助下載 Android SDK。
    另外,也可以到 Android Developers 自行下載。
  6. 即可開始建立第一支 Android Project 啦!

Note: Android SDK Tools 常會有更新,目前是 Rev.22.3 (2014.1.24)