2017年12月11日 星期一

Fritzing -- 好用的 PCB 電路板設計工具

markdown Fritzing 是一個很好用電路板設計工具,大部分都是用拖拉完成電路設計,還可以用來作電路設計文件,軟體內也內建一些知名的電路板可以直接拿出來用,例如 Arduino 或 GogoBoard 等等。 它的麵包板檢視功能可以很方便的作出電路圖,而且如果裡面內建的元件不夠用,還可以自己加入客製化的圖片,元件庫的 core parts 的 breadboard image 可以很方便的加入圖片到 breadboard view 中 在[網路](http://coopermaa2nd.blogspot.tw/2011/01/fritzing-pcb.html)上也有很多關於 Fritzing 的介紹。

2017年12月5日 星期二

為什麼 USB 接頭的 D+, D- pin 比 Power, GND pin 短

這邊有給出一些解釋...為了怕 signal pin 在 power 還沒到時就開始傳輸,可能會造成原件損壞

AC 電壓 RMS 值與 Crest Factor

網路上查到的這篇解釋的不錯

windows git shell 支援中文

安裝完 git for windows 之後用 git shell 查看 git log 時中文會出現亂碼,只要照這邊所設置的 command 讓 git 支援 utf8 編碼,git log 就可以正確顯示中文了

$ git config --global core.quotepath false    # 显示 status 编码
$ git config --global gui.encoding utf-8   # 图形界面编码
$ git config --global i18n.commit.encoding utf-8 # 提交信息编码
$ git config --global i18n.logoutputencoding utf-8 # 输出 log 编码
$ export LESSCHARSET=utf-8
# 最后一条命令是因为 git log 默认使用 less 分页,所以需要 bash 对 less 命令进行 utf-8 编码

2017年11月30日 星期四

找出 non present 的 device

之前介紹過 Setup API 與其使用方式,可以找出系統上的 device 並對其操作,但是它會找出所有曾經被安裝過的 device,包括目前正連在電腦上的與未連接在電腦上的 device,若是想找出目前沒有被連接在電腦上,也就是 non present 的 device,並沒有甚麼簡單的方法可以達成,例如本來想看看 SetupDiGetDeviceRegistryProperty API 能不能查出 device 是不是 non-present,但可惜沒有辦法

Setup API 沒辦法,但是其他 API 可以,後來找到 CM_Get_DevNode_Status 這個 API,可以查詢 devnode 的 status,而 non present 的 device 因為沒有 devnode,所以對 non present 的 device 這個 API 會回 CR_NO_SUCH_DEVNODE,這樣就可以區分出用 Setup API 取得的 device 是不是 non present

2017年11月17日 星期五

Android ViewPager 元件產生滑動效果

ViewPager 是一個可以讓螢幕產生滑動效果的原件,通常是搭配 fragment,可以讓各個 fragment 在螢幕中左右滑動

效果如下

螢幕轉向時 FragmentPagerAdapter 如何處理 fragment

最近在 Android 開發中用到 Fragment、ViewPager 跟 FragmentPagerAdapter 的組合,並且需要在 activity 中取得當前顯示的 fragment,原本的做法是在 getItem method 中將 fragment 用 position 當成 index 儲存起來,之後在繼承 FragmentPagerAdapter 的 class 中新增一個 getFragment(int position) method 取得 fragment

原本運作是沒甚麼問題,但是當螢幕轉向之後取得的 fragment 都變成 null,後來才發現 fragment 會被 FragmentManager 儲存在內部,當螢幕轉向時,並不會重新 create 一個 fragment 實體,而是會重用之前 create 過的 fragment,可以看 FragmentPagerAdapter 的實作




可以看到只有在找不到 fragment 時才會去呼叫 getItem 來 create 出一個 fragment 實體,這樣也解釋了為甚麼 google 範例中在複寫 getItem 時都直接 create 一個 fragment 出來了

不過這樣 getItem 的命名感覺很有問題阿,應該叫 createItem 才對,才不會造成混淆

也因為如此,螢幕轉向時,並沒有呼叫到 getItem,所以我取得的 fragment 都是 null,解決的方法很簡單,不需要自己儲存 fragment,也不需要額外實作 getFragment method,直接呼叫 FragmentPagerAdapter 的 instantiateItem 就可以取得當前顯示的 fragment
Fragment fragment = (Fragment)mPagerAdapter.instantiateItem(mViewPager, position);

2017年11月2日 星期四

windows 7 網芳 127.0.0.1 錯誤 0x800704cf

最近遇到一個問題是 PC 要 access 自己的網芳卻出現 error 0x800704cf,網路上找了很久卻沒甚麼有用的資料,後來發現有人說把一些奇怪的網卡驅動刪除後就恢復了,試了一下,magic,真的把網卡驅動刪除後就恢復了

恩...windows 真是博大精深

2017年10月31日 星期二

記憶體使用量 private bytes, working set 和 virtual bytes 的意義

使用 procexp 查看 process 時會顯示 private bytes 跟 working set,在這邊記錄一下這些跟記憶體使用量有關的 term

Private Bytes

private bytes 是 process 要求的記憶體,不是 process 實際使用到的記憶體,private 的意思是它不包含 shared DLLs 之類的 memory-mapped files,private bytes 也不一定等於 physical memory 用量,它可以包含被 paged 到 disk 的頁面

Working Set

working set 表示被 process 使用到的 physical 記憶體使用量,但是跟 private bytes 不同,working set 包含 memory-mapped file 這個值跟工作管理員理看到的 memory usage 是一樣的

有一點可能會讓人困惑,standby page 雖然也是 physical 但是並沒有包含在 working set 中,所以會發現程式最小化之後 memory usage 突然下降,是因為那些消失的 memory 頁面變成 standby page 了

Virtual Bytes

virtual bytes 是 process 使用的所有 virtual address space 用量,就等於是 working set 加上 standby page 加上被 paged out 到 disk 的 memory pages

2017年10月30日 星期一

Android ListView onCheckedChange 非預期的呼叫

最近在 ListView item 中放入 checkbox,然後用 notifyDataSetChanged 改變 ListView,但是發現 checkbox 的 onCheckedChange 會非預期的被呼叫到

例如在第三個 item 將 checkbox 勾選,然後將儲存在 Adapter 中的 data set 更新,更新後的第三個 item checkbox 預設是沒勾選的狀態,則在呼叫 notifyDataSetChanged 時就會 call 到 第三個 item checkbox 的 onCheckedChange

調查後發現,我使用 setViewBinder 來初始化 checkbox 的勾選狀態,但是在 setChecked 之前先用 setOnCheckedChangeListener 設定了 OnCheckedChangeListener 
@Override
public boolean setViewValue(View view, Object o, String s) {
    // Not correct!!
    AppCompatCheckBox cb = (AppCompatCheckBox)view;
    cb.setOnCheckedChangeListener(listener);
    cb.setChecked((boolean)o);

    // Correct
    cb.setOnCheckedChangeListener(null);
    AppCompatCheckBox cb = (AppCompatCheckBox)view;
    cb.setChecked((boolean)o);
    cb.setOnCheckedChangeListener(listener);
}

notifyDataSetChanged API 的行為應該會保存 item 之前的資料,只對需要的部分作改變,所以第三個 item checkbox 狀態會從 check 到 uncheck,如果有註冊了 listener,則理應通知 listener

那解法就是在初始化 checkbox 時,先 remove 掉 listener 在設定 checkbox,然後才註冊 listener,這樣就避免了不必要的 onCheckedChange 呼叫

此外,還有一個額外需要注意的點是,之前提過,用 notifyDataSetChanged 來更新 ListView,ListView item 之前的狀態都會被保存,所以原本被勾選的 item 更新後沒有被勾選的話會有 checkbox 被取消的動畫效果

如果不想要這個效果的話,則不應該用 notifyDataSetChanged,可以改用 setAdapter 重新設定 adapter 給 ListView,這樣 ListView 就會將整個內容銷毀再更新,就不會有 checkbox 效果,當然這樣會有效能流失,可以感覺到 GUI 的更新速度稍微慢了一點

2017年10月23日 星期一

Android 7.0 中文開發語言坑

Android 系統支援多國語言,若開發 app 時想要支援不同語系的話,會將 default language string resource 放在 values 目錄中,其他想支援的語系放在 values-XX 目錄中,例如我的 app 想支援英文跟繁體中文,可以將英文放在 values 目錄,繁體中文放在 values-zh 目錄

如此,使用者不管是選擇大陸地區或是香港地區,app 都會顯示繁體中文,這是因為 android 在搜尋 string resource 時,只要是 zh-* 的 locale,找不到 resource 時都會 fallback 到 zh 去,所以 zh-HK 或 zh-CN locale 最後會使用到 values-zh 目錄中的 resource,多年來 app 照著這樣的 locale resource search rule 開發,一直運作的很好,直到 Android N 的出現

在 Android N 上面,若是 app 只在 values-zh 中放入中文,在 values 放入英文,手機語系選擇台灣地區會發現 app 顯示的是英文

這是因為從 Android N 開始,locale system 與 resource search rule 都改變了,但其實改變了也就算了,最坑的地方是這個改變不會向前相容,就算你 app 的 targetSdkVersion 設定是 N 之前的系統也沒用,大概絕大多數中文 app 恐怕都要更新才能在 N 上面顯示中文了,真不知 google 是忘了做向下相容還是真的想要讓許多的 app 做更新來適應這個變化

回來看這次 Android N 的改變,照 google 在 issue tracker 的回應,他覺得所有 zh-* 的 locale 最後都 fallback 到 values-zh 是不對的行為,Android 裡面有演算法會自動找出他覺得最適合的 resource

根據 CLDR,Android N 上,zh 會被自動轉為 zh-Hans,zh-CN 會被轉為 zh-Hans-CN,zh-TW 會被轉為 zh-Hant-TW
 
所以我猜想原本 values-zh 應該會被轉為 values-zh-Hans,也就是 values-zh 預設已經變成簡體中文,而台灣地區的 locale 為 zh-Hant-TW,Android N 找不到 zh-Hant-TW 的 resource就會往上找 zh-Hant,還是找不到就找 default resource 了

這樣看來在 Android N 之後,繁體中文跟簡體中文 resource 的 search tree 為不同的兩個分支,彼此間不會有交集

Reference
https://litotom.com/2017/05/02/android7-locale-language/
http://blog.30sparks.com/android-7-0-locales-chinese-problem/
https://issuetracker.google.com/issues/37102249
https://issuetracker.google.com/issues/37093759

2017年10月16日 星期一

.NET library SharpSSH socket read fail

SharpSSH 實際上 depends on Org.Mentalis.Security.dll 來作 ssh 的加解密部分,假如執行目錄下沒有 Org.Mentalis.Security.dll 的話,會發現出現 exception,不過這個問題有點難發現到底是甚麼問題,因為它丟出來的是 IOException,而不是 dll not found 之類的 exception

2017年10月4日 星期三

Android studio 找不到 support library version 26

原本在 Android studio 中要使用 support library 是很簡單的,只要在 gradle 的 dependencies block 中加入要使用的 library 就好,這是因為 Android studio 會自動去 jcenter 這個 maven 倉庫 中去找 support library 下來加入到專案,現在 Android stdio 新建專案後,jcenter 都已經會自動的加入到 gradle 的 repositories block,在這邊可看到更詳細的說明

但是從 support library 26 後,會發現 Android studio 回報找不到 support library 的錯誤,因為 google 已經將最新的 support library 搬到自己的 maven 倉庫,所以要在 dependencies block 中宣告 google 的 maven 倉庫才能下載到 support library 26,在這邊可看到範例,詳細說明可看官網

Google issue tracker for Android

Google 將自己內部使用的 issue tacker system open 出來讓外部使用者也可以使用,例如讓 android 開發者可以 submit bug 到 google issue tracker,感覺是個好東西,沒事可以上去看看大家提交了那些 android 的 bug,尤其是 android 最新的版本,可能你遇到的 bug 還沒甚麼人知道,在 stackoverflow 之類的地方找不到解答,就可以上去 google issue tracker 上找找看有沒有人提交這個 bug

reference:
https://developers.google.com/issue-tracker/
https://android-developers.googleblog.com/2017/04/a-new-issue-tracker-for-our-aosp.html?hl=zh_TW

Android 權限動態請求

Android 6.0 (API level 23) 開始,app 權限區分為兩類,normal 跟 dangerous,normal 的權限跟以前一樣在 app 安裝時給予,但 dangerous 的權限在安裝時不會給,app 必須要在執行時動態的請求 user 給予

例如存取 external storage 的權限,只在 manifest 宣告 android.permission.WRITE_EXTERNAL_STORAGE 權限是不夠的,它是屬於 dangerous 的權限,必須要執行時跟使用者要求,並且使用者同意後才可以

開發的時候需將所有需要的權限透過 API 傳給系統,系統會跳出視窗讓使用者選擇是否同意,但視窗上只會顯示該權限的 group,所以 user 同意後是會將整個 group 的權限給予,之後 app 再要求同一 group 的其他權限,系統將不會跳出視窗並且立刻回覆 app 已擁有權限

詳細可看官網說明

2017年9月30日 星期六

Android get app icon crash if recycle the bitmap

在實做取得 app icon 的時候發現記憶體使用率會飆高而且常常降不下來, 想說可能是 birmap 吃掉記憶體,所以在使用完 bitmap 後就用 recycle 來讓 GC 可以做記憶體回收,但是發現呼叫 recycle 之後再次要取得 app icon 時常常會出現 exception 說使用到已經 recycle 的 bitmap,就在想會不會是系統已經做了 app icon 的 cache,所以每次取到的 app icon 有可能是跟之前一樣的 object,這篇的說法也印證了我的猜想,系統的確會內部自己做 cache

既然不能 recycle bitmap,但記憶體又這麼高,該怎麼辦?這時發現 Android 有提供一個 LruCache 物件來做 cache,很適合 bitmap 使用,試著用用看,結果...在這樣系統跟我都做了 cache 的情況下,記憶體使用率真的變低了

為什麼兩邊都做 cache 反而記憶體會下降,我認為 Android 系統內部的 cache 機制大概有問題 ,既然系統已經內部有做 app icon 的 cache 了,應用程式端就不需要再自己做 cache 才對,cache 的使用效能與記憶體管理系統自己要注意,而不是讓應用程式來煩惱,那還不如你系統就不要做 cache,這樣我記憶體使用率可以再降一點

為了這個問題還去查了一下 PackageManager 的原始碼,才發現 PackageManager 的實作提供者有兩個 ApplicationPackageManager 和 PackageManagerService 這些物件又互相 call 來 call 去對方的 method,看了有點頭昏

恩...繼上次 activity context create PackageManager memory leak 後又一個 Android 的坑 

2017年9月27日 星期三

java blocking IO read 不支援 interrupt

一直以為 java 所有的 blocking operation 是可以用 thread.interrupt() method 中斷的,但是後來才發現  java 原本的 blocking IO library 是不支援 interrupt 的,例如去 read 一個 socket,然後用 thread.interrupt() 去中斷呼叫 read 的 thread,會發現 read 並沒有被中斷

新的 File library 像是 java.nio 才有支援 interrupt,而原本的 IO library 就要考慮其它的方式來中斷一個 blocking read,例如把 socket close,或是去 polling 是否 data available,若 data available 再呼叫 blocking read method

2017年9月17日 星期日

查詢 kernel module CPU 使用率的好幫手 -- Kernrate

最近在調查 CPU 使用率飆高問題的時候,在這邊發現一個好用的工具,kernrate,可以用來查詢 kernel module 的 CPU 使用率

它的用法非常簡單,只有一個執行檔,直接執行後就會開始記錄 CPU 使用率,跑一段時間後用 ctrl-c 就會停止執行並印出它所記錄的 CPU 使用率

不過官網下載的安裝包裝完後只有 x86 跟 IA64 兩種版本的執行檔,沒有 x64 版本,後來網路上發現 windows DDK 中有 x64 版本,所以若是想在 x64 上用的話,就先下載 windows DDK 吧

2017年9月11日 星期一

Activity context leak caused by getPackageManager

最近用 leakcanary 檢查有沒有 memory leak 的時候發現了 context leak,而 leak 的 memory 有 2MB 這麼多

context leak 是 android 最常發生的 memory leak 之一,吃掉的 memory 隨著你的 activity 大小而變,因為你的 activity context 無法釋放,隨著你的 activity 中持有的所有資源都會無法釋放

leakcanary 的強大功能就是會顯示出造成 memory leak 的來龍去脈,照著 leakcanary 的提示,是 UserManager 其中的一個 static variable reference 到我的 activity context,不過我沒有在 activity 中使用到 UserManager,怎麼會讓 context 被 UserManager 持有的

一番查證後,在我的 activity 中有去使用 PackageManager,而 PackageManager 內部使用到了 UserManager,而在 UserManager 第一次被使用到的時候會將自身存在一個 static variable 中,從而讓 context 被這個 static variable hold 住



android framework 用這樣的實作,難怪會有 memory leak,還讓你 leak 的不知不覺,只要用 activity context 呼叫 getPackageManager 就踩到坑裡

這個 memory leak 實際上是 android 5.0 的一個 bug,在 android 7.0 已經修正掉了,app 開發者要避開這個 memory leak 的話,需要用 application context 來呼叫 getPackageManage,而不是用 activity context

開發 android 時真的要小心,注意自己的 code 還不夠,還要注意不要掉到 android 挖好的洞裡

2017年9月7日 星期四

秦九韶演算法

秦九韶演算法是在算一元多項式時非常有用的演算法,每一次迭代運算時只需要一次加法跟乘法,不需要次方運算

以時間複雜度來講,求最高 n 次方的多項式時,用秦九韶演算法需要花費 2n 的時間複雜度,但是以次方運算的時間複雜度為 n 平方,可見節省了相當多的運算次數

演算法筆記中也有介紹

2017年9月2日 星期六

找出給定範圍內的質數 -- Sieve of Eratosthenes

Sieve of Eratosthenes是一種找出給定範圍內的演算法,從該範圍內最小質數開始,逐步刪除該質數的乘積,圖形化表達如下


C 程式如下
bool prime[20000000];

void eratosthenes()
{
    for (int i=0; i < 20000000; i++)
        prime[i] = true;

    prime[0] = false;
    prime[1] = false;

    for (int i=2; i < 20000000; i++)
        if (prime[i])
            for (int j=i*i; j < 20000000; j+=i)
                prime[j] = false;
}
用來實做質數表非常有用,在這邊也有提到更多細節與加速該演算法的方法