擒猿記 Lv.3 冒險開始
Hank 站在華碩總部前,兩扇大門緩緩敞開,映入眼簾的是一名美麗標緻的女子,年齡約二十歲左右,明眸皓齒,臉龐清秀,Hank 看得一愣一愣的,剛畢業的他沒見過什麼大世面,這麼漂亮的女子也沒見過幾個,此時她優雅地走到 Hank 面前。
「這位俊朗的小哥,你就是 Hank 吧!」女子露出微笑。
「呃,我、我、我....」美女當前,Hank 竟一時語塞。
警衛從一旁探出頭來,噗哧一聲,彷彿這樣的新人見多了。
「嘻嘻,你不要緊張,我是這邊的助理 Stephine,所有新人都是由我來引導的。」Hank 眼前的女子說道。
Stephine 攤開一份文件,上頭印著 Hank 的履歷資料,她仔細檢視比對文件與眼前的小伙子,年齡二十四,名校畢業,身材中等偏瘦,Stephine 繞到 Hank 身後,伸手摸了摸 Hank 的臂膀、腰臀與大小腿,正要伸手往鼠蹊部摸去。
「唉呀,姑娘請妳放尊重點,人家我還是在室...」Hank 羞赧地趕緊閃身避開。
「嘻嘻,你不要激動,這只是新人的例行健康檢查,你身手不錯唷,怪不得前測導師給你的評價這麼高。」Stephine 在文件上的健檢攔打了幾個勾,然後優雅地走到 Hank 面前。
「你知道此行的目的,與接下來艱難的任務嗎?」Stephine 向前探頭,大溜溜的眼珠直盯著 Hank 的眼睛看。
Hank 神情轉為嚴肅,說道:「這是我一生的志向與勢必征服的目標,安卓大陸!」
Stephine 笑了,說道:「很好很好,心靈層面也很健全唷。」接著冷不防出手往 Hank 鼠蹊部抓去。
「啊啊啊!!!」被偷襲的 Hank 痛得在地上打滾,留下屈辱的淚水。
「嘻,但是該做的檢查還是要做的唷。」Stephine 拿出筆,在健檢攔的最後一個項目打了個勾。
隨後 Stephine 領著 Hank 進到總部裡的一間寬敞大廳,一台兩層樓高的主機佇立在大廳中央,刺耳的運轉聲不絕於耳,主機不斷發出紅綠燈光交織閃爍。
「這裡就是安卓大陸的入口囉!」Stephine 轉身對 Hank 說道,伸手遞給他一張識別證。
「幾經波折,終於讓我走到這一步了。」Hank 戰戰競競地接過識別證。
「安卓大陸裡的工程師們都以小隊制執行任務的,小心不要拖累隊友喔!」Stephine 貼心提醒。
「放心吧,我一定會凱旋歸來的。」Hank 走近主機,轉頭對 Stephine 一笑,接著識別證發出白光,不一會整個人便被吸入到主機裡,消失在 Stephine 面前。
Stephine 呆呆地望著眼前的主機,伸出右手,難以忘懷剛剛經歷的觸感。
「嘻嘻!難得遇到這麼有品質的新人,這下有好戲看囉。」Stephine 有點害羞的笑了。
此時剛被吸入主機的 Hank 只覺得正從高空往下墜落,在他還來不及叫出口之時,就碰的一聲摔落到地上,揚起一片塵土,他抬起頭看了看,四周一片花草樹木,彷彿來到一處原始森林。
「這裡就是安卓大陸阿!」Hank 翻了個跟斗爬起身。
離他不遠處一個尖銳的叫聲引起的他的注意,循聲望去,一隻貌似猿猴的生物與數對腳步聲正朝他奔跑而來。
(待續)
擒猿本舖
2015年8月8日 星期六
2015年7月19日 星期日
[擒猿筆記篇] Android 在 Activity 中實作 Up Navigation
你一定看過以下最左邊這個 Up Navigation 的箭頭:
因為 Android Designer 認為任何非 main entrance 的 activity 都必須加入這個箭頭,讓 user 可以方便回到上一層,完全忽略大部分的 Android devices 有 back key,幹你娘自以為是 iphone 。
Up Navigation 的實作方式如下:
1. 在 Manifest 中 activity 的欄位添加以下屬性:
2. 在 onCreate() 中加入以下程式片斷後,在 Action bar 上就會出現一個可按的箭頭了:
3. 還需要實作 onOptionsItemSelected() 讓箭頭按下去之後會有反應:
4. 如果該 Activty 是可接受外部 intent 呼叫的,則可透過以下方式實作 Up Navigation,使其再點選箭頭後回到外部程式:
refs: http://developer.android.com/training/implementing-navigation/ancestral.html
因為 Android Designer 認為任何非 main entrance 的 activity 都必須加入這個箭頭,讓 user 可以方便回到上一層,完全忽略大部分的 Android devices 有 back key,
Up Navigation 的實作方式如下:
1. 在 Manifest 中 activity 的欄位添加以下屬性:
<!-- Parent activity to support 4.1 and higher --> android:parentActivityName="com.example.myfirstapp.MainActivity" <!-- Parent activity meta-data to support 4.0 and lower --> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.example.myfirstapp.MainActivity" />
2. 在 onCreate() 中加入以下程式片斷後,在 Action bar 上就會出現一個可按的箭頭了:
@Override public void onCreate(Bundle savedInstanceState) { ... // 隱藏 Logo 只顯示箭頭 getActionBar().setDisplayHomeAsUpEnabled(true); // 顯示 Logo 也顯示箭頭 getActionBar().setLogo(R.drawable.myDrawable); getActionBar().setDisplayUseLogoEnabled(true); getActionBar().setDisplayShowHomeEnabled(true); }
3. 還需要實作 onOptionsItemSelected() 讓箭頭按下去之後會有反應:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
其中 NavUtils 是 android support library v4 的 class,使用前必需載入 android-support-v4.jar 這個外部 jar 檔。4. 如果該 Activty 是可接受外部 intent 呼叫的,則可透過以下方式實作 Up Navigation,使其再點選箭頭後回到外部程式:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
// This activity is NOT part of this app's task, so create a new task
// when navigating up, with a synthesized back stack.
TaskStackBuilder.create(this)
// Add all of this activity's parents to the back stack
.addNextIntentWithParentStack(upIntent)
// Navigate up to the closest parent
.startActivities();
} else {
// This activity is part of this app's task, so simply
// navigate up to the logical parent activity.
NavUtils.navigateUpTo(this, upIntent);
}
return true;
}
return super.onOptionsItemSelected(item);
}
注意,使用此方法時必須在 Manifest 中宣告 android:parentActivityName 和其對應的 <meata-data> 屬性。refs: http://developer.android.com/training/implementing-navigation/ancestral.html
2015年7月16日 星期四
[擒猿筆記篇] Android切換全螢幕與非全螢幕的方法
找了好幾個方法終於有一個能用的,特此紀錄一下。
切換為全螢幕
切回非全螢幕
以上是把 status bar 和 navigation bar 隱藏,如果連 title bar 都不要就要在 xml 檔中設置:
或是在 onCreate() 中加入:
補個幹你娘ㄎㄎ
切換為全螢幕
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
切回非全螢幕
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
以上是把 status bar 和 navigation bar 隱藏,如果連 title bar 都不要就要在 xml 檔中設置:
<item name="android:windowNoTitle">true</item>
或是在 onCreate() 中加入:
requestWindowFeature(Window.FEATURE_NO_TITLE);
補個幹你娘ㄎㄎ
2015年7月8日 星期三
[擒猿基本功] Android 利用 Content Provider 隔山打牛
安卓大陸裡處處是陷阱,必須集合眾人的力量才能擊敗邪惡 Monkey,而 Content Provider 就是一套能夠借力使力,隔山打牛的強大心法,不可不練,非練不可。
翻開擒猿寶典,Content Provider 提供了一個中央控管的資料庫,可以讓其他的 app 可以購過 API 方便存取本身的資料,以下介紹 Content Provider 的原理與實作:
Content Provider 將資料以 Table 的方式儲存,其中一個 row 表示一筆資料,每個 row 會有多個 column,Table 內容如下:
鏡頭一轉,來到安卓大陸的戰場上,火爆猿王肆虐,打得眾人潰不成軍,一位武功強大的老前輩挺身而出,利用獅吼功向眾人發出訊息:幹你娘!大家快來用我的 Content Provider 打王!
這時候身為擒猿手的你,該怎麼提取前輩的內力,借力對邪惡猿王打出致命一擊呢?噎,這時候就要透過 ContentResolver 這個物件,透過他就可以對前輩的 Content Provider 進行 CRUD 操作 (C: Create、R: Retrieve、U: Update、D: Delete)。
Reference: http://developer.android.com/guide/topics/providers/content-provider-basics.html
翻開擒猿寶典,Content Provider 提供了一個中央控管的資料庫,可以讓其他的 app 可以購過 API 方便存取本身的資料,以下介紹 Content Provider 的原理與實作:
Content Provider 將資料以 Table 的方式儲存,其中一個 row 表示一筆資料,每個 row 會有多個 column,Table 內容如下:
word | app_id | frequency | locale | _ID |
---|---|---|---|---|
mapreduce | user1 | 100 | en_US | 1 |
precompiler | user14 | 200 | fr_FR | 2 |
applet | user2 | 225 | fr_CA | 3 |
const | user1 | 255 | pt_BR | 4 |
int | user5 | 100 | en_UK | 5 |
鏡頭一轉,來到安卓大陸的戰場上,火爆猿王肆虐,打得眾人潰不成軍,一位武功強大的老前輩挺身而出,利用獅吼功向眾人發出訊息:幹你娘!大家快來用我的 Content Provider 打王!
這時候身為擒猿手的你,該怎麼提取前輩的內力,借力對邪惡猿王打出致命一擊呢?噎,這時候就要透過 ContentResolver 這個物件,透過他就可以對前輩的 Content Provider 進行 CRUD 操作 (C: Create、R: Retrieve、U: Update、D: Delete)。
Query Data from Content Provider
欲取得 Content Provider 分享資料的 app 必須在 manifest 中宣告 permission,而欲存取資料的 app 則需在 manifest 中去 use 這個 permission。在程式中可以利用以下寫法得到指定 Content Provider 的 Table 中的資料:// Queries the user dictionary and returns results
Cursor mCursor = getContentResolver().query(
CONTENT_URI, // The content URI of the words table
mProjection, // The columns to return for each row
mSelectionClause // Selection criteria
mSelectionArgs, // Selection criteria
mSortOrder); // The sort order for the returned rows
- CONTENT_URI 以 URI 的形式直接指向 Content Provider 的 Table,形如 content://user_dictionary/words,其中 user_diction 為 Content Provider authority,而 words 為 Table name。
- mProjecttion 定義取出的資料要有那些欄位,寫法如下:
String[] mProjection = { "_ID", "word", "locale" };
- mSelectionClause 可定義的篩選資料的條件,寫法如下:
String mSelectionClause = "frequency = 200";
但這樣的寫法非常危險,因為他直接對應到 SQL 語言,譬如 user 可能輸入 "nothing; DROP TABLE *;" ,導致 Table 被清空。 - 更好的寫法是 mSelectionArgs 與 mSelectionClause 搭配使用,能避免上述的惡意破壞情形,寫法如下,注意那個問號很玄:
// Constructs a selection clause with a replaceable parameter String mSelectionClause = "frequency = ?"; // Defines an array to contain the selection arguments String[] selectionArgs = {""}; // Sets the selection argument to the user's input selectionArgs[0] = mUserInput;
- 最後,可以利用 mSortOrder 去控制取回資料的排序方式,寫法如下:
mSortOrder = "ORDER BY _ID";
Getting data from query results
使用上述的 ContentResolver.query() 會傳回一個 Cursor 元件,以下為從 Cursor 中取得我們要的資料的方法:
// Determine the column index of the column named "word" int index = mCursor.getColumnIndex("world"); if (mCursor != null) { while (mCursor.moveToNext()) { // Gets the value from the column. newWord = mCursor.getString(index); Log.d("Lotus", newWord); } }
此外可以直接將 Cursor 與 ListView 做連結,如以下寫法:
// Creates a new SimpleCursorAdapter mCursorAdapter = new SimpleCursorAdapter( getApplicationContext(), // The application's Context object R.layout.wordlistrow, // A layout in XML for one row in the ListView mCursor, // The result from the query new Steing[] {"word" "locale"}, // A string array of column names in the cursor new int[] { R.id.dictWord, R.id.locale}, // view IDs in the row layout 0); // Flags (usually none are needed) // Sets the adapter for the ListView mListview.setAdapter(mCursorAdapter);
Inserting data
利用 ContentResolver.insert() 可達成插入一筆新資料至 Content Provider 的動作,寫法如下 :
// Defines a new Uri object that receives the result of the insertion Uri mNewUri; // Defines an object to contain the new values to insert ContentValues mNewValues = new ContentValues(); /* * Sets the values of each column and inserts the word. The arguments to the "put" * method are "column name" and "value" */ mNewValues.put("app_id", "example.user"); mNewValues.put("local", "en_US"); mNewValues.put("word", "insert"); mNewValues.put("frequency", "100"); mNewUri = getContentResolver().insert( CONTENT_URI, // the user dictionary content URI mNewValues // the values to insert );
Updating data
利用 ContentResolver.update() 可達成對 Content Provider 的資料做更新動作,寫法如下 :
// Defines an object to contain the updated values
ContentValues mUpdateValues = new ContentValues();
// Defines selection criteria for the rows you want to update
String mSelectionClause = "locale" + " LIKE ?";
String[] mSelectionArgs = {"en_%"};
// Defines a variable to contain the number of updated rows
int mRowsUpdated = 0;
/*
* Sets the updated value and updates the selected words.
*/
mUpdateValues.putNull("local");
mRowsUpdated = getContentResolver().update(
CONTENT_URI, // the user dictionary content URI
mUpdateValues // the columns to update
mSelectionClause // the column to select on
mSelectionArgs // the value to compare to
);
Deleting data
利用 ContentResolver.delete() 可達成對 Content Provider 的資料做刪除動作,寫法如下 :
// Defines selection criteria for the rows you want to delete
String mSelectionClause = "app_id" + " LIKE ?";
String[] mSelectionArgs = {"user"};
// Defines a variable to contain the number of rows deleted
int mRowsDeleted = 0;
// Deletes the words that match the selection criteria
mRowsDeleted = getContentResolver().delete(
CONTENT_URI, // the user dictionary content URI
mSelectionClause // the column to select on
mSelectionArgs // the value to compare to
);
Reference: http://developer.android.com/guide/topics/providers/content-provider-basics.html
2015年7月5日 星期日
[擒猿基本功] Android app 支援多重螢幕
這個世界存在著許多各式各樣大大小小、長長扁扁、寬寬窄窄的智慧手機,它們佔據了現代人的生活模式、行為思考與社交聯繫,每台手機看似獨立運作,但其實它們內部都連結到了同一個虛擬世界,這個虛擬世界,我們稱之為安卓大陸。
Supporting Multiple Screens
如果還是不知道,請用密招,連機台下以下指令:
是的,但今天沒有要寫擒猿記,而是要來寫 Android App 要如何支援多重螢幕,你一定覺得幹你娘很失望,沒關係,不要哭,堅強點。
Supporting Multiple Screens
根據 Android 官方文件,Android 定義了:
- Screen size: 根據螢幕對角線長度定義 4 種 Size:
- small
- normal
- large
- xlarge
- Screen density: 實體區域內的 dpi (dots per inch) 可想成是顯示品質,定義了以下 6 種:
- ldpi (~120dpi)
- mdpi (~160dpi)
- hdpi (~240dpi)
- xhdpi (~320dpi)
- xxhdpi (~480dpi)
- xxxhdpi (~640dpi)
Resolution 代表一個螢幕上實際的 pixel 點數,通常 app 不直接使用這個值,而是改用 dp (density-independent pixel),dp 為基於 160dpi 的螢幕 (medium 品質) 計算得到的 pixel 點數,通常 app 會利用這個值來定義 layout 長度,在 run-time 時 Android 系統則根據這個值與實際螢幕大小來做放大的動作,dp 與 pixel 轉換的公式如下:
px = dp * (dpi / 160)
舉例來說,在一個 240dpi 的螢幕上,layout中 1 dp 的長度表示在螢幕是實際顯示為 1.5 pixel 的長度。
支援多重螢幕的最高境就就是要達成 Density Independence,就是 user 在任何大小不同的螢幕上跑你的 app 看起來都一樣的。欲達成 Density Independence,定義 layout 長度時就不該使用 pixel 為單位,應該改用 dp,如此 Android 系統才能幫我們放大成最適合的大小,然而,系統放大的結果可能會導致 bitmap 圖片過於模糊,因此最好再根據不同解析度螢幕提供不同的圖片。
官方文件推薦以下幾種方式,能讓 Android 系統更有效處理多重螢幕的支援:
- 在 manifest 中指定 app 支援的 screen size
- 在 manifest 利用 <supports-screens> 宣告可支援的 screen size,如此可以確保有在支援範圍內的裝置才能透過 Google Play 下載到這支 app。
- 為不同的 screen size 製作不同的 layout
- 若需要對不同的螢幕的顯示方式做一些微調,則建議為其各自製作不同的 layout。
- 不同的 layout 放置在不同的資料夾內,譬如 layout-xlarge/ 內放的就是給 extra-large螢幕顯示用的 layout,Android 系統根據 configuration qualifiers 的定義動態撈出需要的 layout 檔。
- Android 3.2 (ApI Level 13) 之後應該使用 sw<N>dp 的形式來做更進階的分類,譬如放在 layout-sw600dp/ 資料夾內的 layout 檔案是給螢幕寬度至少 600dp 的裝置所使用。
- 為不同的 screen density 製作不同的 bitmap drawable
- Android 系統會把 bitmap drawable (.png, .jpg, .gif, .9.png) 做放大的動作,若只放一種解析度的圖,則放大後可能會有變模糊的情況,因此最好為同一張圖製作多種解析度的副本。
- Android 定義了 configuration qualifiers 讓不同解析度的圖可以放在不同資料夾下,譬如 drawable-hdpi/ 內放的圖就是給 high density 的裝置所使用。
如何使用 configuration qualifiers
Configuration qualifier 是一個字串可加在 resource 資料夾的名稱後方,協助 Android 系統分辨哪些 resource 是適合抓取來使用的。
在 Project 的 res/ 下依據不同解析度建立不同資料夾,然後把這些解析度的 layout 或 drawable 放入到對應的資料夾下,檔案名稱必須要跟 default 資料夾下放的一樣。
資料夾命名的格式如下:
<resources_name>-<qualifier>
resources_name 可以是 layout、drawable 等等 Android 的 standard resource
qulifiler 用來區分不同解析度的螢幕,填入值可以如下表格所定義:
Screen characteristic
|
Qualifier
|
Description
|
Size
|
small
|
Resources for small size
screens.
|
normal
|
Resources for normal size
screens. (This is the baseline size.)
|
|
large
|
Resources for large size
screens.
|
|
xlarge
|
Resources for extra-large size
screens.
|
|
Density
|
ldpi
|
Resources for low-density
(ldpi) screens (~120dpi).
|
mdpi
|
Resources for
medium-density (mdpi) screens (~160dpi). (This is the baseline
density.)
|
|
hdpi
|
Resources for high-density
(hdpi) screens (~240dpi).
|
|
xhdpi
|
Resources for
extra-high-density (xhdpi) screens (~320dpi).
|
|
xxhdpi
|
Resources for
extra-extra-high-density (xxhdpi) screens (~480dpi).
|
|
xxxhdpi
|
Resources for
extra-extra-extra-high-density (xxxhdpi) uses (~640dpi). Use this for
the launcher icon only, see note above.
|
|
nodpi
|
Resources for all
densities. These are density-independent resources. The system does not scale resources tagged with this
qualifier, regardless of the current screen's density.
|
|
tvdpi
|
Resources for screens
somewhere between mdpi and hdpi; approximately 213dpi.
|
|
Orientation
|
land
|
Resources for screens in
the landscape orientation (wide aspect ratio).
|
port
|
Resources for screens in
the portrait orientation (tall aspect ratio).
|
|
Aspect ratio
|
long
|
Resources for screens that
have a significantly taller or wider aspect ratio (when in portrait or
landscape orientation, respectively) than the baseline screen configuration.
|
notlong
|
Resources for use screens
that have an aspect ratio that is similar to the baseline screen
configuration.
|
Android 3.2 之後擴充了qulifiler 參數的使用,可以更詳細的利用 dp 還制定符合裝置的規格,避免遇到如 5" 和 7" 螢幕都是 large 的 screen size,無法為其制定不同的 layout 或 drawable,其新增的 qulifiler 使用方示如下:
Screen configuration
|
Qualifier values
|
Description
|
smallestWidth
|
sw<N>dp
Examples: sw600dp sw720dp |
The fundamental size of a
screen, as indicated by the shortest dimension
of the available screen area. Specifically, the device's smallestWidth
is the shortest of the screen's available height and width (you may also
think of it as the "smallest possible width" for the screen). You can use this qualifier to ensure that, regardless of
the screen's current orientation, your application's has at least <N> dps of width available for its UI.
|
Available screen width
|
w<N>dp
Examples: w720dp w1024dp |
Specifies a
minimum available width in dp units at which the resources should be used—defined by the <N> value. The system's corresponding value for
the width changes when the screen's orientation switches between landscape
and portrait to reflect the current actual width that's available for your
UI.
This is often
useful to determine whether to use a multi-pane layout, because even on a tablet
device, you often won't want the same multi-pane layout for portrait
orientation as you do for landscape. Thus, you can use this to specify the
minimum width required for the layout, instead of using both the screen size
and orientation qualifiers together.
|
Available screen height
|
h<N>dp
Examples: h720dp h1024dp etc. |
Specifies a
minimum screen height in dp units at which the resources should be used—defined by the <N> value. The system's corresponding value for
the height changes when the screen's orientation switches between landscape
and portrait to reflect the current actual height that's available for your
UI.
|
下列幾種歸類出來的qulifiler 可以快速對照使用:
- 320dp: a typical phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).
- 480dp: a tweener tablet like the Streak (480x800 mdpi).
- 600dp: a 7” tablet (600x1024 mdpi).
- 720dp: a 10” tablet (720x1280 mdpi, 800x1280 mdpi, etc).
如果還是不知道,請用密招,連機台下以下指令:
dumpsys window | grep dp
可以看到如下列結果:mCurConfiguration={1.0 ?mcc?mnc en_US ldltr sw400dp w682dp h368dp 240dpi nrml long land finger -keyb/v/h -nav/h skin=/system/framework/theme-res-garmin.apk s.5}
因此針對該機台的 resources 應該放在 sw400dp 的 folder 底下。
Android 系統會預設去抓取最符合當前裝置的 layout 和 drawable,若找不到符合該定義的 resource 時才會去抓取 default 的 resource (不指定 configuration qualifiers 的 資料夾),或是利用一些邏輯判斷去抓取 "best matching" 的 resource。但當 Android 系統所找到的 resource 都比目前系統的定義要來的大時,Android 系統會拒絕使用這些 resource 而回報為 crash。
製作 Alternative drawables
在為不同大小螢幕製作各自的 drawable 時,必須遵守 3:4:6:8:12:16 scaling ratio 的原則,這是口訣,也是心法,譬如說有一張圖在 medium-density 的螢幕上為 48x48 pixels,則該張圖片的 alternative drawables 大小如下:
- 36x36 (0.75x) for low-density
- 48x48 (1.0x baseline) for medium-density
- 72x72 (1.5x) for high-density
- 96x96 (2.0x) for extra-high-density
- 144x144 (3.0x) for extra-extra-high-density
- 192x192 (4.0x) for extra-extra-extra-high-density (for launcher icon only)
2015年7月3日 星期五
Kill Monkey Lv.2 The Pretest of Monkey Killer
Kill Monkey Lv.2 The Pretest of Monkey Killer
This morning the sun rises as usual, the Freshwater Street in Tamsui is been dyed red, Hank is sitting on the bank with an exciting heart, an admission notice of ASUS is holding on his hand, which allows him to login to the Android mainland. Today is his debut at ASUS, the bright light shining from his eyes, like most rockets of workplace, this time, embracing their dreams, after years of hard studies and finally can make some contributions to this world.
However, the young man born in Yunlin, has a hard time in his childhood. When he was a kid, he had to study as well as to do farm work. First time he gave the love letter to a girl he loved in the junior high school, next day he picked up the letter by himself at the corner of playground. Then he loves another girl in the senior high school, but she was taken away by a senior boy right when they entered the university. Since that day, Hank focused on his study, and finally entered a top grated school, but his face always looks older than his classmates.
'My life is so hard, I have nothing to lost.' thought Hank.
Now, one hour before working, Hank decide to practice Kongfu on the bank, a Kongfu named JAVA which he have practiced for two years, he murmured:
Falling plum inherits fast snow.
Polymorphism like the heart of woman.
Look back where once compiled.
Stay calm and encapsulate myself.
An old man laughs out after hearing what he said.
Hank glimpses the old man, he turns around, his eyes like hawks, with thick eyebrows, seems very clever.
'The Kongfu you just practiced was good, but I think you didn't catch the point of JAVA.' said old man.
Hank thinks this man easily break his Kongfu, should not a general people.
'Thanks for your pointing, I'm hoping for more directions.' said Hank.
'Ho ho ho, so who is your shifu? What Kongfu are you learned?' asked the old man.
'My Shifu is Master Null of NTU, my major is fast Tai-Chi.' said Hank.
'Ho ho ho, I know Tai-Chi, too, let's practice together, common, hit me.' said the old man.
'OK, since you said that, I'm coming.' Hank bowed, then stamped his foot and disappeared in the air.
'Oh! so fast, fast is the basic of all kind of Kongfu, your skill is very good.' praised the old man, then he closed his eyes, feeling the fluctuating of the air.
Suddenly, the old man strikes a spout of air spinning on his left-up side, a man is thrown out and heavily falls onto the ground, he is Hank.
'Hey man, your skill is good enough to be a Monkey killer, but if you want to be the best one, need more practice. Ho ho ho, welcome to join ASUS.' said the old man, he walked to Hank and gives him a card.
'Keep in mind, you can't be the best if keep closing your heart.' said the old man before he leaves.
Hank crawls and sits up, looking the card, a big Zen logo was printed on it, he scratches his head.
'So, that is a pretest for rockets? the man of human resources didn't tell me.' thought Hank.
A big building standing on the Guandu plain, a huge logo of ASUS hanging on its top, a magnificent entrance set in front of the building, a guard is watching, here is the headquarter of ASUS.
Hank walks toward, knocked the entrance twice, a big and tall guard comes out from the side door, stops Hank by his knife.
'Who are you, what you want?' asked the guard seriously.
'I'm Hank, come for kill Monkey.' answered Hank loudly.
The guard comes back to side door, soon, the entrance is opened, a woman with sweetly smile shows up.
'I'm waiting for you so long, Hank.'
(To be continued.)
This morning the sun rises as usual, the Freshwater Street in Tamsui is been dyed red, Hank is sitting on the bank with an exciting heart, an admission notice of ASUS is holding on his hand, which allows him to login to the Android mainland. Today is his debut at ASUS, the bright light shining from his eyes, like most rockets of workplace, this time, embracing their dreams, after years of hard studies and finally can make some contributions to this world.
However, the young man born in Yunlin, has a hard time in his childhood. When he was a kid, he had to study as well as to do farm work. First time he gave the love letter to a girl he loved in the junior high school, next day he picked up the letter by himself at the corner of playground. Then he loves another girl in the senior high school, but she was taken away by a senior boy right when they entered the university. Since that day, Hank focused on his study, and finally entered a top grated school, but his face always looks older than his classmates.
'My life is so hard, I have nothing to lost.' thought Hank.
Now, one hour before working, Hank decide to practice Kongfu on the bank, a Kongfu named JAVA which he have practiced for two years, he murmured:
Falling plum inherits fast snow.
Polymorphism like the heart of woman.
Look back where once compiled.
Stay calm and encapsulate myself.
An old man laughs out after hearing what he said.
Hank glimpses the old man, he turns around, his eyes like hawks, with thick eyebrows, seems very clever.
'The Kongfu you just practiced was good, but I think you didn't catch the point of JAVA.' said old man.
Hank thinks this man easily break his Kongfu, should not a general people.
'Thanks for your pointing, I'm hoping for more directions.' said Hank.
'Ho ho ho, so who is your shifu? What Kongfu are you learned?' asked the old man.
'My Shifu is Master Null of NTU, my major is fast Tai-Chi.' said Hank.
'Ho ho ho, I know Tai-Chi, too, let's practice together, common, hit me.' said the old man.
'OK, since you said that, I'm coming.' Hank bowed, then stamped his foot and disappeared in the air.
'Oh! so fast, fast is the basic of all kind of Kongfu, your skill is very good.' praised the old man, then he closed his eyes, feeling the fluctuating of the air.
Suddenly, the old man strikes a spout of air spinning on his left-up side, a man is thrown out and heavily falls onto the ground, he is Hank.
'Hey man, your skill is good enough to be a Monkey killer, but if you want to be the best one, need more practice. Ho ho ho, welcome to join ASUS.' said the old man, he walked to Hank and gives him a card.
'Keep in mind, you can't be the best if keep closing your heart.' said the old man before he leaves.
Hank crawls and sits up, looking the card, a big Zen logo was printed on it, he scratches his head.
'So, that is a pretest for rockets? the man of human resources didn't tell me.' thought Hank.
A big building standing on the Guandu plain, a huge logo of ASUS hanging on its top, a magnificent entrance set in front of the building, a guard is watching, here is the headquarter of ASUS.
Hank walks toward, knocked the entrance twice, a big and tall guard comes out from the side door, stops Hank by his knife.
'Who are you, what you want?' asked the guard seriously.
'I'm Hank, come for kill Monkey.' answered Hank loudly.
The guard comes back to side door, soon, the entrance is opened, a woman with sweetly smile shows up.
'I'm waiting for you so long, Hank.'
(To be continued.)
2015年7月2日 星期四
[擒猿心法篇] Android 中更新 UI 的方法
Android 中只有 UI Thread 才能更新 UI,否則會發生 Exception。
幹你娘,好煩阿!
以下幾種方法可以協助達成更新 UI 的方法,紀錄一下:
使用方式如下:
使用方式如下:
透過 Handler 可以 發送 Message 請 UI Thread 處理更新 UI。
使用方式如下:
AsyncTask 可以在背景做運算,並把結果傳給 UI thread 進行更新,通會常用在需要處理大量運算等狀況下。
使用方式如下:
reference: http://gameorprogram.blogspot.tw/2011/12/android-ui.html
幹你娘,好煩阿!
以下幾種方法可以協助達成更新 UI 的方法,紀錄一下:
1. 呼叫 runOnUiThread
http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)
final void
|
runOnUiThread(Runnable action)
Runs the specified action
on the UI thread.
|
runOnUiThread.(new Runnable() {
public void run() {
myTextView.setText("update");
}
});
2. 呼叫 View 本身的 post 方法
http://developer.android.com/reference/android/view/View.html#post(java.lang.Runnable)
boolean
|
Causes the Runnable to be
added to the message queue.
|
myTextView.post(new Runnable() { public void run() { myTextView.setText("update") } });
3. 使用 Handler
http://developer.android.com/reference/android/os/Handler.html透過 Handler 可以 發送 Message 請 UI Thread 處理更新 UI。
使用方式如下:
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
myTextView.setText("update");
super.handleMessage(msg);
}
};
Message msg = new Message();
mHandler.sendMessage(msg);
4. 使用 AsyncTask
http://developer.android.com/reference/android/os/AsyncTask.htmlAsyncTask 可以在背景做運算,並把結果傳給 UI thread 進行更新,通會常用在需要處理大量運算等狀況下。
使用方式如下:
private class LoadImage extends AsyncTask {
protected String doInBackground(String... url) {
return loadImageFormNetwork(url[0]);
}
protected void onPostExecute(String result) {
myImage.setImage(result);
}
}
new loadImageTask().execute("www.xxx.com/image.png");
reference: http://gameorprogram.blogspot.tw/2011/12/android-ui.html
訂閱:
文章 (Atom)