2010年1月31日 星期日

Android: Seesmic



如果問, Android上最好的Twitter client是哪一個? 我一定投給Seesmic (不要問我為啥不是Peep :P)

比起比較早出現的Twidroid, 它的功能並不多, 但其實已經夠用了, 比起Peep, 它的介面又清爽了許多, 整體上, 雖不華麗, 但在操作上的便利性上似乎也下了點功夫, 相當的直覺


反應速度上也相當的理想, 瀏覽Tweets時, 一直往下捲就會一直往回幫你抓舊的回來, 對於在無聊時往回看以前的推, 相當的方便, 很多功能一層層往下, 相當直觀, 也支援lists

我個人比較喜歡是搜尋的設計, 它分成了All, Trending topics, users等三類, 也可以將search的關鍵字儲存起來, 跟網頁上的使用習慣相當的接近

缺點:

  • "Send"的位置擺在左上角其實對右手單手操作很不便利, 電容式螢幕容易為了按"Send"而誤觸了虎口附近的按鈕
  • Lists的設計, 必須從Menu才可以進入, 其實蠻不方便的, 多一個tab來放lists其實也不為過, 因為會想要用lists閱讀時, 有可能都是在那時候不想閱讀其他在timeline裡面不相關的訊息
  • 自己的lists的列表, 應該是有必要cache的, 感覺它還是每次要去從server取得
  • 應該要有個Widget或是Shortcut可以隨時隨地立刻發推才對
我的評價: 4.75/5

Android: Mobisle Notes Free


記事本絕對是一隻智慧型手機上很重要很常用的軟體, 如果一隻智慧型手機無法拿來記事, 其實挺遜的, 不過很常出貨的手機都忽略掉這一點了, 所幸Android上還有Market

我平常也是很常用記事本來記事的, 不過有時候其實也是會拿推特來隨手記, 在我手機上, 我最常用的一個記事本就是這個Mobisle Notes Free

這記事本有啥優點呢? 其實他沒很多的功能, 但介面乾淨, 簡單好用, 這已經是很大的優點了:

這是它的主畫面, 依時間條列出記事, 其實還蠻清爽的


編輯模式有兩種, Checklist模式跟純文字模式, 一魚兩吃, 其實還蠻方便的, 還可以透過mail, mms這些分享

設定畫面, 從這邊可以看出它支援備份與還原

缺點:
  • 無法分類, 分類功能其實是很重要的, 不然筆記一多就很難整理了
  • 同步到雲端去, 比如說同步到Google notes或Google docs, 有這類的功能才有辦法跟其他的裝置, 比如說PC共用
整體說來, 以五分滿分的標準下, 我給3.5分的評價

波西傑克森

哈利波特的最大貢獻就是引起整個世界對這類的奇幻童書的注意, 似乎也引起許多人投入這類小說的攥寫

"波西傑克森"也可以說是這類的小說, 老實說, 同樣的架構, 等同於霍格華茲的混血營, 雖然沒有霍格華茲的華麗與多采多姿, 但這類給特殊"小朋友"的學校, 基本上是波西與哈利兩本作品的共通點, 或許, 波西是效法哈利的故事架構, 不過這本小說比較大的特點是引入了希臘神話

希臘神話其實算來應該是世界文明的神話裡面相當人性化的, 眾神並不是完人, 而是跟人類一樣也有相當多的人性弱點, 風流就是其中一種, 整個故事就是以眾神的風流債為主軸, 最好笑的是故事後面波西等於要眾神承認自己的風流... :P

從第一冊神火之賊到最後一冊的終極天神, 其實不用對希臘神話很了解衣樣可以很enjoy在這幻想空間中, 看完後可能還會對希臘神話產生興趣

昨天把最後一冊終極天神給看完, 還算不錯, 其實還想再看第二遍(全套), 期待電影 

Leap Frog Tag



昨天去書展替小遠買了這樣一個東西, 雖然有點貴, 但相當有趣, 想說看能不能讓他喜歡上閱讀, 不過這產品讓我覺得比較貼心的是家長功能, 可以追蹤小朋友的學習, 雖然現在小遠還不會自己拿這來學還需要陪他一起, 不過未來等他會自己玩後, 應該是相當貼新的功能

2010年1月30日 星期六

跨行程(Process)的檔案存取

一個Android應用程式有許多種存取資料的方法, Sqllite database是一種方式, 而最原始的方法就是檔案

翻開官方的文件, 在Dev Guide -> Data Storage -> Files 裡的第一段:

You can store files directly on the mobile device or on a removable storage medium. By default, other applications cannot access these files.

一個應用程式可以存取的檔案系統, 除了像是SD Card這種可移除式的媒體外, 就是內建的儲存體, 但使用內建的儲存體有一個缺點, 因為每個Android應用程式如果不是特別指定, 它都會擁有一個專屬的uid (請參考Linux/UNIX的基本文件), 預設開檔的模式是只有自己可以讀取, 因此別的應用程式, 是讀取不到這個檔的, 就算知道檔案的絕對路徑, 這當然是一種安全性的考量, 但有時候針對某些應用我們又希望能夠在不同的應用程式間分享檔案

首先先來看一下如何開啟內建儲存體內的檔案作為寫入跟讀取, 以下是相關的methods:

  • Context.openFileInput
  • Context.openFileOutput
  • Context.deleteFile
  • Context.fileList
  • Context.getFilesDir
  • Context.getFileStreamPath
  • Context.getCacheDir

如果是要開啟檔案作為輸出用, 可以用openFileInput, 透過這個寫入的檔案會在 "/data/data/your_app_package_name/files"底下, 這method可以有兩個參數,

openFileOutput(String name, int mode), 第一個當然不用多說, 第二個有幾種模式

  • MODE_APPEND 開啟檔案作為附加新內容(Append)
  • MODE_PRIVATE 這是預設, 也就是說其他的application (不同的uid), 不可以來存取
  • MODE_WORLD_READABLE 全世界的人都可以來讀, 只要知道路徑檔名
  • MODE_WORLD_WRITABLE 除了開放給所有的人讀也可以寫

從這邊就可以知道, 開MODE_WORLD_WRITABLE, 就可以達到跨行程檔案共用的方式, 但這方法的缺點是, 等於把權限開放給所有人, 只要知道目錄的應用程式都可以來存取, 甚至可以刪除, 完全無法管控, 其實挺危險的

另外一個方式是透過ContentProvider的方式, 這方式因為透過Uri來存取, 可以隱藏實際檔案位置, 而且不需暴露檔案實際位置, 因為是透過ContentProvider所以也加上permission的管控

在ContentProvider裡面寫法很簡單, 只要overwrite "openFile"即可, openFile接受Uri和file mode兩個參數, Uri和檔案的對應關係, 可以由ContentProvider這邊自由決定, file mode是存取模式, API文件裡面寫的是"rwt", r - read, w -write, t - truncates, 但其實這也是可以由實作端控制, 未必一定要照這規則

這個method必須回傳一個ParcelFileDescriptor, 如下

public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
File myFile = new File("/sdcard/abc");
return ParcelFileDescriptor.open(myFile,
ParcelFileDescriptor.MODE_READ_WRITE);
}

在另一個行程需要透過這個ContentProvider 存取檔案也很簡單, 只要利用ContentResolver.openFileDescriptor, 呼叫這個method就可以得到由ContentProvider得回來的ParcelFileDescriptor

可是又要怎存取這個ParcelFileDescriptor呢? 透過ParcelFileDescriptor.getFileDescriptor就可以取得FileDescriptor的實體, 利用這個就可以透過FileInputStream和FileOuputStream來存取了, 如下例

ParcelFileDescriptor remoteFD = resolver.openFileDescriptor("myuri://URI", "rw");
FileOutputStream out = new FileOutputStream(remoteFD.getFileDescriptor());

高階應用:
ParcelFileDescriptor其實也可以來自於Socket, 只要用ParcelFileDescriptor.fromSocket(Socket socket)


2010年1月24日 星期日

關於AlarmManager之二三事 (3)

怎樣查看一個alarm有沒正確的跟Alarm manager註冊了呢?

這時候就是請出bugreport的時候了:

adb bugreport > bugreport.txt

打開bugreport.txt後搜尋"DUMP OF SERVICE alarm", 你就會發現下面的資訊, 這就是你需要的了:

Current Alarm Manager state:

Realtime wakeup (now=1264350748706):
RTC #1: Alarm{43c639e8 type 1 android}
type=1 when=1264435200000 repeatInterval=0 count=0 operation=PendingIntent{43bb7510: PendingIntentRecord{43bf57a0 android broadcastIntent}} RTC #0: Alarm{43dad548 type 1 android}
type=1 when=1264350780000 repeatInterval=0 count=0 operation=PendingIntent{43b9fc48: PendingIntentRecord{43c13278 android broadcastIntent}}

Elapsed realtime wakeup (now=1979294):
ELAPSED_WAKEUP #0: Alarm{43d33930 type 2 android}
type=2 when=70664306 repeatInterval=0 count=0 operation=PendingIntent{43bb39e8: PendingIntentRecord{43b80d90 android broadcastIntent}}


關於AlarmManager之二三事 (2)

setReaping與setInexactRepeating有啥不同?

在這系列的第一篇有提到, 無故的叫醒手機是很耗費電力的, 但有時候卻又不得不這樣做, 如果盡可能的把喚醒的間隔拉長是可以緩解這問題

但真正的問題在於, 一支手機內不會只有一支程式需要每隔一段時間觸發一次, 如果碰到以下這狀況:

程式A, 05:05.00 設定每隔1小時
程式B, 05:06.30 設定每隔1小時
程式C, 05:07.00 設定每隔半小時

雖然看起來每支程式觸發最小間隔要半個小時, 但其實在這狀況, 手機分別會在05:37.00, 06:05.00, 06:06.30, 06:07.00 被喚醒, 次數並不少, 而且在六點多這時候被喚醒的間隔是很短的

在1.5之前, 用setRepeating來設定週期性的Alarm的確會有這情形, 但其實, 常常程式不是真的需要在很精確的時間被執行(除非是鬧鐘), 這樣的作法相當浪費

因此在1.5的時候, 多了setInexactRepeating, 這method照API文件上的說明的意義就是盡量把相近的Alarm集中在一起觸發, 如果不是很要求精確在某一時間觸發的話, 其實應該要選用這個

但setInexactRepeating其實有陷阱的, 它的間隔只有在以下幾種數值內才有作用:

  • INTERVAL_FIFTEEN_MINUTES
  • INTERVAL_HALF_HOUR
  • INTERVAL_HOUR
  • INTERVAL_HALF_DAY
  • INTERVAL_DAY

如果不是落在這五種的範圍內, setInexactRepeating和setRepeating根本就是等義


關於AlarmManager之二三事 (1)

Alarm type分為四種

  • ELAPSED_REALTIME
  • ELAPSED_REALTIME_WAKEUP
  • RTC
  • RTC_WAKEUP
RTC類別的, 計算時間的方式是以實際的系統時間, 因此, 當User變動系統時間(或另一種狀況, 系統時間被自動更動), 就會影響到排程, 此時可能就需要寫一支BroadcastReceiver去聽Intent.ACTION_TIME_CHANGED來做重新排程的工作, 此種類的用途通常是用在真的需要在某個特定的系統時間作為觸發

ELAPSED_REALTIME則不同, 它計時的方式是以手機開機後開始計算, 不會受到系統時間變更所影響, 只是它的缺點在於它與系統時間沒有絕對關係, 較適合定時觸發的動作

而有WAKEUP和沒WAKEUP的差別呢? 手機在待機時是有可能進入休眠狀態的, 此時整個系統是不會有動作的, 在有WAKEUP的Alarm被觸發後, 此時Alarm Manager會去把手機給叫醒, 並且請求Wake lock鎖住手機不立刻進入休眠, 直到intent receiver的onReceive做完才會釋放wake lock, 而RTC, ELAPSED_REALTIME是不會強行叫醒手機的, 而是會等到手機真的醒了之後才會有機會被觸發

無端端叫醒手機, 其實對手機電力的影響不小的, 所以在使用Alarm manager必須要很小心去避免無故的叫醒正在沈睡的手機


反省

看了自己前兩篇比較技術性的文章, 發現幾個問題:

  • 術語有些自己多此一舉做翻譯, 有些卻沒有, 並不是容易閱讀
  • 版面編排亂七八糟
  • 組織性不夠, 篇幅又太長
  • 範例的註解不夠
下次想嘗試縮短篇幅了, 用寫tips的方式或許比較好閱讀


Blogo似乎不錯用

感覺比以前用ecto或MarsEdit都好用太多了, 25 USD好像也不是太貴, 先試用一陣子吧


2010年1月23日 星期六

替Pluroium加上plugin功能

之前一篇文章囉哩八梭的講了一堆Intent, 這次來看個實例

拿Pluroid的open source - Pluroium來當作實驗對象, 這次要實驗的是如何替它的compose畫面提昇一個簡單而彈性的功能, 先來看一下畫面:




為了怕被鍵盤擋住, 所以先稍微小一下Layout把表情符號給加了上去, 並且加了一個按鈕"Attach"

這Attach的作用是用來讓使用者選擇要插入的內容, 比如說他可以選擇一個圖片上傳後把圖片URL插入到內容內, 或是選擇一個位置把地址插入到裡面, 諸如此類的功能, 但這邊又不想把功能寫死, 而是要可以讓主程式不動, 隨著外掛plugin安裝可以讓它支援更多的內容

先來看看插入的Attch button的layout

<Button android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="Attach" android:onClick="handleAttachment"></Button>


在Button01定義的onClick是handleAttachement, 所以我們在ComposeActivity上加上

public void handleAttachment(View target) {
Intent intent = new Intent("org.pluroid.pluroium.COMPOSE_PLUGIN");
startActivityForResult(Intent.createChooser(intent, "Choose a plugin"), RESULT_COMPOSE_PLUGIN);
}

這段有幾個部份要解釋一下:
  • org.pluroid.pluroium.COMPOSE_PLUGIN 這是用來呼叫plugin的action
  • startActivityForResult 這跟startActivity的不同點是, 當它呼叫的Activity結束時, 它可以接收到它呼叫的Activity的結果
  • createChooser 這算是個utility method, 它幫你包裝了一些東西, 在這邊搭配startActivity使用的話, 如果有多個Activity支援COMPOSE_PLUGIN, 那麼當按下Attach後就會先跳出一個標題是"Choose a plugin"的視窗列出所有支援這intent的Activities讓User選擇(如果只有一個Activity, 就不會出現這視窗
  • RESULT_COMPOSE_PLUGIN 這是一個數字, request code, 當callee activity結束後, 要靠這個讓caller activity知道它剛剛是處理哪種


Activity還需要overwrite一個onActivityResult, 範例如下

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == RESULT_COMPOSE_PLUGIN && resultCode == RESULT_OK) {
String text = data.getStringExtra(Intent.EXTRA_TEXT);
plurkContent.append(" ");
plurkContent.append(text);
return;
}
super.onActivityResult(requestCode, resultCode, data);
}

這就是接收剛call那個activity回傳回來的結果

這時候你如果興沖沖的跑去測試這按鈕, 你一定會很失望, 因為一按下按鈕, 程式馬上爆炸...別急, 因為你這時候還沒找到任何支援這個intent action的activities, 當然會有問題啦!!

為了保險起見, 我們可以在initView裡加上一段保險, 如果裡面沒有任何Activities有支援這action就把attach button給disable

PackageManager pm = this.getPackageManager();
Intent intent = new Intent("org.pluroid.pluroium.COMPOSE_PLUGIN");
List ativities = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);

if(ativities.size() == 0) //No activity found for "org.pluroid.pluroium.COMPOSE_PLUGIN"
findViewById(R.id.Button01).setEnabled(false);


加上這個後, 看起來就保險多了, 接下來我們可以來設計plugin了:
這plugin基本上只要可以處理COMPOSE_PLUGIN就好, 因此Intent filter很簡單,

接下來我們先來做一個簡單的plugin activity, 讓使用者按下OK後就回傳"Hello Pluroium", 以下是Sample code:

public void doOK(View target) {
Intent data = new Intent();
data.putExtra(Intent.EXTRA_TEXT, "Hello Pluroium");
setResult(RESULT_OK, data);
finish();
}
public void doCancel(View target) {
setResult(RESULT_CANCELED);
finish();
}

(兩個button, 一個onClick設成doOK, 一個是doCancel)
利用"Activity.setResult", 我們就可以把user的選擇結果回傳給ComposeActivity了

----------------------------------
謎之音: 文句寫的真不通暢, 果然該睡了

----------------------------------


懶得在往前整理了

新年新氣象, 從新再開始寫吧

"Sense"

(Origin: 2009/12/31 Tweets)

I don't think that "sense" is only "make sense". The most important is knowing what users want it to be.

使用者介面應該著重流程與邏輯, 不能只是make sense, 還要可以讓user直覺的操作

很想學習這方面的學問

胡言亂語 / 2010年1月1日

(Origin: 1/1 Tweets)

2010年早上一起床,覺得可以把想了一整年的問題下一個推論: 這公司為何賺錢?強大的行動力是主因,以強大的行動力走在鋼索上,但卻已有如一顆從核腐壞卻拼命用強力防腐劑維持表面鮮紅的蘋果一樣,並不如外表可口

如果把強大的行動力精準的用在對的地方,其實以同樣的資源應該可以用兩倍於原本的速度做更加多的事.....在原料成本上的斤斤計較並無助於節省成本,相反的把資源集中在有價值的東西上才能創造有競爭力的產品,在這對手也是同樣光速成長的年代,多餘的耗損只是給別人機會跟上而已

各類的中長程計劃是絕對必要且必需keep on track,必需能dynamic隨時勢調整但dynamic必需是局部性而非全盤推翻,不然資源的耗損就高,反倒會致命

What a good mobile application look like?

(Origin: 1/6 Tweets)

我認為是:

Neat and clear UI with stable and higher performance

在Mac上寫blog

剛打了長長一篇, 發現在Browser打這些文章其實很難用, 貼過去的tag不會幫我轉><

裝了Qumana, 其實也沒好用到哪去, 不知道有沒比較好用的軟體 @@"

真麻煩

淺談Intent

(Origin 1/6 Tweets)

Android上的Intent其實是個簡單而強大的機制, 不同的應用程式可以利用它互相的傳遞資訊
從這機制可以來延伸思考, 不同軟體間的各自為政將會是種錯誤的事, 軟體與軟體間應該能盡量建立connection, 打破藩籬, 一直在單一軟體增加功能會是死路一條吧

舉個簡單的例子, Camera軟體拍照完, 可以直接將照片分享到e-mail, mms, 網路上, 也可以直接送到後處理軟體後製(例如說PicSays), 一個Camera軟體不需要自己提供所有的功能, 只要把成品送至有適當接口的軟體, 它只要專心把拍照功能做好, 其他就交給別人去加強它

當然後製軟體也可以在做完後製後交接給下一棒, 比如說還是可以在這邊做分享的動作, 這樣各種模組的組合下, 就有不同的可能性, 使用者也可以選擇對他來說比較方便的軟體當成其中的模組不需要受限於某種特定軟體之中

這種模式可以把一個大型的軟體應用拆裝成不同的積木, 開發者可以各自開發自己擅長的部份, 使用者也可以依自己喜好組合

Intent的使用上相當的簡易, 最基本的組成是: action, data



  • action 代表的是要被處理的動作, 舉個簡單的例子, Intent.ACTION_VIEW , 如同字面上的意思, 這個動作就是用來"檢視"(View)某種資料 , 處理這個Intent的Component(Activity, BroadcastRecevier)就要去針對對應的action實作動作

  • data 是個uri, uri指向資料實際的位置(可以是實體檔案, 也可以是一個provider, 也可以是個contact) , 處理這個Intent的Component(Activity, BroadcastRecevier)必須要提供處理這個data的能力


除了這兩樣東西外, 其他還可以帶的資訊是: category, type, component, extras



  • category 藉由category可以把一系列相關的intents給grouping起來, 最常見也一定會見到的intent category就是CATEGORY_LAUNCHER , 如果某個Activity的intent filter含有這個category, 表示這個Activity會在Home的Launcher(啟動程式區)裡看到, 如果某個Activity標上了android.intent.category.SAMPLE_CODE , 那你就會在SDK裡面的ApiDemos 找到它的入口

  • type 指的是資料的mime type, 這在某些Action 是相當有用的, 比如說ACTION_SEND, Camera拍照後Share相片, 是透過這個action, Browser share link也是透過這action, 但一個AP未必支援兩種資料, 這時候就是透過mime type來區分的, 基本上Camera , Browser都是會直接叫ACTION_SEND, 但一個會指定mine type是image/*一個會指定text/plain , 所以, 雖然是同一種intent action, 帶出來的menu裡的items也會不同

  • component 用來指定某一特定的component (Activity, BroadcastReceiver), 註冊同一種intent的components有可能不只一個 , 透過指定component name, 可以直接呼叫特定的component

  • extras 用來帶額外的資料, 比如說Browser call ACTION_SEND, 就會額外帶EXTRA_TEXT, EXTRA_SUBJECT



一個activity能處理的intent是定義在AndroidManifest裡的intent-filter section, 如

<activity android:name=".app.HelloWorld" android:label="@string/activity_hello_world">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>


(寫到這邊有點懶得寫了, 直接寫應用, 因為很多都可以看SDK doc)




如何取出support某個intent的activities?

可以使用 PackageManager.queryIntentActivities(Intent intent, int flags)

這個還有個應用, 可以用來得知某個程式有沒被安裝

拓展Browser的應用

其實Browser會把Uri forward給可以處理它的Activities, 比如說"market://" , 碰到這種連結就會直接給Market , 當然, Browser本身也是處理"scheme: http及https"類型intent的application, 所以就可以有以下這樣的應用:



  • OAuth callback, 這是我看來的用法不是我發明的, 挺高明的, 在寫OAuth時, 如果沒有call back url, 就變成要user輸入一個verifier, 這種在使用上蠻討厭的, 但其實call back url也是可以是個Uri的, 比如說"myapp://xxxx" , 只要實作一個處理這Uri的Activity就可以處理掉這問題了

  • 續上, 延伸應用, form action其實應該也可以套用同樣的作法, 因此可以寫一個web form call local app來處理data

  • Remote image viewer 如果 http://xxx/xxx.jpg這類的圖檔連結可以用自己的image view開啟, 那可以提供不同於Brower的使用體驗, 要達到這樣也很簡單, 以下就是用來處理Flickr圖檔連結的intent filter
    <intent-filter><action android:name="android.intent.action.VIEW"></action>
    <data android:scheme="http" ></data>
    <data android:host="*.flickr.com"></data>

    <category android:name="android.intent.category.DEFAULT"></category>
    <category android:name="android.intent.category.BROWSABLE"></category>
    <data android:pathPattern=".*\.jpg"></data>
    </intent-filter>


寫這麼多字, 後面越來越文句不通暢, 懶得寫了, 有空在來整理



What Android should be? What a phone could do? What Android could do?

(Origin: 1/6 Tweets)

不覺得Nexus One (N1) 的銷量會很爆炸性, 雖然價格跟規格算起來都算空前, 不過我不認為這隻的銷量對Google來說有多大的意義

在N1之前已經出過不少的Android Phone了, 一開始出的G1的意義是宣示了Android is coming, 但隨之HTC的多款手機, 直到後面開始百家爭鳴, Android跟iPhone一個很大的差別就出現了

iPhone是一個封閉但卻獨佔(只有Apple)的平台, 所有規格, 應用皆掌握在Apple手中, 不過Android則不一樣, 真的是百家爭鳴, 這對在上面的軟體開發來說或許有可能是個惡夢, 尤其想開發高階應用的軟體

N1應該也是一種宣示, 宣示Android就該是這樣, 這種規格, 這種價格, 這種銷售方式, 如果他吸引了夠多的眼球, 也越來越多N1-spec compatible 的軟體, 那他就會是一種"參考"的基本

不過, 這只是我個人的假設而已啦

身為一個developer, 我倒比較希望看到像是Cynogen那些可以玩出什麼好玩的東西

等車胡思亂想記1/12: 智慧型手機平台

(Origin: 1/12 Tweets)

智慧手機商應該積極經營好平台,有好的平台(軟硬體)才會吸引開發者開發更多好功能,有更多好應用就會吸引更多消費者,有更多消費者就會再吸引更多軟體公司進場,iPhone的確做到了

其實智慧型手機商不需要自己開發太多的功能在上面, 只要focus在基本功能上, 其他的就只要經營好平台就好, 一支太多功能的手機, 或許對使用者來說很"俗又大碗", 但也是一開始而已, 一家廠商絕對無法兼顧所有使用者的需求, 加上智慧型手機的平台特性, 很多第三方的軟體公司, 開發者也會開發性質類似的軟體, 到最後使用者未必覺得內建軟體符合他的需求, 反倒會尋求其他的替代, 與其與這些第三方的軟體開發做競爭, 不如把氣力花在平台的經營上

越多人想在你的平台上, 甚至願意為你的手機做特製版本, 自然就容易吸引更多人購買, 平台的數量增加了, 其實對這些人也是有利的

平台以及在其上的應用, 其實應該是互相提昇對方的, 舉個例子, Facebook 是個社群網站, 本身也是一個良好的平台, 在上面的應用軟體跟Facebook本身也是互相提昇的(如果當初Happy Farm只有單機版, 就算是一個online 版, 或許也不會有多成功)

對User Experience的一點小見解

(Origin: Tweets at 1/12)
突然有種感覺, 所謂的UE, 並不是去找出User所習慣, 所想要的, 而是被創造出來的

以iPhone來說, 其實沒有phone key的手機在真正想打電話的時候是相當不方便的, 但iPhone的User就深覺得按鍵越少越好, 但卻不會自覺打電話的步驟變多了, 傳統的手機, 主要以打電話為主, 從口袋一拿出來, 按下數字, 播號, 其實很簡單, 但iPhone沒Phone key, 沒多工, 要打電話步驟多, 又得暫停手邊的工作, 其實並不是非常好, 但習慣的人一定會覺得, 按鍵少了使用比較直覺, 這也沒錯, 只是這種習慣不是user一開始就想要的, 卻有點像是被教育出來的

Multi-touch也是個例子, 以最近在用MBP, MT其實是相當方便, 但在手機上, 拿MT放大縮小甚至一些手勢乍看之下好像很方便, 但其實手機單手持的機率很高(至少我是這樣), MT根本無用武之地, 甚至不甚好用, 其實Android Browser以前有個很方便可以放大縮小的control, 對單手操作相當的方便, 但後來就不見了, 現在反而一直被要求要MT, MT反倒變成一個非有不可的要件, 對於HD2那種大螢幕, 本來單手就很不方便, 自然而然會以雙手操作, MT在上面的話就還算好用, 但說實在的, 像在Hero這種大小的螢幕, 個人其實蠻討厭必須要用MT才能操作的場合

這兩點, 我不認為Apple去找出來的使用者習慣, 而根本就是Apple創造出來的使用習慣, 漸漸似乎就變成準則, 因此似乎創造才是做好這件事的根本

但是創造應該也不是無來由的亂創造, 如果不依循使用邏輯, 不符直覺, 不夠簡單的話, 也不容易讓使用者一操作就變成他的使用習慣

一味的拼Fancy, 如果沒注意到使用習慣, 再華麗的介面也只是累贅

來開始把之前在Twitter寫的整理一下吧

一直懶得寫blog, 今年開始得好好經營了, 其實之前在Twitter上斷斷續續寫了一些, 應該可以把它整理到Blog上來了