Youtube連結在此:
最近聽到最好聽的歌曲,林檎真的好迷人,雖然英文發音有點不標準,
th開頭都會變成s的音...花了大約快兩小時還是無法完全確定整首都對,
因為網路上目前沒有比較完整的"順眼"版本,於是就決定來試試看了。
在這過程中,我綜合參考了以下網址,對於翻譯進展幫助很大:
1.日文版歌詞
2.百度貼吧
3.豆瓣
若有人有更好的意見也請不吝告知!~
==============================
The cover once was found,
let me return
I'm lost in my own crowd
I ask and beg you to
turn me around
I'm calling god on you.
No vision comes to me
but I'm alone
as hard as I reach
And you know I'll never throw
my body down
again before you're thrown
Come save the night
Come down to me
And keep your faith in a while
I'll take my hands and cast a spell
On darkness spread
On time like a dream
Just show your face I wonder mine
I'll take you in my arms alive
So seek and come to me again.
I have no hope at all
Not even one
Tear faded back and fall
and if everything I think
dim after dark
It would not change a thing
A broken glass
I'll say hello,
Won't you reveal all you know
I'll take my heart and hug you tight
And spread the light on time for both
You're sinking into my own mind
The world is howling so wild
I'll keep you warm with me again
I'll take my hands and cast a spell
On darkness spread
On time like a dream
Just show your face I wonder mine
I'll take you in my arms alive
So seek and come to me again.
=================================
真的好好聽喔>_<
2015年2月25日 星期三
2015年2月14日 星期六
(Android Training系列)用Fragment來建立動態UI(上)
話說從頭
動態(Dynamic)網頁或是APP目前是一股潮流,帶著使用者前往更加自由與客製化的未來前進。在這股潮流之中,我想要為大家介紹一個Android為大家帶來的類別,它叫做Fragment(片段)。如果你想要創造一個動態且多層的介面,用Fragment Class就對啦~(至少目前我只知道它QQ)Fragment就像是Activity裡面的便利貼一樣,或者我們也可以把一個Activity加上許多的Fragments,讓我們畫面有拼貼的效果。
這些Fragments都各自有各自的佈局(layout)和生命週期(life cycle),因此我們也可以將之視為Activity中之模組化的子Activity區塊。
創造Fragment
一個完整的Fragment除了擁有自己的生命周期之外,也能偵聽自己的傳入事件,也可以像子Activity一般可以讓你在母Activity運行時添加或移除,也可以重複地用在許多不同的Activities中。接下來的說明會教大家如何用Android內建的Support Library來建立最低可以相容於Android 1.6版的Fragment。在開始之前,必須先確定電腦裡有安裝Support Library的SDK(可以去SDK管理員確認)。
創造Fragment Class
步驟說明:
1.建立一個繼承(extend)Fragment類別的Class,接下來與建立Activity相同,可以覆寫(Override)其生命週期方法(onStop(), onResume()..等)以建立我們的程式邏輯。
2.與Activity不一樣的地方是,我們用onCreateView()來定義Fragment的佈局。事實上,這是讓一個fragment運作唯一需要的callback函數。其長相其實跟建立功能表選單Option Menu幾乎一致,都需要Inflater。(關於callback函數可以看這裡)
import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.ViewGroup; public class ArticleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.article_view, container, false); } }以上是使Fragment運行的必要callback方法。當我們有其他需要時,再去實做其他的生命週期方法就行了。關於更多關於Fragment的生命週期及callback方法:Fragments developer's guide.
用XML為Activity增加Fragment
雖然fragments是可重複使用的模組化UI元件,但每一個屬於Fragment Class的instance都必須要與其母類別FragmentActivity相關聯(註:在API Level 11以後我們可以直接繼承Activity即可,但這樣一來就可能會失去Level 11以下的相容性)。我們可以在佈局xml檔中完成這個關聯。
以下是用佈局檔在activity中產生兩個fragments的例子,請讀者留意螢幕尺寸修飾詞為-large。黑字是我認為可以稍加注意的地方。
路徑:res/layout-large/news_articles.xml
路徑:res/layout-large/news_articles.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <fragment android:name="com.example.android.fragments.HeadlinesFragment" android:id="@+id/headlines_fragment" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.android.fragments.ArticleFragment" android:id="@+id/article_fragment" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>Tip:如果你想要支援不同螢幕尺寸,請讀Supporting Different Screen Sizes。
(其實也只是多弄幾個不同的layout .xml讓系統自己判斷而已)
再把剛剛的news_article.xml定義的layout套用至activity中:
到此即大功告成,各位可以自己試試(按這裡可以下載Sample code,下載完成後解壓縮,打開Android Studio-->Import Project,選剛剛解壓縮後產生之資料夾)。
再把剛剛的news_article.xml定義的layout套用至activity中:
import android.os.Bundle; import android.support.v4.app.FragmentActivity; public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.news_articles); } }留意如果你是用 v7 appcompat library版本的Support Library,將會extends ActionBarActivity,一個 FragmentActivity 的子類別。想知道更多請看Adding the Action Bar。
到此即大功告成,各位可以自己試試(按這裡可以下載Sample code,下載完成後解壓縮,打開Android Studio-->Import Project,選剛剛解壓縮後產生之資料夾)。
注意:如果用以上介紹的方法在Activity中添加fragment,將無法在運行時移除該fragment。因為我們是直接在MainActivitiy中套用R.layout.news_articles。如果你想要讓fragments能夠來去自如,我們必須在Activity啟動後再添加,此方法將會在下篇文章中介紹。
2015年2月13日 星期五
使用批次檔(.bat)在Windows中為資料夾加密
好久不見了,就在這個內湖南港區要為全民做一件大事的同時,沒有投票權的高雄市民我今天要來跟大家介紹一個還算實用的小招式,是前幾天我在找相關資料時發現的(就別問我為啥要找了XD),這個招式的IDEA是從使用者有不想讓任何人看到的檔案時可以透過這招來實現。網路上中文的內容大多是圍繞在使用一些諸如金剛鎖啦、secretfolder之類的硬方法(就是雖然可能比較萬無一失,但可能要承擔該程式盜取個資風險,以及方式不夠快(要先下載一個你喜歡的程式,然後再安裝後才能用)的心理負擔。
我甚至還看到神奇的隱藏檔案招式,看完我忍不住笑了。
不過當我看到下一支影片介紹之後,立馬決定採用。這方法是直接讓使用者用批次檔(batch file)的方式在DOS中執行一些指令以鎖定並隱藏其見光死檔案。首先要針對批次檔來簡單介紹一下:
回到主題,這次我們要做的是幫資料夾加密。雖然windows本身有提供加密的功能,但那不是用密碼加密而是用憑證檔案加密,對於普羅大眾來講(其實是對我自己)有那麼一點距離,因此今天要來分享的是如何用密碼來加密。
看得懂影片+英文的人可以直接點這裡照原創作者Hasan Zahidi的指示做,看不懂的也別害怕,教你兩分鐘內解決。首先你得先複製下面的程式碼:
==================不要複製這裡=========================
cls
@echo off
title Folder Locker
IF EXIST "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}" GOTO UNLOCK
IF NOT EXIST Locker GOTO MDLOCKER
echo Folder Created.
:CONFIRM
echo Are you sure you want to lock the folder? (Y/N)
set/p "cho="
IF %cho%==Y GOTO LOCK
IF %cho%==y GOTO LOCK
IF %cho%==N GOTO END
IF %cho%==n GOTO END
echo Invalid Choice.
GOTO CONFIRM
:LOCK
ren Locker "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}"
attrib +h +s "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}"
echo Folder Locked.
GOTO END
:UNLOCK
echo Enter password to unlock the Folder :
set/p "pass="
IF NOT %pass% == YourPassword GOTO FAIL
attrib -h -s "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}"
ren "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}" LOCK
echo Folder Unlocked Successfully.
GOTO END
:FAIL
echo Invalid Password!
GOTO END
:MDLOCKER
md Locker
echo Folder created.
GOTO END
:END
PAUSE
=====================不要複製這裡==========================
好了,接下來新增一個txt檔案(就是打開一個記事本的意思)並貼上程式碼。至此已經25%完成
接下來你要做的就是把上面藍色的YourPassword給改成你自己的密碼(例如123456789之類的)
記得不要讓密碼和前面的等號和後面的GOTO的G連在一起喔!
然後在記事本的選單列上,點"檔案"-->"另存新檔",會跳出一個視窗,看你要存在哪裡和取甚麼名稱都可以,存完之後,為檔案重新命名,在原本檔名後面加上.bat把檔案轉換為批次檔(例如原本檔名是123.txt或123,就改為123.bat)。這時候你就可以發現圖示改成一個有齒輪的,這代表你成功了!
接著點一下你剛創造的bat檔案,再按任意鍵關閉黑色視窗,就會在目錄中發現新的Locker資料夾,把你要加密的檔案丟進去, 再開一次剛剛的bat檔後會問你要不要加密,輸入Y(大小寫皆可),這時候你的資料就和Locker資料夾一起消失了!!
不過事實上檔案還是在那邊,這點可以從容量看的出來。到這裡你已經完成任務,往後需要存取資料,只需要再點一下bat檔,輸入你的密碼。只是有幾點需要注意的事情:
我甚至還看到神奇的隱藏檔案招式,看完我忍不住笑了。
不過當我看到下一支影片介紹之後,立馬決定採用。這方法是直接讓使用者用批次檔(batch file)的方式在DOS中執行一些指令以鎖定並隱藏其
- 維基百科表示:又稱批處理文件, 在DOS、OS/2、微軟視窗系統中,是一種用來當成腳本語言運作程式的檔案。它本身是文字文件,其中包含了一系列讓具備命令列介面的直譯器(cmd)讀取並執行的指令。
回到主題,這次我們要做的是幫資料夾加密。雖然windows本身有提供加密的功能,但那不是用密碼加密而是用憑證檔案加密,對於普羅大眾來講(其實是對我自己)有那麼一點距離,因此今天要來分享的是如何用密碼來加密。
看得懂影片+英文的人可以直接點這裡照原創作者Hasan Zahidi的指示做,看不懂的也別害怕,教你兩分鐘內解決。首先你得先複製下面的程式碼:
==================不要複製這裡=========================
cls
@echo off
title Folder Locker
IF EXIST "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}" GOTO UNLOCK
IF NOT EXIST Locker GOTO MDLOCKER
echo Folder Created.
:CONFIRM
echo Are you sure you want to lock the folder? (Y/N)
set/p "cho="
IF %cho%==Y GOTO LOCK
IF %cho%==y GOTO LOCK
IF %cho%==N GOTO END
IF %cho%==n GOTO END
echo Invalid Choice.
GOTO CONFIRM
:LOCK
ren Locker "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}"
attrib +h +s "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}"
echo Folder Locked.
GOTO END
:UNLOCK
echo Enter password to unlock the Folder :
set/p "pass="
IF NOT %pass% == YourPassword GOTO FAIL
attrib -h -s "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}"
ren "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}" LOCK
echo Folder Unlocked Successfully.
GOTO END
:FAIL
echo Invalid Password!
GOTO END
:MDLOCKER
md Locker
echo Folder created.
GOTO END
:END
PAUSE
=====================不要複製這裡==========================
好了,接下來新增一個txt檔案(就是打開一個記事本的意思)並貼上程式碼。至此已經25%完成
接下來你要做的就是把上面藍色的YourPassword給改成你自己的密碼(例如123456789之類的)
記得不要讓密碼和前面的等號和後面的GOTO的G連在一起喔!
然後在記事本的選單列上,點"檔案"-->"另存新檔",會跳出一個視窗,看你要存在哪裡和取甚麼名稱都可以,存完之後,為檔案重新命名,在原本檔名後面加上.bat把檔案轉換為批次檔(例如原本檔名是123.txt或123,就改為123.bat)。這時候你就可以發現圖示改成一個有齒輪的,這代表你成功了!
接著點一下你剛創造的bat檔案,再按任意鍵關閉黑色視窗,就會在目錄中發現新的Locker資料夾,把你要加密的檔案丟進去, 再開一次剛剛的bat檔後會問你要不要加密,輸入Y(大小寫皆可),這時候你的資料就和Locker資料夾一起消失了!!
不過事實上檔案還是在那邊,這點可以從容量看的出來。到這裡你已經完成任務,往後需要存取資料,只需要再點一下bat檔,輸入你的密碼。只是有幾點需要注意的事情:
- 你的.bat檔案要妥善保管,不過丟了其實也不會怎樣,只要照上面的步驟再走一次,密碼跟原本一樣即可。
- 這個.bat檔其實是任何人只要看到都能夠打開的(也就是說他/她可以用記事本打開看到你/妳的密碼),所以建議各位可以把這個批次檔存在雲端或不會看起來奇怪的地方(但你得記住原先的Locker資料夾放在哪裡...最好是把.bat丟到同個目錄下再輸入密碼解密。),然後取名也盡量不要取的很刺眼(例如藏寶圖啦、Password啦、
sod啦),甚至就直接設為隱藏放在你/妳放Locker的地方XD
對於程式碼,只要有學過一點程式語言應該都可以看出來它只是用一些判斷條件和使用者指令去進行加密解密的動作,而且我也不是很懂(雖然掃過去一遍就大概知道邏輯了...),所以我就不解釋了(逃~)!看完這篇還沒去投贊成票的朋友們可以趕快去XDD
2015年2月11日 星期三
(Android API Guides系列)Android 應用程式架構基礎(上)
好久沒有更新啦~寒假到了人就特別閒一點。因為本人最近剛好在學Android,坊間的教材參差不齊,入門用雖有好書,但我個人覺得還是Google自己寫的比較完整一點(廢話...),且坊間參考書也多是參考Google寫的內容加以編纂。所以才突發奇想來翻譯一下(不過因為原來的也是有些冗長,我會把重要的地方盡量挑出來省自己和大家的時間),不知道可以翻幾篇(眼神死)。不過我是完全不專業的非本科系大四生一枚,只能希望有錯誤的地方大家多多指正,有問題的話....應該是幾乎沒辦法回答XDD
以下內容都是針對Google API Guide - Application Fundamentals做翻譯。
進入正題,相信在學習程式語言的朋友們應該都有聽過Java,雖然我完全沒有學過它,但靠著大二時修的C#(念作"see sharp,"Visual C系列的一種結合C與C++的物件導向語言,詳見維基百科),關於物件導向我於是也能略懂略懂。Android app就是以Java語言編寫而成的,寫好的程式碼會交給Google開源釋放出的SDK(Software Development Kit, 軟體開發套件)去編譯(Compile, 把人用的原始語言轉換成電腦看得懂的目標語言的動作),同時也會把程式需要用到的外部資料(例如圖片、音訊檔,或是版面配置檔等xml資源檔案)一起包含進去變成一個附檔名為.apk的APK(Android Package,應用程式封裝),也就是平常我們下載APP時會在手機裡的檔案夾看到的安裝檔。
APP一旦安裝好了,該APP就會建立起自己的一塊安全領域(security sandbox):
- Android的作業系統(OS, operating system)是支援全多工的 Linux-based系統,每一個APP都能夠獨立運作。
- Android系統預設上,會指派一組唯一的Linux ID給每一個APP(這組ID只會被此系統使用,即APP本身並不會看到),而這組ID會被Android系統用來識別出那些檔案是屬於哪個APP使用。
- 每個應用程式程序都擁有獨立的虛擬機器 (VM, Visual Machine), 所以APP的程式碼會獨立地運作,在它自身的Linux程序中。
- Android會在任一個有關於此APP的組件(Activities, Services...等,後面會再提到)被要求執行時啟動這個Linux程序,然後在不再需要或是系統必須空出記憶體給其他APP使用時關閉。
因此,我們說Android系統滿足了最小許可權原則. 也就是說,每個APP在預設上只能利用其所必要之系統部分。 這使得APP在其使用上有保護整體裝置運作的安全性,只在使用者給予權限時能夠作動。
不過其實,還是有方法可以讓APP之間分享資料或是主動存取系統服務的:
不過其實,還是有方法可以讓APP之間分享資料或是主動存取系統服務的:
- 我們其實可以安排讓兩個不同的APP分享同樣的Linux ID,藉此讓它們都能存取各自的資料。為了保留系統資源,共有同樣ID的APP甚至還能夠在同一個Linux程序下執行並共有同一台虛擬機器(惟這兩個APP必須也使用同樣的憑證)
- 我們都知道,APP可以要求使用者提供權限以存取使用者的裝置資訊,例如通訊錄、簡訊、SD卡資料、相機、藍芽...等等。這些權限必須在安裝時被使用者允許,否則將無法進行安裝程序。
以上大概已經介紹了Android app存在於系統中的基本樣貌,在剩下來的文章中我們將繼續看到:
Intent的instance可以用Intent intent=new Intent();的方式產生,再由開發人員決定要賦予其甚麼樣的任務(此時再決定要活化甚麼組件,可以是開發人員自己編寫的activity);或是也可以直接定義intent本身的任務(直接指明要活化的組件,通常是內建的內容),如Intent intent=new Intent(動作,內容)的方式,其中Intent方法的參數分別是動作(例如瀏覽網站就用內建的ACTION_VIEW方法、撥號則是ACTION_DIAL...)及內容(例如瀏覽網站時就是Uri.parse("要瀏覽的網址")、撥號則是Uri.parse("tel:電話號碼"))。
如上所述,對於activities和services而言,intent定義了要進行的動作(例如看某張圖片或傳某種資料),也可以指明將要進行操作的資料之統一資源標示符URI(Universal Resource Identifier,可以當作是資料的ID,如上面用到的Uri.parse()方法就是利用這個ID去解析所要的網頁、電話號碼)。舉例來說,一個intent也許會傳遞一個由某個activity發出的,要求show出一張照片或打開一個網頁的指令,這時候就會用到URI。在某些例子之中,我們可以讓一個由intent活化的activity再用intent的形式傳回結果(可能用bundle的形式打包資料),舉例來說,我們可以在activity中創造一個intent,來讓使用者挑選一個聯絡人,再把使用者挑選的結果用另一個intent傳回來給activity,這時這個intent也會包含了關於該聯絡人的URI。關於URI,這裡有更詳細的解說。
對broadcast receiver來說,intent僅定義了需要被廣播的通知內容(例如低電量通知的intent中可能只有一個已知的字串"電源不足"。
最後一個組件類型content provider,無法被intent活化。這類組件的活化條件是收到來自ContentResolver的要求時。Content resolver物件處理了所有跟content provider的資料交換,因此發出要求的組件不需要也無法直接觸及content provider,這種類似白手套的機制是為了系統的資訊安全,在計算機科學中被稱為抽象化(Abstraction),是一種把系統理想化進而提高可開發性的概念。在這裡的意義是我們可以只關心content resolver這個現成類別的方法如何被我們利用,不需去管在檯面下的資料如何被交換。
想知道更多有關intent的資訊的人,可以參照Intents and Intent Filters (官方提供);更多關於活化特定組件的資訊也可以參照以下連結 : Activities, Services, BroadcastReceiver , Content Providers(官方提供)
這篇上集就先到這裡,主要我是希望能詳實地呈現原汁原味,所以沒什麼刪減(最基本的東西是最難刪減的,因為最重要....)。有些地方可能翻得不太好,有些地方我引入自己學習Android半個月以來(無誤)的經驗,同時因為我把目標觀眾設定為"已經安裝好Android Studio或Eclipse,且已經看過一些參考書,實作過一點東西,但想知道更多更詳細的人",所以我不會教大家怎麼設置開發環境,請大家動動手指Google一下相信一定有成千上萬種教學XDD。
P.S.下集不知道甚麼時候會寫好XDD
- 定義APP的核心架構組件(Core Framework Components)
- 清單檔(Manifest file),可用來宣告APP之組成內容及必要之裝置特性。
- 分離於APP程式碼,且讓使用者的APP能夠在不同的裝置組態中最佳化的資源檔(Resource files)
App核心架構組件(App Components)
App組件是組成Android應用程式的積木,每一個組件都可以是一個不同的程式進入點,但這僅是對手機系統而言;對使用者來說,這些進入點可能必須互相關聯(也就是說使用者無法直接跳過某個組件進到下個組件)。但是,這些組件在系統中確實是獨立存在的個體且各自擁有明確的定位:每一個組件都能幫助定義開發者設計的應用程式之整體表現。
架構中共有四種不同的組件,各自有不同的目的及生命週期(Life cycle, 定義該組件如何創生及消滅):
架構中共有四種不同的組件,各自有不同的目的及生命週期(Life cycle, 定義該組件如何創生及消滅):
-
Activities(近似於網頁的頁面,或是C#之form元件)
- Activities代表著單一個視窗(screen)以及其使用者介面(UI, user interface)。舉例來說,一個郵件APP可能會有一個activity呈現出一列新的郵件,另一個activity讓使用者撰寫郵件,再一個讓使用者閱讀郵件。雖然他們可能呈現出一體感(介面上、使用者操作使用上),但其實他們是獨立運作的個體(透過intent來聯繫,透過bundle來傳遞資料,後面會再提)。
- 如此一來,就能夠讓activities達到共用的目的,使用者可以在不同的APP裡開啟同樣的activity(如果在郵件APP中我們允許此行為,可能可以利用public class的方式實作)。舉例來說,假設今天另有一個拍照APP想要把照片利用郵件傳遞給別的使用者,我們可以設計使拍照APP多一個撰寫郵件的功能,而這只需要連接到剛才提到的郵件APP中的撰寫郵件activity就能達成。
- 最後要提的是,每個activity都是繼承(extend)於Activity類別的子類別(subclass),這點在實際撰寫程式時會注意到。有興趣的人可以進一步參閱Google Activities developer guide.
-
Services(用在通常會在背景運作且不會太耗電的程序)
Services與Activities的差異在其背景工作/進行遠距程序的能力,且Service沒有UI。舉例來說,一個service可以讓你在播放音樂的同時,操作各種不同的APP;或是可以讓你在和某APP的activities互動時,繼續從網路獲取資料。Service可以由另一種組件,例如activity,啟動或是結合,使得這些組件互相關聯。
-
同樣地,service是繼承於Service類別下的子類別,有興趣的人可以進一步參閱Google Services developer guide.
- Content providers(管理資料的部門)
Content provider用來做資料管理,從字面上可以理解為一種提供資料、內容的部門。通常我們可以在Android系統中以檔案系統, SQLite資料庫, 網路, 或是其他你的APP能存取的常駐儲存位置(雲端、SD卡等)。利用content provider,其他APP可以查閱或甚至更改資料內容(如果該content provider提供權限的話)。舉例來說,有用來管理用戶的連絡資訊的content provider,當有任何APP需要存取或變更關於聯絡人的資訊時,就能夠透過適當的content provider(例如ContactsContract.Data)達到目的。因此當然也能設定為只能被特定的APP給存取,例如開發者專為其APP設計之資料庫,或是用來儲存筆記的Note Pad 範例程式。(Note Pad程式碼可以從Android Studio的Import sample取得,在選單列的File-->Import sample找尋即可)
- 利用content provider建立instance(屬於某類別的物件,關於物件導向介紹,請看這裡)時,此instance的類別也是隸屬於ContentProvider的子類別,且必須實作標準的應用程式介面(API, 軟體系統溝通的橋樑)來讓其他APP也能獲取此content provider的內容。更多訊息請參照這裡
Broadcast receivers(接收通知的捕手)
Broadcast receiver是用來回應從系統其他部分傳來的通知(system-wide broadcast announcement)的組件,在手機裡,許多receivers都是來自系統,例如螢幕關閉通知、低電量通知、檔案已下載完成通知等等。在APP裡也可以啟動通知,舉例來說,在使用A程式時,你可能會收到來自B程式的broadcast,通知你某某檔案已經下載完成,可以使用。雖然broadcast receiver不會呈現UI,但可以建立狀態列通知(status bar notification, 就是螢幕上方那條)來告知使用者:有廣播事件(broadcast event)被觸發了。更普遍的情況是,broadcast receiver扮演著連接其他組件的"通道"的角色,且通常只用來執行小量的工作。例如根據被觸發的event來觸發一個service以完成某目標,但本身只是中介的角色。
Broadcast receiver實作於BroadcastReceiver類別下,且每一個broadcast都是以Intent物件的形式傳遞。更多訊息請參照這裡。
Android系統的一個獨特部分是其可以讓任何一個APP啟動另一個APP的組件。舉例來說,如果你想要讓使用者拍張照,你可以找到另一個APP所開發的拍照activity,並利用它來為你的程式拍張照。神奇的是,你不需要合併或甚至連結該activity的程式碼,你只需要啟動該activity並拍張照。拍完之後,照片甚至可以傳回到你的APP裡頭供你使用。從使用者經驗的角度來說,這就好像相機內建在你的APP裡面一樣。
當系統啟動一個Android組件時,同時也啟動了該APP的程序(如果該程序還沒執行)和實作了一個該組件類別之instance。舉例來說,如果你的APP開啟了拍照APP中的拍照activity,則該activity實際上是運作在拍照APP的程序之中。因此,有經驗的程式設計師會發現Android apps沒有一個單一的進入點(像是Arduino, Processing, C#等都會有的main()或setup()或loop()方法)。
- 由於前面提到Android系統獨立運作各APP並設定存取權限的緣故,我們的APP無法直接活化另一APP裡的組件。但是這些APP上層的Android系統就可以。所以,如果想要做這件事,我們需要一個叫做Intent(坊間翻作意圖)的物件來乘載給系統的要求。如果系統認可,系統就會下海幫你完成這件事情。
活化組件(Activating Components)
上面提到的四種組件中,有三種:Activities, services, and broadcast receivers能夠被Intent這種非同步(asynchronous message, 我的理解是因為其無法馬上要求回覆的特性,因此稱為非同步)的物件給活化。Intents會在運行時把獨立的組件們給連結起來(你可以把Intents想像為郵差或信使,他們會從一個組件傳遞要求到另一個組件)以傳遞資料或要求動作,因此也有參考書稱之為超連結元件。
Intent的instance可以用Intent intent=new Intent();的方式產生,再由開發人員決定要賦予其甚麼樣的任務(此時再決定要活化甚麼組件,可以是開發人員自己編寫的activity);或是也可以直接定義intent本身的任務(直接指明要活化的組件,通常是內建的內容),如Intent intent=new Intent(動作,內容)的方式,其中Intent方法的參數分別是動作(例如瀏覽網站就用內建的ACTION_VIEW方法、撥號則是ACTION_DIAL...)及內容(例如瀏覽網站時就是Uri.parse("要瀏覽的網址")、撥號則是Uri.parse("tel:電話號碼"))。
如上所述,對於activities和services而言,intent定義了要進行的動作(例如看某張圖片或傳某種資料),也可以指明將要進行操作的資料之統一資源標示符URI(Universal Resource Identifier,可以當作是資料的ID,如上面用到的Uri.parse()方法就是利用這個ID去解析所要的網頁、電話號碼)。舉例來說,一個intent也許會傳遞一個由某個activity發出的,要求show出一張照片或打開一個網頁的指令,這時候就會用到URI。在某些例子之中,我們可以讓一個由intent活化的activity再用intent的形式傳回結果(可能用bundle的形式打包資料),舉例來說,我們可以在activity中創造一個intent,來讓使用者挑選一個聯絡人,再把使用者挑選的結果用另一個intent傳回來給activity,這時這個intent也會包含了關於該聯絡人的URI。關於URI,這裡有更詳細的解說。
對broadcast receiver來說,intent僅定義了需要被廣播的通知內容(例如低電量通知的intent中可能只有一個已知的字串"電源不足"。
最後一個組件類型content provider,無法被intent活化。這類組件的活化條件是收到來自ContentResolver的要求時。Content resolver物件處理了所有跟content provider的資料交換,因此發出要求的組件不需要也無法直接觸及content provider,這種類似白手套的機制是為了系統的資訊安全,在計算機科學中被稱為抽象化(Abstraction),是一種把系統理想化進而提高可開發性的概念。在這裡的意義是我們可以只關心content resolver這個現成類別的方法如何被我們利用,不需去管在檯面下的資料如何被交換。
Google提供了分別的方法以活化不同類別的組件:
- 我們可以把定義好的intent丟給startActivity()方法(如:startActivity(intent)),或是startActivityForResult()以取得被活化的activity運作後的結果。
- 我們也可以用類似的方式活化一個service,把intent丟給 startService(). 或是用bindService()直接把intent連結到service上。
- 或是創造一個broadcast,例如把intent丟給sendBroadcast(),sendOrderedBroadcast(), 或是 sendStickyBroadcast()方法,在這裡先不一一解釋。
- 我們也可以實行一個檢閱的指令,用 query() 方法( ContentResolver類別的成員,會回傳代表資料的Cursor)
想知道更多有關intent的資訊的人,可以參照Intents and Intent Filters (官方提供);更多關於活化特定組件的資訊也可以參照以下連結 : Activities, Services, BroadcastReceiver , Content Providers(官方提供)
這篇上集就先到這裡,主要我是希望能詳實地呈現原汁原味,所以沒什麼刪減(最基本的東西是最難刪減的,因為最重要....)。有些地方可能翻得不太好,有些地方我引入自己學習Android半個月以來(無誤)的經驗,同時因為我把目標觀眾設定為"已經安裝好Android Studio或Eclipse,且已經看過一些參考書,實作過一點東西,但想知道更多更詳細的人",所以我不會教大家怎麼設置開發環境,請大家動動手指Google一下相信一定有成千上萬種教學XDD。
P.S.下集不知道甚麼時候會寫好XDD
2015年2月10日 星期二
(Android API Guides系列)Android 應用程式架構基礎(下)
大家好,睽違了2天相信大家都很期待下集,那就讓我們繼續看完關於Google釋出的API解說中最基本但也最重要的部分:Application Fundamentals吧!
在本集中我們將會看到定義程式內容和性質的Manifest files(清單檔)和存放各種App會使用的資源的Resource(資源檔)檔案。
Manifest files(清單檔)
在Android系統啟動一個APP組件之前,它必須先到這個通常在專案中名為AndroidManifest.xml的檔案去檢查該組件是否存在之後才能啟動。所以我們必須在這個xml檔案(我們可以在Android Studio的專案中關於Manifest的資料夾中找到它)中宣告所有的成員。
除了宣告組件存在之外,manifest檔還有以下主要功能:
如上所述,宣告組件成員是manifest檔案主要任務,方法可以如下:
Activities, services, content providers這些組件,如前述地,在我們的Java程式碼中寫完完整功能之後,我們還必須在manifest中宣告之後才能被系統"看到",否則無法運作。但是,Broadcast receivers是個例外,它可以像他們另外三個夥伴一樣在manifest檔中宣告,也可以動態地在Java程式碼裡空降(就像BroadcastReceiver一樣)並驕矜地呼叫registerReceiver()來完成系統註冊(讓系統知道它存在)這個trivial的動作。
想知道更多有關如何為你的APP組成一個manifest清單檔請看The AndroidManifest.xml File。
如前所述,在談到活化組件時,我們提到可以用Intent來開啟三種組件(activities, services, and broadcast receivers)。方法上我們可以直接言明目標組件是誰,在Intent中直接指向它。然而Intent強大的地方就是在其隱匿性(Implicit),怎麼說呢?隱匿性只需要我們描述動作類型(或是也可以進一步告訴Intent這個信使我們想要操作的資料),這樣系統就能夠幫我們找到一個裝置中的組件(可以是別的APP的成員)來幫我們完成這個動作。如果有複數的組件能執行Intent所描述的動作,使用者也可以自行選擇要使用哪個組件。(編按:聽起來真的很強大啊XD)
至於系統要怎麼識別出那些組件能達成Intent的任務呢?原來就是manifest裡面的宣告組件功能的區塊啊!當我們在APP的清單檔中宣告了一個activity,我們可以選擇性地把宣告"這個activity具有甚麼功能"的Intent filter給函括進去,這樣一來從其他APP來的Intent就可以取用我這個activity的功能了!
簡單來說就是為了在上架到Google Play商店時能夠讓使用者快速知道你的APP與其裝置之相容性,我們必須把相關資訊放在manifest檔案裏頭。舉例來說,如果你的APP需要用到相機且必須要在Android 2.1(API Level 7)以上運行,你可以這樣做:
吸收最大利益廣大市民福祉,你也可以android:required屬性改為false,這樣一來系統會在執行時檢查裝置是否有相機,你也可以用此方式disable掉一部分需要用到相機的功能,使APP能正常運作。
關於裝置相容性,等不及的人可以看Device Compatibility document。
至於要怎麼做到最佳化呢?我們需要一點前情提要:
- 識別該APP需要的使用者權限,例如網際網路存取、讀取通訊錄等
- 宣告最小相容的API等級(minimum API Level,也就是用來組成、編譯你的程式的API版本,越新通常會包含越多功能,1.0.2版預設為8)
- 宣告會用到的軟硬體成員,例如相機、藍芽裝置、多點觸控螢幕。
- 外部API函式庫(那些不包含在Android framework APIs裡面的,例如Google Maps library)
1.宣告組件
<?xml version="1.0" encoding="utf-8"?> <manifest ... > <application android:icon="@drawable/app_icon.png" ... > <activity android:name="com.example.project.ExampleActivity" android:label="@string/example_label" ... > </activity> ... </application> </manifest>在<application>標籤裡,android:icon指向某個決定APP圖示的.png Resource檔。在<activity>標籤裡,android:name定義了開啟的activity的類別名稱(ExampleActivity)。android:label則定義了此activity的顯示名稱。
Activities, services, content providers這些組件,如前述地,在我們的Java程式碼中寫完完整功能之後,我們還必須在manifest中宣告之後才能被系統"看到",否則無法運作。但是,Broadcast receivers是個例外,它可以像他們另外三個夥伴一樣在manifest檔中宣告,也可以動態地在Java程式碼裡空降(就像BroadcastReceiver一樣)並驕矜地呼叫registerReceiver()來完成系統註冊(讓系統知道它存在)這個
想知道更多有關如何為你的APP組成一個manifest清單檔請看The AndroidManifest.xml File。
2.宣告組件功能
至於系統要怎麼識別出那些組件能達成Intent的任務呢?原來就是manifest裡面的宣告組件功能的區塊啊!當我們在APP的清單檔中宣告了一個activity,我們可以選擇性地把宣告"這個activity具有甚麼功能"的Intent filter給函括進去,這樣一來從其他APP來的Intent就可以取用我這個activity的功能了!
<intent-filter>
的用法如下:<manifest ... > ... <application ... > <activity android:name="com.example.project.ComposeEmailActivity"> <intent-filter> <action android:name="android.intent.action.SEND" /> <data android:type="*/*" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
注意到<action android:name="android.intent.action.SEND" />這行定義了要捕捉的動作名稱"SEND",下一行定義了檔案類型,再下一行則是Intent的類型(其實這邊我不懂"*/*",知道的人可以教我XD)。如此一來,如果從另一個APP傳出了含有ACTION_SEND動作(編寫並寄送郵件)的intent,系統可能會開啟我們寫的activity來讓使用者有另外一種選項編寫並寄送郵件。
想知道更多有關如何建立intent filter的人可以參考Intents and Intent Filters document。3.宣告APP之系統需求
簡單來說就是為了在上架到Google Play商店時能夠讓使用者快速知道你的APP與其裝置之相容性,我們必須把相關資訊放在manifest檔案裏頭。舉例來說,如果你的APP需要用到相機且必須要在Android 2.1(API Level 7)以上運行,你可以這樣做:
<manifest ... > <uses-feature android:name="android.hardware.camera.any" android:required="true" /> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> ...</manifest>這樣一來,沒有相機(沒有才怪)或是Android系統舊於2.1版的可憐孩兒們就不能從Google Play安裝你的APP了(哭哭)。不過為了
關於裝置相容性,等不及的人可以看Device Compatibility document。
App Resources(APP資源檔)
一個完整的APP是由Java程式碼和我們會用到的資源(例如圖像、音訊、以及其他關於視覺設計的部分)組成。而這些資源都會被定義在XML格式的資源檔中(Android Studio專案中的res資料夾裡面),舉例來說,你可以在xml資源檔中定義你設計的activity中存在的動畫(animation)、選單(menu)、造型(style,color)、佈局(layout)。因為這些資源與程式碼被分開來管理,所以在更新以上部分的內容時,不需要再更改程式碼,這使得你的APP在適應不同裝置時(例如不同語言、不同螢幕大小的手機)能更快達到最佳化。至於要怎麼做到最佳化呢?我們需要一點前情提要:
SDK build tool(軟體開發建置工具)會為每一個APP專案用到的資源定義一個唯一的整數ID,以用來當作Java程式碼及其他xml資源檔參考(reference)此資源的識別碼(以人比喻的話,相似於每個人的身分證字號的意思)。舉例來說,當你的APP包含了一個名為logo.png的圖檔(假設你存在res/drawable/資料夾中),SDK tools就會幫你在R.java這個資源類別檔裡頭自動產生一個名為R.drawable.logo的ID,讓你可以在Java程式碼中用這個ID來取得該圖檔物件。(如果在xml檔中的話就要用@drawable/logo來取得。)
回到最佳化的話題,由於資源檔與程式碼分開管理的特性(一個在xml檔中定義,一個在Java檔中定義),我們能達到適應不同裝置組態的目標。舉例來說,你在xml中定義一個UI string時,可以用任何語言,因此你可能會有很多個語系的同一個UI string在不同的資源檔中。當你需要為你的程式附加不同語言選項時,你就可以讓系統自動去找到合適的xml檔案。比如說,利用為資源檔資料夾加入語言修飾詞(language qualifier)的動作(例如 res/values-fr/xml資源檔案),再加上使用者裝置的語言設定(前例為法文,-fr),Android系統可以幫你決定適當的xml檔案,再生成你的UI。
為不同的資源檔版本,Android支援許多不同的修飾詞。這些修飾詞可以是添加在資源目錄的短字串以決定適當的裝置組態,如上述的-fr可以讓系統知道這是定義法文版本的xml資源的資料夾。另一個例子,你可能需要產生不同的佈局檔以應付不同的手機螢幕方向/尺寸,舉例而言,當螢幕放直(portrait orientation)時,你可能想要一些按鈕佈局改為垂直方向;當螢幕橫放時(landscape orientation)時,按鈕要放水平。這些都能透過適當的修飾詞讓系統自動決定。
回到最佳化的話題,由於資源檔與程式碼分開管理的特性(一個在xml檔中定義,一個在Java檔中定義),我們能達到適應不同裝置組態的目標。舉例來說,你在xml中定義一個UI string時,可以用任何語言,因此你可能會有很多個語系的同一個UI string在不同的資源檔中。當你需要為你的程式附加不同語言選項時,你就可以讓系統自動去找到合適的xml檔案。比如說,利用為資源檔資料夾加入語言修飾詞(language qualifier)的動作(例如 res/values-fr/xml資源檔案),再加上使用者裝置的語言設定(前例為法文,-fr),Android系統可以幫你決定適當的xml檔案,再生成你的UI。
為不同的資源檔版本,Android支援許多不同的修飾詞。這些修飾詞可以是添加在資源目錄的短字串以決定適當的裝置組態,如上述的-fr可以讓系統知道這是定義法文版本的xml資源的資料夾。另一個例子,你可能需要產生不同的佈局檔以應付不同的手機螢幕方向/尺寸,舉例而言,當螢幕放直(portrait orientation)時,你可能想要一些按鈕佈局改為垂直方向;當螢幕橫放時(landscape orientation)時,按鈕要放水平。這些都能透過適當的修飾詞讓系統自動決定。
想知道更多你可以加入程式的資源類型和不同的組態下的資源檔要如何產生可以參考這裡:Providing Resources。
關於Android Fundamentals的介紹就到這邊,謝謝各位觀看。希望沒有太難懂......其實我寫這些文章一大部分是要以後自己看的,我就是上一篇文章中提到的目標觀眾"有一點基礎,但是希望知道更多的人"。希望能和也在學習或老手複習的人一起變強,所以有任何的疑問或是建議也請大家多多提出~
前年暑假去東京玩,在橫濱拍的照片XD |
訂閱:
文章 (Atom)