星期三, 6月 18, 2014

國二作文簿 (part 3)

哈哈哈我在寫什麼啦 XD

我喜歡

涼風送爽的季節,百花盛開、鳥語花香、大地一片翠綠。啊!我愛春的原野;烈日炎炎的季節,蟲鳴鳥叫、繁星點點、夕陽一輪火紅。啊!我愛夏的烈日;風高企爽的季節,涼風陣陣、馨香四溢、蝴蝶翩翩飛舞。啊!我愛秋的涼風;冰天凍地的季節,百獸休憩、霜臨大地、世界一片靜寂。(只有「百獸」的打呼聲而已)啊!我愛冬的熱鬧靜寂

看!那清晨的霜露結在草地;那傍晚的天空一片紫紅;那午的烈日竟情揮灑,那入夜的星空光彩奪目。我只要他們的萬分之一;清晨的純潔、傍晚的美貌、午的瀟灑和入夜的紛......(好像在看古早的文藝愛情片)確實

春,醒了,又睡了;夏,醒了,又睡了;秋,醒了,又睡了;冬,醒了,又睡了;早晨,醒了,又睡了;午候,醒了,又睡了;傍晚,醒了,又睡了;夜,醒了,又睡了。可是人,永遠都醒著,也永遠都睡著。醒在夢裡,睡在現實,醉在今宵,活在黎明。

這兩句,正好就是你的寫照!
要老師怎麼批呢?
一、二段真是太棒了
第三段真是太混了


繽繽繽繽繽繽繽繽繽繽繽繽繽繽繽繽繽繽繽

第三段之所以這樣寫,是因為字數夠了......

第一段被劃掉的熱鬧,我的確是故意寫「熱鬧」的。老師大概沒有理解我的修辭手法......

「午候」的「候」,我的確是要寫「候」而不是「後」,所以刻意不訂正。

上標部分是寫在格子旁邊導師批改的留白部分。

理工人不是不能寫矯情油膩的文章,只是不屑寫

星期二, 6月 17, 2014

國二作文簿 (part 2)

翻到國中時的作文簿......(紅字部分為導師批改)

花與樹(新詩創作)

花;
一朵花;
一朵美麗的花;
一朵美麗的小花,
象徵美麗,也象徵脆弱(希望)

樹;
一棵樹;
一朵高大的樹;
一朵高大的大樹,
象徵平凡,也象徵壯碩。

花與樹;
一朵美麗的花語高大的樹。
一朵美麗的小花和高大的大樹。
象徵和諧,更象徵著生生不息。

相同的意境,就不必重複的敘述。
詩,就是貴在言簡而意深,而你的冗句太多

沒法度,要湊篇幅啊!(本句為發還後補上...)

第一段的脆弱是要跟壯碩呼應,導師大概沒看到第二段就批改了。我現在看過,還是覺得放脆弱更恰當。

我一直都是個非常討厭寫字的人。

星期六, 1月 18, 2014

程式設計師 vs. 新聞記者

Android 的 PopupMenu 不支援顯示 icon。可是很多時候你會想放個 icon 給他... 那怎麼辦呢?

深挖 PopupMenu 的程式碼以後,發現他實際是透過 MenuPopupHelper 這個 class 來顯示實際的 PopupWindow,而該 class 有個 setForceShowIcon() 函式,可以用來強制顯示 icon。

可是... 這個 mPopup 在 PopupMenu 裡是 private field 啊... client code access 不到它... 怎麼辦咧?

在這裡有兩個選擇...

  1. 搞肛的辦法...:把 PopupMenu.java 跟所有用到的 internal class 實作複製一份過來,多新增一個 setForceShowIcon() 方法。
  2. 偷吃步:透過 Java 的 Reflection 機制來偷偷存取該 private field。

當然,我不會在這裡講搞肛的辦法,因為我是怠惰的程式設計師,能偷吃步一定要偷吃步的(怠惰的程式設計師施工原則:自己要維護的程式碼越少越好)。

所以,本來這樣的東西:

PopupMenu menu = ...;
...
menu.mPopup.setForceShowIcon(true);

就變成了...:

public static void hackPopupMenuToShowIcon(PopupMenu popup, boolean showIcon)
{
    try
    {
        // 從所有 field 中找出名稱為 mPopup 的 field。
        Field[] fields = popup.getClass().getDeclaredFields();
        for (Field field : fields)
        {
            if ("mPopup".equals(field.getName()))
            {
                // 設定存取權(本來是 private field 不能存取)
                field.setAccessible(true);
                // 取得 popup 這個 instance 的 mPopup
                Object menuPopupHelper = field.get(popup);
                // 取得 mPopup 的 class
                Class classPopupHelper = Class.forName(menuPopupHelper.getClass().getName());
                // 取得 mPopup 的 class 的 setForceShowIcon() 這個 method
                Method setForceIcons = classPopupHelper.getMethod("setForceShowIcon", boolean.class);
                // invoke 該 method...
                setForceIcons.invoke(menuPopupHelper, showIcon);
                break;
            }
        }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

// 使用時變成
PopupMenu menu = ...;
...
hackPopupMenuToShowIcon(menu, true);

感覺就像台灣的新聞記者......

  • 馬總統正在公園慢跑。

硬要寫成

  • 馬總統英九先生目前正在一個被稱作公園的地方執行一個慢跑的動作。

星期四, 1月 09, 2014

RenderScript with AndroidStudio

=== 中文版 ===

我只是想 log 一些用 Android Studio 寫 RenderScript 的 gotcha...

  1. 如果你把 <script-name>.rs 放在跟 .java 同一個目錄,grandle 是不會幫你編的... 你得在跟 src、res 同一層開一個新的資料夾叫「rs」,然後把你的 <script-name>.rs 丟進裡面。
  2. 如果你在執行的時候,出現「Invalid RS info file /data/data/<package>/cache/<package>/<script-name>.o.info! (No such file or directory)」,表示你使用的 build-tool 高過執行環境的 API Level。請改用更低的 build-tool...

    具體作法,是去 build.grandle 裡面,把 buildToolsVersion 改低,例如改成 17...(記得要先去 SDK Manager 裡面裝上更低版本的 build tool。)

=== English Version ===

I just want to log some RenderScript gotcha's while developing with Android Studio.

  1. If you just dropped your <script-name>.rs within the same directory with your .java file, grandle won't compile it for you... You've got to make a new directory aloneside src and res, named "rs", and throw your <script-name>.rs over there.
  2. If you encounter "Invalid RS info file /data/data/<package>/cache/<package>/<script-name>.o.info! (No such file or directory)", that means your build-tool is too new to the environment API level. Switch to a lower version build-tool would make it run.

    In practice, edit build.grandle, switch to a lower "buildToolsVersion", for example 17... (don't forget to install a lower version build-tool with SDK Manager first.)

星期一, 1月 06, 2014

這不是姬兮兮

武漢女大生用數學符號作三行情詩 男友也驚呆

大陸中心/綜合報導

武漢長江工商學院大一女生吳華傑日前用數學符號「-∞」、「+∞」和幾個簡單的英文單詞向男友表達愛意,被同學們稱讚「高端、大氣、上檔次」,並獲得該校舉辦的「三行情詩」徵文比賽一等獎。

《楚天金報》報導,吳華傑是該校經濟與商務外語學院學生,頗喜歡研究、創作五言絕句和七言律詩等古詩詞;在一次上數學課時,她突然想到可以結合數學演算法,為男友寫一首情詩,就開始她的創作之旅:「INPUT (-∞,+∞),IF(-∞THEN+∞],ELSE+∞)。」

吳華傑說,「INPUT是數學語言中輸入的意思,-∞和+∞分別指負無窮和正無窮。第一行詩是指愛情開始時,雙方都在付出。IF是條件陳述式如果的意思,THEN是然後的意思,第二行詩指如果有一方背叛,負無窮付出,另一方就『]』(閉區間符號,特指停止)正無窮的付出。ELSE是否則的意思,第三行詩指彼此如果沒有背叛,就會為對方付出正無窮的愛。這首詩是想告訴男友,你若不離不棄,我定生死相依。」

「這首情詩把數學語言與文學相結合,表達雙方不離不棄的陪伴,牽著彼此的手走到生命的盡頭之意。高端大氣上檔次,一般人真寫不來!」該校清水石文學社代表許黎稱讚道。

吳華傑說,她和男友在讀高中時相識,因當時怕耽誤學業,她一直沒有接受男友的示愛,直至上大學後,兩人才確立戀愛關係。目前,她的男友正在創業,當看到這首情詩時,男友也驚呆了。
  1. 這可能不能算是數學、甚至不能算是程式碼,恐怕只能算是 psuedo-code...
  2. 括號沒對齊...

這讓我想起 PerlYuYanWikipedia 頁面居然被移除了 = =)... 所以寫了一段:

#!/usr/bin/perl
use Lingua::Sinica::PerlYuYan;

#用籌兮 用嚴兮 截起吾純心
#賦小入大合 兮註在君意
#印道我心哉 點起起純心
#等零倘壹合 歟道有情哉
#然曰無情矣 合兮井底空

翻譯...

#!/usr/bin/perl
use Lingua::Sinica::PerlYuYan;

use integer; use strict; chomp (my integer $D
= <stdin>); #在君意
print "我心" . (($D
== 0 xor 1) ? "有情"
: '無情'); #井底空

可是這首詩念一念,除了有點情色部分,好像被甩的話就要抓對方去跳井。

要算計、要嚴格,取一顆純淨的心。
把小的東西放進大的裡面(!?),兩個人情投意合。
在我心上相印,點綴純潔的心。
將 0 與 1 合在一起(!?),是有情還是無情?一起跳進空的井底。

我好無聊 XD

星期三, 6月 06, 2012

遺失

我改用 Chromium 很久了,大概是 Firefox 3 那時候吧!那時並沒有把即時書籤一起加入 Chrome,因為 Chrome 一直到現在都沒有好用的即時書籤 = =

最近因為要逛 Gnome Shell Extensions,把 Firefox(哇!都 13 了!)開起來,就想說看看以前朋友的 blog 還在不在。

我之前總共訂閱了 16 個朋友的 Blog、現在 8 個載入失敗、6 個超過三年以上沒新文章,只有兩個還繼續在寫。

可能大家都改玩 Facebook / Twitter / Plurk 了吧...

... 持之以恆真的很困難 XD
(我自己有時候也會空個一兩年才寫一篇文章 XD)

星期四, 3月 08, 2012

_id、_ID 傻傻分不清楚

最近在寫 Android 的 Database 程式的時候,發現點擊 ExpandableListView 的第一層要讓他展開的時候,總是會出現以下的 IllegalStateException:

E/AndroidRuntime(12706): FATAL EXCEPTION: main E/AndroidRuntime(12706): java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. E/AndroidRuntime(12706): at android.database.CursorWindow.nativeGetLong(Native Method) E/AndroidRuntime(12706): at android.database.CursorWindow.getLong(CursorWindow.java:515) E/AndroidRuntime(12706): at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75) E/AndroidRuntime(12706): at android.database.CursorWrapper.getLong(CursorWrapper.java:106) E/AndroidRuntime(12706): at android.widget.CursorTreeAdapter$MyCursorHelper.getId(CursorTreeAdapter.java:436) E/AndroidRuntime(12706): at android.widget.CursorTreeAdapter.getGroupId(CursorTreeAdapter.java:191) E/AndroidRuntime(12706): at android.widget.ExpandableListConnector.getItemId(ExpandableListConnector.java:421) E/AndroidRuntime(12706): at android.widget.AdapterView.getItemIdAtPosition(AdapterView.java:756) E/AndroidRuntime(12706): at android.widget.AdapterView.setSelectedPositionInt(AdapterView.java:1128) E/AndroidRuntime(12706): at android.widget.AbsListView.onTouchEvent(AbsListView.java:3147) E/AndroidRuntime(12706): at android.view.View.dispatchTouchEvent(View.java:5541) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1951) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1712) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) E/AndroidRuntime(12706): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) E/AndroidRuntime(12706): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1912) E/AndroidRuntime(12706): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1371) E/AndroidRuntime(12706): at android.app.Activity.dispatchTouchEvent(Activity.java:2364) E/AndroidRuntime(12706): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1860) E/AndroidRuntime(12706): at android.view.View.dispatchPointerEvent(View.java:5721) E/AndroidRuntime(12706): at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:2890) E/AndroidRuntime(12706): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2466) E/AndroidRuntime(12706): at android.view.ViewRootImpl.processInputEvents(ViewRootImpl.java:845) E/AndroidRuntime(12706): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2475) E/AndroidRuntime(12706): at android.os.Handler.dispatchMessage(Handler.java:99) E/AndroidRuntime(12706): at android.os.Looper.loop(Looper.java:137) E/AndroidRuntime(12706): at android.app.ActivityThread.main(ActivityThread.java:4424) E/AndroidRuntime(12706): at java.lang.reflect.Method.invokeNative(Native Method) E/AndroidRuntime(12706): at java.lang.reflect.Method.invoke(Method.java:511) E/AndroidRuntime(12706): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) E/AndroidRuntime(12706): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) E/AndroidRuntime(12706): at dalvik.system.NativeStart.main(Native Method)

他唯一比較算是「錯誤訊息」的是「Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.」這個,是表示說程式試圖存取某個 column,可是 query 中沒有這個欄位,所以會回傳 -1。於是乎,程式就這麼爆炸了。

可是... 他只告訴我「col -1」,沒告訴我他到底想查哪個欄位啊... = = 所以只好去追程式碼,發現主要是這個東西「android.widget.CursorTreeAdapter.getGroupId()」會試著抓「_id」這欄位。

SQLite 在 create table 的時候,會自動幫你建立叫做「_id」的欄位作為索引。但是如果你的 create table statement 中有包含某個 integer 型態的 primary key,他就會改用這個欄位來索引(就是不會再多建一個「_id』)了。

Android 的 Cursor 會拿這個欄位作為內部索引,會試圖存取它。當找不到這個欄位的時候,就會丟出 IllegalStateException。

可是呢,我很犯賤的在 create table 的時候用了 _ID 作為 primary key,於是即使 query 是「SELECT `_id` FROM `table_name`;」,他回傳的資料中還是會以 _ID 作為欄位名稱...

結論就是... create table 的時候得用「_id」,用「_Id」、「_iD」、「_ID」統統不行... XD~