Showing posts with label android. Show all posts
Showing posts with label android. Show all posts
June 11, 2013
SimpleAdapter and ViewBinder
ListView 是 Android 一個極為常用的元件,經常看見為了「用自己定義的 xml 來產生 ListView row」而自己實作了一個 BaseAdapter。這樣的作法也不能說不對,我一開始也是這樣。為了烤蛋糕自己做了一個烤箱的事情,幾次之後還是覺得有點怪其實絕大多數的時候我們都不需要額外實作一個 Adapter,直接拿 SimpleAdapter 來用即可。
SimpleAdapter 需要一堆資料,還要有資料對應到 View 的表格。首先看一筆資料,每一筆資料都是一個 Map,從 JSON 的格式來看就像是
產生 Julian 的資料就會是
假設資料放在 List 裡面,
接著看 SimpleAdapter 的 contructor
白話文解釋就是
假設我們的 layout row.xml 如下,它有一個 TextView 與 ImageView
把名字對應到 TextView,大頭照對應到 ImageView 就是
如此一來,SimpleAdapter 就會透過 Map.get(from[0]) 取出名字,然後再 findViewById(to[0]) 找到 TextView,接著就 TextView.setText(); 設定名字
也因此只要設定好對應關係就可以產生我們要的 view 了,其他生成 view 的事情就交給 SimpleAdapter 去做,我們不用再插手/不用自己再實作一份。
至此我們會有疑問:我們僅僅只是對 string key 跟 view id 建立關聯,但是 SimpleAdapter 怎麼知道要 setText?
更進一步的問題就會是:我們想要對 View 做更多客製化,好比「根據每個 User 的 Prefer Color 設定該 row 的背景顏色」,該怎麼做?
針對第二個問題,SimpleAdapter 有個 inner class 叫 View Binder,我們可以對它實作
接著把 from, to 多做一組 mapping 即可
這樣子我們就多教了 SimpleAdapter 一件事:看到 Integer 就把它當成背景顏色來設定
其實這個例子寫得滿蠢的,希望能夠這樣有保留到最重要的精神
SimpleAdapter 需要一堆資料,還要有資料對應到 View 的表格。首先看一筆資料,每一筆資料都是一個 Map,從 JSON 的格式來看就像是
var julian = {
"name": "Julian Chu",
"avatar": R.drawable.julian,
"location": "Taiwan",
"prefer": "blue"
}
產生 Julian 的資料就會是
Map<String, Object> julian = new HashMap<String, Object>();
julian.put("name", "Julian Chu");
julian.put("avatar", R.drawable.julian);
julian.put("location", "Taiwan");
julian.put("prefer", new Integer(Color.BLUE));
假設資料放在 List 裡面,
private void appendData(List<Map<String, Object>> records, User user) {
Map<String, Object> record = new HashMap<String, Object>();
record.put("name", user.getName());
record.put("avatar", user.getAvatar());
record.put("location", user.getLocation());
record.put("prefer", user.getPreferColor());
records.add(record);
}
接著看 SimpleAdapter 的 contructor
SimpleAdapter(Context context,
List<? extends Map<String,?>> data,
int resource,
String[] from,
int[] to)
白話文解釋就是
- 我要建立一個 SimpleAdapter,先給我 context
- 給我一串資料,放在 List 裡面
- List 裡面的每一筆資料格式都是 Map<String, ?>,也就是 key=String, value=任意資料結構
- 給我一個 layout xml 檔(resource),產生 view 的時候會拿它來當 template
- 對於 Map 裡面的資料,我要拿哪些欄位來用(from)
- 取出的欄位,要對應到 xml 檔裡面的哪些 view (to)
假設我們的 layout row.xml 如下,它有一個 TextView 與 ImageView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@id/row_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@id/row_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@id/row_avatar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
把名字對應到 TextView,大頭照對應到 ImageView 就是
String[] from = {"name", "avatar"};
int[] to = {R.id.row_name, R.id.row_avatar};
SimpleAdapter adapter = new SimpleAdapter(
context,
records,
R.layout.row,
from,
to
);
如此一來,SimpleAdapter 就會透過 Map.get(from[0]) 取出名字,然後再 findViewById(to[0]) 找到 TextView,接著就 TextView.setText(); 設定名字
也因此只要設定好對應關係就可以產生我們要的 view 了,其他生成 view 的事情就交給 SimpleAdapter 去做,我們不用再插手/不用自己再實作一份。
至此我們會有疑問:我們僅僅只是對 string key 跟 view id 建立關聯,但是 SimpleAdapter 怎麼知道要 setText?
更進一步的問題就會是:我們想要對 View 做更多客製化,好比「根據每個 User 的 Prefer Color 設定該 row 的背景顏色」,該怎麼做?
ViewBinder
第一個問題的解答是,SimpleAdapter 對 TextView, ImageView, Checkable 有作預設的處理。findViewById 之後會用 if (v instanceof TextView) 來判斷是不是 TextView,找到 TextView 就把 data 拿來 TextView.setText(data)。針對第二個問題,SimpleAdapter 有個 inner class 叫 View Binder,我們可以對它實作
class TheBinder implements SimpleAdapter.ViewBinder {
public boolean setViewValue(View view, Object data, String textRepresentation) {
if (data instanceof Integer) {
Integer color = (Integer)data;
view.setBackgroundColor(color.intValue());
}
}
}
接著把 from, to 多做一組 mapping 即可
String[] from = {"name", "avatar", "prefer"};
int[] to = {R.id.row_name, R.id.row_avatar, R.id.container};
adapter.setViewBinder(new TheBinder());
這樣子我們就多教了 SimpleAdapter 一件事:看到 Integer 就把它當成背景顏色來設定
其實這個例子寫得滿蠢的,希望能夠這樣有保留到最重要的精神
December 25, 2012
Momome
聖誕節的時候上傳了之前寫的一個小程式 Momome,請看 Google Play 的 Momome
這是 Open source 的程式,原始碼可以在 Github momome 裡面取得。
程式很單純,寫入一些簡單的筆記事項,以 ListView 的方式顯示。比較特別之處是,你寫入的東西會被加密儲存,讀取的時候再解開。解密需要你輸入之前設定的密碼,而且程式在關閉的時候會自動上鎖。
也就是說,設定一個密碼之後開始紀錄一些大小雜事,寫完直接離開程式即可。下一次開啟時會被詢問密碼,只有知道密碼的人才能夠看見你寫了什麼東西進去。
生活中大多數會用到的東西 Market 上頭都有了,之前還真不知道要寫什麼小程式來玩玩。
娛樂性的 app 好比遊戲,大家會在手機裡面裝好幾個性質類似的程式,我相信許多人的手機裡面就好幾個不同版本的 Angry Birds。但是寫遊戲的成本非常高,需要程式、美工與企劃,除了熱血度破表的阿宅,個體戶實在很難推出遊戲 App。
工具類 App 的生存模式就不同,即使類似功能的程式有好幾個選擇,使用者最後都只會想要「選出一個」,然後一直用到它跟不上時代為止。要在夾縫中生存就必須持續打出差異化,讓人們覺得「這個程式比較好」才會捨棄另外一個選擇。還有一種工具類程式要與後端的服務做結合,好比摩斯漢堡的點餐程式、iKala、Line 或 Whats app,人們是為了用後端的服務而選擇前端程式,角力的場所其實是後端,這種也不是個體戶的領域。
個人認為想要再寫新的 App 送上 Market,要嘛不斷整合各種功能愈寫愈大,要嘛在同質性高的族群裡頭找出貼心的小細節、或是把程式的主要功能做到最好,不然使用者很懶得換工具的。
若說大家手機裡面 80% 的程式相同,只有 20% 的程式會不一樣,把某個小細節抽出來特化到極點,對準 20% 的空間其實是個體戶的守備範圍。這個市場絕對不大,因此不會是商業應用的好對象,寫起來成本不高,又適合 Open Source 出來給大家一起改,自娛娛人的小程式針對這種方向來寫還不錯。
我也覺得,這種只專心做一件事情的小程式會愈來愈多。能夠飛天遁地的大玩意有幾隻就夠了,現實生活中每個人在小地方都很不一樣,也因此有些非常奇怪的需求並不容易被滿足,有隻 Just work 的程式滿足這種小需求真的是很貼心的事情。(這種程式麻煩的地方在於很難推銷出去給別人知道 XD)
恰好我很鼓勵老婆使用強度夠的密碼,最好還是每個網站都用不同組。但是太多複雜的密碼很難記憶,寫下來也不好。乾脆把「密碼的提示」紀錄在隨身會帶的手機裡頭,再用一組密碼去保護它,兼顧了方便性以及最低限度的安全。
這隻小程式是寫給老婆的,我自己也很常用。好比去朋友家裡偶爾要登入 Wifi,隨手把密碼紀錄到程式裡面就不需要每次都問,人家家裡的密碼用明碼記錄下來似乎不太好。
至於為什麼叫 Momome,因為老婆的外號是「桃」,而且這個程式用來當作 Memo,就取了這個簡單好記的名字。
到今天 12/25 跟老婆在一起滿三年了,老婆聖誕節快樂唷~
這是 Open source 的程式,原始碼可以在 Github momome 裡面取得。
程式很單純,寫入一些簡單的筆記事項,以 ListView 的方式顯示。比較特別之處是,你寫入的東西會被加密儲存,讀取的時候再解開。解密需要你輸入之前設定的密碼,而且程式在關閉的時候會自動上鎖。
也就是說,設定一個密碼之後開始紀錄一些大小雜事,寫完直接離開程式即可。下一次開啟時會被詢問密碼,只有知道密碼的人才能夠看見你寫了什麼東西進去。
![]() |
| 打開程式卻沒有輸入密碼,看不見任何內容 |
![]() |
| 輸入密碼解鎖 |
![]() |
| 解鎖後看見之前輸入的內容 |
生活中大多數會用到的東西 Market 上頭都有了,之前還真不知道要寫什麼小程式來玩玩。
娛樂性的 app 好比遊戲,大家會在手機裡面裝好幾個性質類似的程式,我相信許多人的手機裡面就好幾個不同版本的 Angry Birds。但是寫遊戲的成本非常高,需要程式、美工與企劃,除了熱血度破表的阿宅,個體戶實在很難推出遊戲 App。
工具類 App 的生存模式就不同,即使類似功能的程式有好幾個選擇,使用者最後都只會想要「選出一個」,然後一直用到它跟不上時代為止。要在夾縫中生存就必須持續打出差異化,讓人們覺得「這個程式比較好」才會捨棄另外一個選擇。還有一種工具類程式要與後端的服務做結合,好比摩斯漢堡的點餐程式、iKala、Line 或 Whats app,人們是為了用後端的服務而選擇前端程式,角力的場所其實是後端,這種也不是個體戶的領域。
個人認為想要再寫新的 App 送上 Market,要嘛不斷整合各種功能愈寫愈大,要嘛在同質性高的族群裡頭找出貼心的小細節、或是把程式的主要功能做到最好,不然使用者很懶得換工具的。
若說大家手機裡面 80% 的程式相同,只有 20% 的程式會不一樣,把某個小細節抽出來特化到極點,對準 20% 的空間其實是個體戶的守備範圍。這個市場絕對不大,因此不會是商業應用的好對象,寫起來成本不高,又適合 Open Source 出來給大家一起改,自娛娛人的小程式針對這種方向來寫還不錯。
我也覺得,這種只專心做一件事情的小程式會愈來愈多。能夠飛天遁地的大玩意有幾隻就夠了,現實生活中每個人在小地方都很不一樣,也因此有些非常奇怪的需求並不容易被滿足,有隻 Just work 的程式滿足這種小需求真的是很貼心的事情。(這種程式麻煩的地方在於很難推銷出去給別人知道 XD)
恰好我很鼓勵老婆使用強度夠的密碼,最好還是每個網站都用不同組。但是太多複雜的密碼很難記憶,寫下來也不好。乾脆把「密碼的提示」紀錄在隨身會帶的手機裡頭,再用一組密碼去保護它,兼顧了方便性以及最低限度的安全。
這隻小程式是寫給老婆的,我自己也很常用。好比去朋友家裡偶爾要登入 Wifi,隨手把密碼紀錄到程式裡面就不需要每次都問,人家家裡的密碼用明碼記錄下來似乎不太好。
至於為什麼叫 Momome,因為老婆的外號是「桃」,而且這個程式用來當作 Memo,就取了這個簡單好記的名字。
到今天 12/25 跟老婆在一起滿三年了,老婆聖誕節快樂唷~
July 3, 2012
JJ’s Studio
最近將會與合作許久的朋友 John[1] 一同以工作室的方式提供 Android 以及 Embedded Linux 的相關服務。工作室的名字就叫 JJ's studio。
從退伍後第一份工作以來,就持續過著賣命完成上級命令的生活,一直到了去年終於有機會喘口氣稍微休息,找回比較正常的社交生活,並且接觸一些自己從來沒有想過的領域。
這幾個月裡的走走停停,使得自己對於「目標」一事有更清晰的執著,更幸運的是有個認識許久的朋友擁有相同的目標。為了凝聚彼此的動能,我們兩個這幾天經過討論,打算以工作室的角色,用我們累積的技術與經驗為公司提供服務。
由於我們兩人在 openmoko 與 0xlab 的經驗之故,目前為止想要先將範圍鎖定在
- Embedded Linux
- Android app
- Android framework
若有相關的需求,歡迎寫信給 john@0xlab.org 洽談,John 會與我同步討論。
[1] JJ's Studio - http://asleepfromday.wordpress.com/jjs-studio/
從退伍後第一份工作以來,就持續過著賣命完成上級命令的生活,一直到了去年終於有機會喘口氣稍微休息,找回比較正常的社交生活,並且接觸一些自己從來沒有想過的領域。
這幾個月裡的走走停停,使得自己對於「目標」一事有更清晰的執著,更幸運的是有個認識許久的朋友擁有相同的目標。為了凝聚彼此的動能,我們兩個這幾天經過討論,打算以工作室的角色,用我們累積的技術與經驗為公司提供服務。
由於我們兩人在 openmoko 與 0xlab 的經驗之故,目前為止想要先將範圍鎖定在
- Embedded Linux
- Android app
- Android framework
若有相關的需求,歡迎寫信給 john@0xlab.org 洽談,John 會與我同步討論。
[1] JJ's Studio - http://asleepfromday.wordpress.com/jjs-studio/
June 9, 2012
Debian Linux 傳送檔案到 ICS 的 Galaxy S2
因為老婆熱愛桃紅色的手機,於是換了一台 Samsung 的 Galaxy S2 給她。
身為一個阿宅,當然要盡快幫老婆的手機升級到 Android 4.0 的 Ice Cream Sandwich. 升級到 4.0 之後,比較重大的改變就是 USB storage 的功能變成了 MTP,目前看到的 windows 使用好像沒啥問題 (有問題應該也不敢賣吧),但是很不巧的,在 linux 底下好像麻煩許多。
稍微 google 一下,解法不外乎是用 gmtp 或是 mtp-tools 去 mount mtp,但我在 更新到 4.0 的 S2 上面怎麼試怎麼失敗,完全無法 connect。直到我看見這篇 MTP connection between Galaxy S2 裡面有段話
所幸底下有解法,解法意外的簡單,打開 Settings,進入 wifi 的設定,裡面有個 USB 工具,在 Connect Storage to PC 點一下即可。
底下是傻呼呼 Step by Step 教學
1. 首先拔掉手機跟電腦之間的 USB 線
2. 在桌面的 Menu 裡頭點 Settings
3. 在 Wireless and Network 那一區裡頭點選 More
4. click USB Utilities
5. Connect Storage to PC
6. 出現這個對話框的時候,把 USB 線接上
7. Here you go! 人生依然美好
同場加映:在 4.0 之後要抓圖,是「按著 Power 鍵 + Home 鍵持續一秒」,抓的圖會放在 Pictures/Screenshots 目錄底下
身為一個阿宅,當然要盡快幫老婆的手機升級到 Android 4.0 的 Ice Cream Sandwich. 升級到 4.0 之後,比較重大的改變就是 USB storage 的功能變成了 MTP,目前看到的 windows 使用好像沒啥問題 (有問題應該也不敢賣吧),但是很不巧的,在 linux 底下好像麻煩許多。
稍微 google 一下,解法不外乎是用 gmtp 或是 mtp-tools 去 mount mtp,但我在 更新到 4.0 的 S2 上面怎麼試怎麼失敗,完全無法 connect。直到我看見這篇 MTP connection between Galaxy S2 裡面有段話
In short: your device doesn't use MTP as libmtp understands it. It's a custom stack by Samsung and you're sort of just screwed.
(簡單來說,libmtp 並不了解你的裝置上面的 MTP,那是 Samsung 自己搞的一套,你吃屎了)好吧。Base on Linux 的 Android 搞了一個 Linux desktop 很難溝通的機制,Android team 真是太傑出了。
所幸底下有解法,解法意外的簡單,打開 Settings,進入 wifi 的設定,裡面有個 USB 工具,在 Connect Storage to PC 點一下即可。
底下是傻呼呼 Step by Step 教學
1. 首先拔掉手機跟電腦之間的 USB 線
2. 在桌面的 Menu 裡頭點 Settings
3. 在 Wireless and Network 那一區裡頭點選 More
4. click USB Utilities
5. Connect Storage to PC
6. 出現這個對話框的時候,把 USB 線接上
7. Here you go! 人生依然美好
同場加映:在 4.0 之後要抓圖,是「按著 Power 鍵 + Home 鍵持續一秒」,抓的圖會放在 Pictures/Screenshots 目錄底下
March 13, 2012
Android Clickable Span in TextView
Spannable 可以讓一個 TextView 顯示不同外觀的字串,也可以加入 Click 事件的 callback。
通常想讓 TextView 觸發 Click 事件,最直接的正規作法就是 View.setOnCilckListener。倘若運氣不好,遇上一些比較奇怪的需求,例如一串文字的某一部份用一種顏色,另外一部份使用其他顏色,而這兩者同時都要能夠 Click。
這樣的需求能以 ViewGroup + TextView 完成,但更進一步的問:是否用一個 TextView 就解決?解答就會導向 Spanned/Spannable
不知道 Span 該如何翻譯,單從功能上來看,Span 是賦予一段文字(CharSequence)額外的能力。舉例來說我有一個字串 TheFinalAnswerIs42,我希望 Final 的部份以紅色顯示,42 的部份可以被 click,就是把 ForegroundColorSpan 設給 Final,ClickableSpan 設給 42,如此一來,TextView 仍然是顯示這一段文字,內容卻變得更加豐富。
先看看物件之間的關係,Spanned 介面繼承了 CharSequence,Spannable 介面繼承了 CharSequence,TextView.setText 的對象是 CharSequence,因此所有的 Spanned/Spannable 都可以直接放入 TextView 而不會出錯。因此問題簡化成如何從一個 String 變出我們需要的 Span。
查閱 Android 本草綱目,利用 SpannableStringBuilder 產生 SpannableString
如此一來,這個字串的其中一部分就被賦予了變色的能力,如果要使其成為 clickable
最技巧的部份就是 setSpan,使用的對象是最原始的 Object 而非比較嚴謹的 Spanned 之類介面,本草綱目也說你可以任意綁上自己定義的物件,問題就在此:TextView 怎麼知道如何用我定義的物件?反過來想,TextView 是如何使用 ClickableSpan?
簡單挖一下 TextView 的 source code 即可明白:TextView 的 onTouchEvent 有針對 ClickableSpan 做處理。換句話說自己定義的 Span 無法被 TextView 認得,必須繼承 TextView,針對自己的 Span 做處理,至於 Api 裡頭提供的 Spannable,TextView 應該都已經認得,不須擔心。
於是,一個原本單調的 TextView,賦予 Span 進去之後就會開始變得多采多姿。
通常想讓 TextView 觸發 Click 事件,最直接的正規作法就是 View.setOnCilckListener。倘若運氣不好,遇上一些比較奇怪的需求,例如一串文字的某一部份用一種顏色,另外一部份使用其他顏色,而這兩者同時都要能夠 Click。
這樣的需求能以 ViewGroup + TextView 完成,但更進一步的問:是否用一個 TextView 就解決?解答就會導向 Spanned/Spannable
不知道 Span 該如何翻譯,單從功能上來看,Span 是賦予一段文字(CharSequence)額外的能力。舉例來說我有一個字串 TheFinalAnswerIs42,我希望 Final 的部份以紅色顯示,42 的部份可以被 click,就是把 ForegroundColorSpan 設給 Final,ClickableSpan 設給 42,如此一來,TextView 仍然是顯示這一段文字,內容卻變得更加豐富。
先看看物件之間的關係,Spanned 介面繼承了 CharSequence,Spannable 介面繼承了 CharSequence,TextView.setText 的對象是 CharSequence,因此所有的 Spanned/Spannable 都可以直接放入 TextView 而不會出錯。因此問題簡化成如何從一個 String 變出我們需要的 Span。
查閱 Android 本草綱目,利用 SpannableStringBuilder 產生 SpannableString
Spannable span = (new SpannableStringBuilder()).newSpannable("TheFinalAnswerIs42");
span.setSpan(new ForegroundColorSpan(0xFFFF0000), 3, 5,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
如此一來,這個字串的其中一部分就被賦予了變色的能力,如果要使其成為 clickable
span.setSpan(new MyClickableSpan(), 16, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mTextView.setText(span); mTextView.setMovementMethod(LinkMovementMethod.getInstance());MyClickableSpan 是繼承 ClickableSpan 的實作,只要覆寫 onClick 即可。
最技巧的部份就是 setSpan,使用的對象是最原始的 Object 而非比較嚴謹的 Spanned 之類介面,本草綱目也說你可以任意綁上自己定義的物件,問題就在此:TextView 怎麼知道如何用我定義的物件?反過來想,TextView 是如何使用 ClickableSpan?
簡單挖一下 TextView 的 source code 即可明白:TextView 的 onTouchEvent 有針對 ClickableSpan 做處理。換句話說自己定義的 Span 無法被 TextView 認得,必須繼承 TextView,針對自己的 Span 做處理,至於 Api 裡頭提供的 Spannable,TextView 應該都已經認得,不須擔心。
於是,一個原本單調的 TextView,賦予 Span 進去之後就會開始變得多采多姿。
Subscribe to:
Posts (Atom)











