2010年12月24日 星期五

網頁與AIR程式互動

如果需要在Browser上可以與AIR應用程式做互動,如安裝AIR App,或由網頁上的Click觸發啟動AIR App,以下是相關執行程序

一.準備工作
1.AIR程式端設定AIR程式允許透過Browser觸發
設定AIR發布用的application.xml的
 <application xmlns="http://ns.adobe.com/air/application/2.0">  
建議設定發布為AIR 1.53以上版本,因為如果AIR為1.53之前的版本,Browser要呼叫AIR,一定要知道AIR的PID值(在AIR內可以用NativeApplication.nativeApplication.publisherID取得)。若AIR為1.53後的版本,若Browser不知道AIR的PID,可以用""代即可。

加入
 <allowBrowserInvocation>true</allowBrowserInvocation>  
讓AIR允許被Browser啟動

2.Browser端Flash取得AIR Browser API
Browser端Flash要操作AIR所要用的API都放在http://airdownload.adobe.com/air/browserapi/air.swf內
透過loader載入這個檔案即可使用相關功能

public var airSWF:Object;
public var airSWFLoader:Loader = new Loader();
public var loaderContext:LoaderContext = new LoaderContext();
loaderContext.applicationDomain = ApplicationDomain.currentDomain; 
airSWFLoader.contentLoaderInfo.addEventListener(Event.INIT, onInit); 
airSWFLoader.load(new URLRequest(" http://airdownload.adobe.com/air/browserapi/air.swf"), loaderContext);
private function onInit(e:Event):void { 
    airSWF = e.target.content;
    airSWF.getApplicationVersion(appID, pubID, versionDetectCallback);
}        

二.Browser檢查Client是否已經安裝AIR執行環境
var result:String=airSWF.getStatus();
取得回傳值
"available":可安裝但尚未安裝。
"unavailable":無法安裝
"installed":已安裝

三.Browser檢查Client端是否已經安裝AIR 應用程式
利用檢查AIR應用程式版本來確認程式是否已經安裝,執行後,若檢查完成
會呼叫執行所設定的versionDetectCallback函式,並在這callBack函式內
取得版本值,當版本值為null代表未安裝程式
airSWF.getApplicationVersion(appID, pubID, versionDetectCallback);
private function versionDetectCallback(version:String):void { }    

設定參數:
appID:應用程式ID,即AIR應用程式的application.xml內的id值,或在air內透過
    NativeApplication.nativeApplication.applicationID取得
pubID:發佈者ID,在air內透過
    NativeApplication.nativeApplication.publisherID取得

注意:要讓這功能有效可以使用,在使用air.swf一定要是載入http://airdownload.adobe.com/air/browserapi/air.swf
若將這air.swf複製到local端呼叫使用,則取得版本永遠會是null值

四.Browser安裝AIR App
airSWF.installApplication(installPath, runtimeVersion, arguments); 
設定參數:
installPath:String,要安裝的air檔案路徑
runtimeVersion:String,允許執行的AIR Runtime最低版本,例如"1.5"
arguments:Array,非必填項目,要傳遞給AIR的參數,這參數會被AIR內的
BrowserInvokeEvent.BROWSER_INVOKE事件所接收

五.Browser 啟動已安裝AIR APP
airSWF.launchApplication(appID, pubID, myArguments);

六.Browser傳遞參數給AIR App
airSWF.launchApplication(appID, pubID, myArguments);
只要將傳遞的參數放到myArguments陣列內即可

2010年12月9日 星期四

List物件客製CellRenderer與設定背景顏色

在使用List或DataGrid物件,如果需要自行設計CellRenderer,例如加入圖片,底圖或使用多文字框,以下是自訂CellRender操作流程

一.自訂 CellRenderer Class
自訂CellRenderer必須繼承Sprite或MovieClip且實作ICellRenderer介面
因此一個自訂的CellRenderer Class基本上一定具備以下結構

public class ItemRenderer extends Sprite implements ICellRenderer{
    private var _listData:ListData; 
    private var _data:Object; 
    private var _selected:Boolean; 
    public function ItemRenderer() {}
    public function set data(d:Object):void { 
    }
    public function get data():Object { 
        return _data; 
    } 
    public function set listData(ld:ListData):void { 
        trace("ListData=" + ld.label);
        _listData = ld; 
    } 
    public function get listData():ListData { 
        return _listData; 
    } 
    public function set selected(s:Boolean):void { 
        _selected = s;             
    } 
    public function get selected():Boolean { 
        return _selected; 
    } 
    public function setSize(width:Number, height:Number):void { } 
    public function setStyle(style:String, value:Object):void { } 
    public function setMouseState(state:String):void{ } 

}
雖然自訂的CellRenderer可以直接繼承自系統的CellRenderer,但最好還是實作ICellRenderer介面,可以有比較大的彈性應用

二.在Flash IDE上產生Instance
在Flash IDE上,依照需要設計產生CellRender所要對應的Symbol
並在Library內設定該Symble的Linkage
Class:完整的CellRenderer Class名稱
base Class:flash.display.MovieClip

三.List利用setStyle指定cellRenderer Class
當已經設計好CellRenderer Class並在fla上產生好Symbol
執行
list.setStyle("cellRenderer", ItemRendererClass);
(ItemRendererClass是自訂的Renderer Class)
即可讓list使用你自訂的CellRenderer

四.List加入資料
將要提供給cellRenderer用的資料以物件芳式包裝好,再以addItem()加入,這樣CellRenderer內的 set data(obj:Object)即會收到所傳入的物件

var obj=new Object();
obj.id=xxx;
obj.thumb=xxx;...
list.addItem(obj)

五.CellRenderer內各Method說明

1.data
當list以addItem將資料加入後,會自動執行set data()

在list上
list.addItem(_itemObj);    
在renderer上會觸發
public function set data(d:Object):void { 
    //--d即是addItem所帶的_itemObj
    //--利用d帶進來的資料,顯示在你要顯示的文字框或圖片--
}        

2.listdata
當list.addItem(_itemObj);也同時會觸發renderer內的這個listData method
set listData(ld:ListData)內的ld為一個ListData物件,包含了這個renderer在List內的相關資訊
例如ld.index即是這個render在list內所在位置的index值

3.selected
當render的選取狀態有變化時會觸發這個method,也就是說當使用者在list上click item
如果這個item被選取時,selected(s:Boolean)
s會得到true,若在非選取狀態,則為false
在這裡可利用s值,改變render顯示的樣式,顯示物件選取狀態

4.setSize
只要是在list上做關於size改變的設定,例如
list.setSize()或設定list.rowHeight,都會把在list上設定的大小值
傳給render的setSize(),你可以在這method內依照傳進來的值
調整render內物件的大小
5.setStyle
可用來設定CellRender的顯示樣式,若不想做任何處理,保持空的即可
但一定要保留這method在Class內

6.setMouseState
可用來設定CellRender的滑鼠狀態,若不想做任何處理,保持空的即可
但一定要保留這method在Class內

六.設定List的背景色
List本身並無backgroundColor的選項可供改變List的底色,使用serStyle("backgroundColor")也是無效,若要改變底色需要設定的是"skin"的style,並傳入一個你要當作背景的物件當作傳入值

var bg:Sprite = new Sprite();
bg.graphics.beginFill(0xff0000,0.5);
bg.graphics.drawRect(0, 0, 10, 10);
bg.graphics.endFill();
list.setStyle("skin", bg);

註:skin style預設是List_Skin這Class

2010年11月2日 星期二

Android Service-幾種應用範例(二)

一.實作要點

1.說明
Service提供兩種的使用方式,如果Client只是透過startService去執行Service的功能,只是把要做的功能寫在onStartCommand內即可,若是Client透過bindService來執行Service,就需要在Service內產生Ibinder物件,讓onBind可以把binder物件傳給Client,讓Client可以由取到的binder物件再取到Service物件,然後就可以呼叫Service上提供的method

2.Activity(使用Service的Client)
1.extends Activity物件
2.實做ServiceConnection(需要bindService時使用)
  實做並產生一個connection instance,在connection內
  override其onServiceConnected(ComponentName className, IBinder service)
  與onServiceDisconnected(ComponentName className)

3.onServiceConnected被自動呼叫(需要bindService時使用)
  在與Service連線成功後,onServiceConnected會被自動呼
  叫並接收到由Service內部onBinder所發送出來的IBinder物件,
  通常會是extends 自Binder
4.取得Service物件(需要bindService時使用)
  將取得的Binder物件呼叫其Class內定義的方法(如getService)
  來取得Service物件,如Service(binder.getService())
5.利用取得的Service呼叫執行中Service上的public method

3.Service(提供服務的元件)
1.extends Service物件
2.設計binder class extends Binder(需要bindService時使用)
  設計一個內部Binder Clas並產生binder instance,在class內
  建立getService function,可以透過這binder取得所在的service
3.overrider onBinder function(需要bindService時使用)
  將已建立的binder instance傳出去
4.override onStartCommand(需要用startService時使用)
  若只用startService啟動Service,只需要override這
  function即可

二.Sample:LocalService 使用startService

1.說明
透過startService呼叫Service會執行Service內部的onStartCommand(),所以把要執行的工作放在override的onStartCommand()內

2.Activity
Intent intent = new Intent(this, MusicService.class);
intent.putExtra("songPath","sdcard/mp3/mySong.mp3");
this.startService(intent);
3.Service
@Override
public void onCreate() {    
    super.onCreate();
    mp=new MediaPlayer();    
}
@Override
public void onStart(Intent intent, int startId) {
    super.onStart(intent, startId);
    String songPath=intent.getExtras().getString("songPath");
    try{
        mp.setDataSource(_path);
        mp.prepare();
        mp.start();
    }catch(Exception e){};
}

三.Sample:LocalService 使用bindService

1.說明
透過bind方式要執行Service上的功能,是透過建立連線物件後,再直接對Service做操作,要做的工作就寫成Service內public method 讓人呼叫執行

2.Activity
private MusicService mService;
@Override
public void onCreate(Bundle _state){
    doBindService()
}
private void doBindService(){
    Intent intent = new Intent(MyActivity.this, MusicService.class);
    bindService(intent, connc,Context.BIND_AUTO_CREATE);
}
private ServiceConnection connc=new ServiceConnection() {            
    @Override
    public void onServiceDisconnected(ComponentName name) {    
    }
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {        
        mService=((MusicService.LocalBinder)service).getService();        
    }
};

要使用service上的function就可以直接用,如 mService.start(),mService.stop()...等定義在Service內public的方法。若要取得回傳值,只要service內的function有回傳值,直接接收就可以了,例如
String _path=mService.getSongPath();

3.Service
內定義一個內部Binder class可以用來取得service
public class LocalBinder extends Binder {
     MusicService getService() {
        return  MusicService.this;
    }
}
private final IBinder mBinder = new LocalBinder();
@Override
public IBinder onBind(Intent intent) {    
    return mBinder;
}

2010年11月1日 星期一

Android Service-概念(一)

一.說明
Service本身是個無介面,只單純提供功能讓其他元件(Activity)呼叫使用的元件,如果有需要長時間執行的獨立程序,可以寫成Service元件提供其他人呼叫使用。

Service本身並非一個獨立的Process,也不會脫離Main Thread獨立運作,如果需要做長時間的CPU運算,為了不影響到主程式運作,可以在Service內產生Thread,讓thread幫你作一些工作,Service的子類別IntentService即是一個有自己Thread 的Service,服務給並無直接與使用者互動的介面。
當Service元件被產生時,一定會執行其onCreate(),如果有需要產生Thread,則在這裡去產生新的thread

當Service有設定在Manifest上,就可以被自己與其他的App來做存取,其他App要使用service,需在他自己App的Manifest內的uses-permission作宣告

二.執行Service功能的兩種方式
1.startService
當有元件呼叫Context.startService(),系統會讀取被呼叫的Service(產生instance並執行其onCreate()),然後將client所傳進來的intent帶進Service的onStartCommand(Intent, int, int)內。這service會一直執行,直到有人呼叫Context.stopService()或內部呼叫stopSelf()而停止。

無論Context.startService()被呼叫了多少次,如果要停止Service,只要執行一次Context.stopService(),或在Service內執行stopSelf(),就會被停止。
如果是在Service內使用stopSelf(int),可以保證intent已經有被處理了,才會被停止。

對於已被啟動的Service,如果需要有不同的Service執行模式,可以在override onStartCommand()時,設定不同的回傳值。這回傳值常數已經被定義好在Service Class內
1.START_STICKY:
  當Service在執行時被砍掉後,若沒有新的intent進來,
  Service會停留在started state,但intent資料不會被保留
2.START_NOT_STICKY或START_REDELIVER_INTENT:
  當Service在執行時被砍掉後,若沒有新的intent進來,
  service會離開started  state,若沒有很明確的再啟動,
  將不會產生新的service物件

2.bindService
Client可以利用Context.bindService() 去建立與service持續性的連線,
如果建立連線時,還沒產生Service instance,會自動產生並呼叫執行onCreate。與startService不同的地方是,接下來並不會呼叫onStartCommand

要執行bindService,首先要先建立一個serviceConnection物件,把這conection物件當作參數放到bindService內讓Context與Service建立連線,Context.bindService(Intent service, ServiceConnection conn, int flags)
flags參數預設是Context.BIND_AUTO_CREATE,也就是bind的時候會自動產生service

當連線成功後,會自動呼叫執行這個connection內的onServiceConnected(ComponentName className, IBinder service) function,在這function會接收到由service內的onBinde()所丟出來的Ibinder物件
利用這IBinder物件取得Service物件,就可以直接操作Service內各個public 的method

三.Service Process重要性判斷
系統會盡量保持Service的Process運作,但若需要刪除Process,以下是重要性判斷準則
1.正在執行onCreate(), onStartCommand()或onDestroy()的
  Service會被當成前景執行程序,不會被刪除
2.假若這ervice已經被啟動(started),那這service所在的
  process的重要性,會是在visible process與hide process之間
3.如果service所在的Process上有元件是visible,那這Service
  的重要性就相當於是visible
4.一個已經started的service可以利用
  startForeground(int,Notification)放在比較重要的
  前景執行狀態,在記憶體少的時候比較不會被刪除

當記憶體不足Service被刪除後,它稍後還是會被重新啟動產生出來,但通常重新啟動後,原本的intent並不會被保留,如果需要在重新啟動後,再重發intent給Service,必須在override onStartCommand()時return START_REDELIVER_INTENT讓重新啟動的程序裡的onStartCommand(Intent intent, int flags, int startId)內的flags值=START_FLAG_REDELIVERY

Android 資料儲存

一.資料儲存方式
在Android內要保存資料,有以下幾種方式可以選擇
1.SharedPreferences
    以key-value方式儲存只有Private data
2.Internal Storage
    使用device內部的記憶體儲存Private data
3.External Storage
    使用如SD卡這樣的外部儲存媒介,儲存Public data
4.SQLite Databases
    以資料庫結構儲存private data
5.Network Connection
    儲存資料到網路主機上
對於Private Data,在Android利用 Content Providers Class來作存取

二.SharedPreferences
利用 SharedPreferences Class可以將基本型別的資料(boolean,string,float,int..)以key-value方式作存取,data會持續保留在user session,即使app被砍了,資料還是保留著

1.取得SharedPreferences的兩種方式
1.需要用到多個Preference的狀況
  getSharedPreferences(name):如果需要用到多個
  preference file儲存,利用name來取得
  例:
  SharedPreferences settings = Context.getSharedPreferences("myPre", 0);
2.只需要用到一個Preference
  Activity.getPreferences(int mode):如果你的Activity
  只會用到一個preference

2.寫入preference的流程
1.呼叫edit()取得SharedPreferences.Editor
    SharedPreferences settings = getSharedPreferences("myPre", 0);
    SharedPreferences.Editor editor = settings.edit();
2.利用以下method把值寫入putBoolean() and putString()
    editor.putString("myStr", "strValue");
3.使用commit()把改變的資料真正寫入
    editor.commit();

3.讀取Preference值
使用SharedPreferences的getBoolean()、getString()等method
String str = settings.getString("myStr","defaultStr");

4.範例
public class Calc extends Activity {
    public static final String PREFS_NAME = "MyPrefsFile";

    @Override
    protected void onCreate(Bundle state){         
       super.onCreate(state);
       . . .
       // Restore preferences
       SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
       boolean silent = settings.getBoolean("silentMode", false);
       setSilent(silent);
    }

    @Override
    protected void onStop(){
       super.onStop();
      SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
      SharedPreferences.Editor editor = settings.edit();
      editor.putBoolean("silentMode", mSilentMode);
      editor.commit();
    }
}

三.Internal Storage
你可以把資料直接儲存在device的內存,預設儲存在內存的檔案是只有該App可讀取,其他App無法讀取,當App移除時,這資料會一併被移除

1.在內存產生一個private file,寫入資料流程
1.提供一個檔案名稱來呼叫openFileOutput(name)
  取得FileOutputStream物件(Context的method)
2.FileOutputStream物件使用write()寫入資料    
3.FileOutputStream物件使用close()關閉檔案


String FILENAME = "hello_file";
String string = "hello world!";

FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
範例裡的參數MODE_PRIVATE是指當有同名檔案會自動覆蓋

2.由內存讀取檔案資料
1.提供檔名呼叫openFileInput(name)來取得
  FileInputStream物件
2.FileInputStream物件使用read()讀取bytes資料
3.FileInputStream物件使用close()關閉

3.使用暫存
若只是暫存資料,而不是永久存檔可以利用getCacheDir()來取得一個File物件當作暫存檔,當系統內存不足時,這些cacheFile就會被刪除,使用暫存檔需要自己時時去清理

4.其他method
1.getFilesDir()
    取得內存在檔案系統的目錄絕對路徑
2.getDir()
    在內存空間建立目錄或開啟已存在目錄
3.deleteFile()
    刪除內存檔案
4.fileList()
    取得目前App在內存所儲存的檔案清單Array

四.External Storage
所有Android相容device均支援利用外部儲存裝置來儲存檔案(如SD卡),
使用者利用USB即可將資料傳輸到電腦內

1.檢查外存媒介是否存在
在使用外存之前都需先用getExternalStorageState()檢查外存媒介是否存在


String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
    //可以對media作讀寫
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
    //只可以對media作讀取
} else {
    //無法作讀寫
}

2.讀取外存檔案
1.API level8
  使用 Context.getExternalFilesDir(String type)取得一個目錄的
  File物件,這method的type參數,是指定子目錄的類型,
  如DIRECTORY_MUSIC,DIRECTORY_RINGTONES或傳入null取得
  App root目錄,再透過File取得檔案,如果檔案已經存在則會打開
  該檔案。利用這method可直接建立目錄,當App移除時,目錄會跟著
  移除    
    
  例
  File path=Context.getExternalFilesDir(null);
  File file=new File(path,"mypic.jpg")    
2.API Level 7以下版本    
  則用Environment.getExternalStorageDirectory()取得根目錄的
  File物件,也就是讀取的資料會是在
  /Android/data/package_name/files/目錄下
  package_name是如同com.example.android.app的名稱
    
  例
  File path=Environment.getExternalStorageDirectory()
  File file=new File(path,"mypic.jpg")


3.儲存檔案
若要儲存檔案,不指定給特定App用,且希望在App移除時檔案不被刪除,
請儲存到外存上的 Music/, Pictures/, Ringtones/等目錄

1.API Level 8
  使用Context.getExternalStoragePublicDirectory(String type)
  取得目錄的File物件。這method的type參數,設定值為
  DIRECTORY_MUSIC, DIRECTORY_PICTURES,DIRECTORY_RINGTONES,
  如果目錄不存在,會自動產生
    
  例
  File path=Context.getExternalFilesDir(null);
  File file=new File(path,"mypic.jpg")
2.API Level 7 以下版本
  使用Environment.getExternalStorageDirectory()取得根目錄的
  File物件。儲存的資料會是在以下的目錄
  
  Music/ - media scanner會掃描這裡找音樂檔
  Podcasts/ - media scanner會掃描這裡找podcast.
  Ringtones/ - media scanner會掃描這裡找音樂手機檔鈴聲.
  Alarms/ - media scanner會掃描這裡找alarm sound.
  Notifications/ - media scanner會掃描這裡找notification sound.
  Pictures/ - 所有照片包括相機拍的都在這裡.
  Movies/ - 所有影片包括相機拍的都在這裡.
  Download/ - 其他下載檔案.
  
  例
  File rootPath=Environment.getExternalStorageDirectory();
  File path=new File( rootPath.getParent() + "/Music" );
  File file=new File(path,"my.mp3")  


4.使用暫存
1.API Level 8
  使用getExternalCacheDir() 開啟cache File,當App被移除時,
  檔案也會被自動移除,但在App還在的狀態下,使用者要自己管
  理暫存避免空間不足
2.API Level 7以下版本
  使用getExternalStorageDirectory()開啟cache File,檔案會被
  放在/Android/data/package_name/cache/目錄下

五.使用資料庫

1.建立資料庫
Android完全支援SQLite,在App內所有Class都可以透過name來使用DB
要在Android內操作使用DB,可以建立SQLiteOpenHelper 的子類別
並在override onCreate()內,建立產生所要的資料庫資料表


public class MyDbOpenHelper extends SQLiteOpenHelper {
    private static final int DATABASE_VERSION = 2;
    private static final String DICTIONARY_TABLE_NAME = "dictionary";
    private static final String DICTIONARY_TABLE_CREATE =
                "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +
                KEY_WORD + " TEXT, " +
                KEY_DEFINITION + " TEXT);";

    DictionaryOpenHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(DICTIONARY_TABLE_CREATE);
    }
}

2.資料庫存取
透過實體化這Class透過呼叫 getWritableDatabase() and getReadableDatabase()取得
SQLiteDatabase物件來對資料庫作讀寫,
查詢動作使用SQLiteDatabase query(),
若是比較複雜的查詢可以用SQLiteQueryBuilder,它會提供一些method來建立查詢

3.查詢結果
每次SQLite 作查詢都會回傳一個Cursor,用來指到查詢結果,
透過Cursor來瀏覽db資料

六.使用網路連線
使用網路連線來將資料儲存於遠端的伺服器
利用以下package提供的物件功能
java.net.*
android.net.*

2010年10月25日 星期一

Android Component Lifecycles - Broadcast Receiver(三)

一.Broadcast Receiver Lifecycle
只有一個LifeCycle callback method
void onReceive(Context curContext, Intent broadcastMsg)
當有訊息傳達到receiver,Android就會呼叫執行Receiver內的 onReceive()
並把intent傳進去給onReceive(),只有在執行onReceive()時,receiver的狀態是active的,當執行完return後
就會變成inactive狀態

當receiver在active狀態時是被保護不被殺的,一旦執行完處於inactive狀態,則在任何時間要砍都可以
記憶體不足時就可先砍掉這receiver

receiver存在的一個隱藏性的危險是,如果當receiver要回應broadcast message,需要開啟一個新的thread去處理時,receiver在開啟thread後會立刻return(其實,處理程序還在運作),receiver已經被當作是inactive狀態,隨時有可能會被砍掉。解決的方式是啟動一個service去處理要做的事,而不要在receiver內去開啟新的thread。

二.Processes 重要性順序
Android系統會盡可能保留所有的process,但如果當記憶體不足時,就會需要砍掉一些較不重要的process。如何判斷process的重要性,以下為重要性順序
1. foreground process:也就是正在進行中的程序
    1.使用者正在互動執行的Activity
    2.正在執行中Activity所正在呼叫運作的Service
    3.Service內部正在進行不可中斷的callback包括onCreate() 
      onStart()或onDestroy()
    4.正在執行onReceive()的BroadCast Receiver物件
      除非系統記憶體已經太低太低,否則系吐統不太可能把正在
      前景執行的程序砍掉
2.visible process:
    1.不是在前景運作,但仍然在螢幕上看的到的元件(已經呼叫了
      onPause())例如前景activity是個對話窗,但還允許前一個
      activity在後面被看到
    2.與visible Activity有關聯的Service
3.service process:
    透過startService()啟動的service,但不在以上兩層次範圍內
    雖然service並非直接與使用者看到的東西關聯在一起,但仍在
    用作使用者在意的事
    例如在背景播放音樂或在背後下載資料,除非記憶體不足否則系
    統會讓他保持運作
4.background process
    一個在背景已經看不到的Activity(已經呼叫了onStop),通常都
    會有許多background process被保留在後面,在記憶體不足時可
    以砍掉節省資源
5.empty process
    沒有任何Activity的元件,就如同cache一樣,這存在只是用來改
    善啟動效能的快慢,為了調節效能,process cache與
    kernal cache經常會被清除

因為一個service的排序是高於一個visible activity,所以在Activity初始化時,若需要進行較長時間處理,最好是啟動一個service來作,效果會比產生一個thread來作好。例如播放音樂與上傳圖片到網站上,在service作會比較好。還有就是在receiver的onReceive處理內,啟動service去執行也較佳

Android Component Lifecycles - Service(二)

一.Service可以用以下兩種模式運作
1.被啟動後一直運行,直到被呼叫停止或自行停止
  外部利用呼叫Context.startService()啟動
  呼叫Context.stopService()停止
  Service內部自己執行Service.stopSelf()或
  Service.stopSelfResult()停止
  無論startService()呼叫了幾次,停止都只需要
  呼叫一次stopService()
2.利用與Service物件建立連線,使用連線呼叫使用Service
  Client利用Context.bindService()建立一個連線到Service物件,
  並使用這連線去呼叫Service。
  若要關閉連線則利用Context.unbindService()關閉連線
  多個client是可以綁定相同的service,如果要用的service還沒被
  啟動,在bindService()時會自動啟動它

這兩個模式並非是完全獨立的,你可以透過startService()後再bind Service。例如一個背景音樂播放的service利用傳遞一個包含音樂播放資訊的intent給startService(intent)來啟動,之後使用者要由這歌取得資訊,Activity會透過呼叫bindService()建立與service的連線,在這case裡stopService並不會真的停止service,因為已經被bind
需要unbind後才會完全停止。

二.Service LifeCycle Method
Service的lifeCycle method只有以下三個,你可以overroide來掌握state的變化。
與Activity的差別是,這裡的method是public,而Activity是protected
public void onCreate() 
public void onStart(Intent intent) 
public void onDestroy()

三.Service 的幾個階段
1.entire lifetime
    在onCreate與onDestroy()之間
    利用onCreate()來作初始化,而在onDestroy()釋放所有資源
    例如音樂播放service在onCreate()時產生thread來播放
    而在onDestroy()停止thread

2.active lifetime
    由onStart()開始,這階段會接收到由startService()傳來
    的intent物件。如果是一個音樂播放的Service會在這階段
    利用取得的intent物件,找到要播放的音樂資料做播放 

無論service是用Context.startService()或Context.bindService()啟動,都會觸發 onCreate()與onDestroy(),但onStart只有是在用 startService()啟動才會被觸發。

四.Bind流程會觸發的事件
如果透過Bind來使用Service,以下事件在過程中被觸發,可以透過實作以下method。
IBinder onBind(Intent intent) 
boolean onUnbind(Intent intent) 
void onRebind(Intent intent)

只要service 啟動後允許其他人來bind,那就會有以下事件會被觸發onBind() onUnbind()

在onBind()被傳入一個來自Activity執行bindService的intent物件。onUnBind()被傳入一個來自Activity執行unbindService()的intent物件。無論service是被用哪種方式啟動,都還是可以隨時去bind(),所以service都可以接收onBind()與onUnbind()事件。

Android Component Lifecycles - Activity(一)

Android內幾種主要元件都有自己的生命週期,在其生命週期的每個階段,都有相對應的callBack method,也就是說當元件在進入該階段時,Android系統就會自動執行該階段的callBack。因此我們可以看到各種元件都會有一些內建的callBack method,如果我們希望在元件的某個階段去執行一些動作,你可以依照需要override認一階段的method

一.Activity的3種狀態(state)
1.active,running
    出現在螢幕的前景,也就是在目前task的activy堆疊的最上層,
    這Activity正被focus並接受使用者的動作
2.paused
    失去了focus,但使用者還是可以看到Activity,其他activity
    在其上方,也許是透明或沒有全螢幕覆蓋,因此paused的Activity
    還可以被看到,一個paused Activy還是在存活狀態(還保有所有資料,
    並被window manager所管理)但在系統記憶體過低時還是可能被砍掉
3.stopped
    當完全被其他的Activity所遮蔽,他是保有一些狀態資料,
    但已經看不到,他的視窗已經被隱藏,當系統記憶體過低會被砍掉

當系統記憶體過低,會將屬於paused與stopped狀態的Activity 砍掉,也就是呼叫其finish()或直接就砍了其process,當要再重新顯示在使用者面前,需要完全restart並restore之前的state 資料

二.Activity LifeCycle Method
當Activity由一個state轉到另一個state的過程中,以下幾個內部method會被自動觸發通知,所以我們若要在特定時間點執行特定動作需要override 相關protected method
protected    void onCreate(Bundle savedInstanceState) 
protected    void onStart() 
protected    void onRestart() 
protected    void onResume() 
protected    void onPause() 
protected    void onStop() 
protected    void onDestroy()

三.Activity 的幾個階段
每個Activity一定要Override onCreate()來作初始化功能,有的會需要override onPause()
去把資料改變記錄下來,以因應可能停止的動作
1.entire lifetime完整生命週期
    一個Activity由onCreate()開始,到最後onDestroy()結束,會在
    onCreate()時做所有初始化的動作,在onDestroy()內釋放所有的
    系統資源。
    例如有一個Thread在背景進行網路資料下載,這thread會在onCreat()
    程序內產生,而在onDestroy()停止這thread
2.visible lifetime
    由呼叫onStart()開始到 onStop()結束,在這過程使用者可以看到
    Activity在螢幕上,在這期間使用者可以看到元件顯示在畫面上,
    但不見得在前景或與使用者互動。
    例如你可以在onStart註冊一個BroadcastReceiver,而在onStop()
    中解除註冊,利用BroadcastReceiver監看UI上的變化,這樣就可
    以觀察到相關的變化,在Activity運作上,onStart()與onStop()
    在進行中可以被多次呼叫
3.foreground lifetime
    由呼叫onResume()到onPause()間,在這區間,Activity在前景,並可
    與使用者互動。Activity經常在這兩個狀態間跳動。    
    例如當Device進入睡眠狀態或另一個Activty要開啟,就會呼叫
    onPause(),而當activity繼續執行,或一個新的intent被發送出來
    Activity內的onResume()就會被呼叫執行

四.Activity LifeCycle Method狀態說明
1.onCreate()
    當activity第一次被產生後,會被執行。
    你可以在這程序內create View,bind data與list,
    在這method被執行時會接收到一個Bundle物件,
    這物件包含了Activity之前的state資料
    
    接下來會執行的有onStart()
2.onRestart()
    當Activity被停止後,又重新啟動時執行(與onStart同)
    接下來會執行的有onStart()
3.onStart()
    在Activity要變成Visible前執行
    
    如果接下來要把Activity顯示在前景,則伴隨著onResume()
    如果接下來要把Activity隱藏,則伴隨著onStop()    
4.onResume()
    在Activity開始與使用者互動前被呼叫
    在這點Activity是在Activity堆疊的最頂端
    
    接下來的會是onPause()
5.onPause()
    當系統要啟動其他Activity,這程序會被呼叫,
    在這程序中需要去處理,把尚未儲存的資料儲存下來,
    停止動畫與其他會消耗CPU的動作,這過程需要非常快速,
    因為下一個Activity會等他return才會執行
    
    若接下來這Activity要回到前景,接下來的會是onResume()
    若接下來這Activity要變隱藏,則接下來會是onStop()
6.onStop()
    當Activity不再讓使用者看到時呼叫
    可能發生在這Activity準備要destroy或是其他的Activity
    回復到前景
    
    假使這Activity要回到前景,接下來會是onResume()
    假若這Activity要整個關閉,接下來會是onDestroy()
7.onDestroy()
    當Activity被Destroyed前被呼叫
    這會是這Activity最後一個接收到通知,
    他可能發生在呼叫了finish()之後,或因為系統因為記憶體
    不足要節少空間而刪除,可以利用isFinishing()來判斷是
    什麼原因造成    

五.儲存Activity state
若要在Activity被關閉重開啟後,可以保留之前的狀態,
可以實做onSaveInstanceState()把資料存下來,儲存到Bundle物件上
而在重啟後讀出來
其相關順序為
onSaveInstanceState()->onPause()
onStart()->onRestoreInstanceState() 
在這過程中只儲存過渡性的資料,不要儲存固定的資料,因為onSaveInstanceState並非會一直被執行到

Monday - God Is an Astronaut

星期一的早上
天氣是舒服的秋涼
有太陽
上班的路上 也沒有太壅塞的車潮
辦公室裡 陽光溫暖 也明亮

一早的電話 帶來了幾許煩躁
打壞了原本的美好

打開音樂
用God Is an Astronaut來恢復平靜

2010年10月21日 星期四

AndroidManifest 設定檔- 基本概念

一.說明
在每個Android Application內一定會在Project根目錄下配置一個AndroidManifest.xml檔案
這檔案提供以下幾個作用
1.設定這個Application的Java Package Name
  也就是設定一個Java Package路徑用來代表這個Application        
2.設定組成這App的所有元件
  包括Activity,Service,ContentProvider,BroadCast Receiver等,
  開發好的元件都需要註冊在這Manifest檔案內,如果沒註冊在這裡,
  元件無法被使用。除了註冊元件,並利用Intent Filter讓Android
  知道在什麼狀況可以啟動哪個元件        
3.決定哪些程序將可以控制元件
4.宣告了App需要有哪些權限去取得被保護的資料或執行其他App的元件功能      
5.宣告了本App允許讓其他App互動的權限    
6.提供執行中Instrumention Classes清單與相關資料
  這些資料只有開發階段會存在,發布後會被移除
7.宣告了這App執行所要求的最低Android API版本        
8.設定這App需要連結的API Libraries
    除了預設使用Android API外,可以利用設定<uses-library>
    使用其他package的元件功能API
二.語法原則
1.element
1.<manifest> and <application>只能出現一次,其他的都可以出現多次
2.<activity>, <provider>與<service> 可以沒有順序性的出現在任何
  地方,但<activity-alias>一定要跟在<activity>後面
2.attribute
所有的屬性都是非必填的選項,除了manifest外,所有元素的屬性一定都是以android:命名
3.Class name
在Manifest內,多數的元素都直接對應到Java Class,包括application本身
如activities (activity), services (service), broadcast receivers (receiver)
與content providers (provider)


如果要在Manifest內加入這幾個class的subclass,subclass,則在name屬性上,
輸入完整的Class名稱(包括package name)
例 加入一個繼承自Service的subClass SecretService
 <manifest . . . >  
      <application . . . >  
           <service android:name="com.example.project.SecretService" . . . >  
                . . .  
           </service>  
           . . .  
      </application>  
 </manifest>  

如果這subClass是在這Application的package下,則在name屬性上
只要用.ClassName方式設定即可,系統看到.name會自動將Ap的package 加上去

 <manifest package="com.example.project" . . . >  
      <application . . . >  
           <service android:name=".SecretService" . . . >  
                . . .  
           </service>  
           . . .  
      </application>  
 </manifest>  

當要啟動這元件時,若這subClass存在,系統會產生這subclass(範例是SecretService)的instance使用,
若subclass不存在,則會產生其base class(範例是Service)的instance
4.Multiple values
若一個項目可以有多個值存在,會用多個tag repeat,而不會在一個tag寫入多個值

 <intent-filter . . . >  
      <action android:name="android.intent.action.EDIT" />  
      <action android:name="android.intent.action.INSERT" />  
      <action android:name="android.intent.action.DELETE" />  
      . . .  
 </intent-filter>  
5.resource value
會需要用到resource 當作屬性值時會以
[package:]type:name表示
若是來自於style theme的值則會是
?[package:]type:name
6.String values
當屬性值為字串會用到\\當跳脫字元,例\\n 換行

三.幾項元素功能作用
1.Intent Filters
在manifest內,主要的幾個元件如Activity Service...等利用Intent Filter設定對intent的處理能力
也就是說,用Intent Filter描述他可以處理那些intent,在一個元件可以是可以同時設定多組的intent filter。
Android系統在收到intent後可以依此決定要啟動哪個元件來處理intent需求

2.Icons and Labels
許多元素都有icon與label顯示小圖與文字在使用介面上,有的會有description 放比較多的說明文字。
例如在permission上,這三個屬性都有,當Application對系統要求取得權限時,依照提供的permission設定
就可以把這3個屬性的資料顯示在介面上

如果在上層的container上設定icon與label,那麼其子元素的icon與label都會以上層設定
當作預設值

3.Permissions
用來設定去存取Device資料,啟動其他App的元件或是本身元件被其他App使用的權限設定
一個Appication可以用permission保護其元件,所有的Permission都被定義在
android.Manifest.permission Class內,也可以自行定義自己的Permission


 <manifest . . . >  
      <permission android:name="com.example.project.DEBIT_ACCT" . . . />  
      . . .  
      <application . . .>  
           <activity android:name="com.example.project.FreneticActivity"  
                      android:permission="com.example.project.DEBIT_ACCT"  
                      . . . >  
                . . .  
           </activity>  
      </application>  
      . . .  
      <uses-permission android:name="com.example.project.DEBIT_ACCT" />  
      . . .  
 </manifest>  
以上除了定義permission外還要宣告uses-permission讓其他App可以使用這個元件
<permission-tree>:定義一個permissions group的namespace
<permission-group> :定義一組permission的label,純粹只是定義一個名稱
<permission>:若要定義屬於哪個group,則在group屬性設定
     <permission-group>設定的名稱即可

4.Libraries
每個Application預設連結到Android Library,如果要使用其他Library的package
則需要用uses-library宣告

Android Intent Filter-判斷intent傳遞對象

一.Intent接收原理
當使用者發送一個intent出來,要求元件去執行動作,如果這個intent裡有很清楚的設定了ComponentName,那麼intent就會直接被送到指定的元件,並啟動該元件,如果沒有設定,則會由Android系統自動去判斷該把這intent送到哪個元件上啟動他。

大多數在本身專案內元件可以處理的動作,intent通常都會直接指明要給哪個元件處理,如果沒有指定元件名稱的intent大多是用來啟動其他Application上的元件

二.Intent Filter的作用
Android系統如何判斷哪個元件可以接收哪個intent,就是依靠在ManiFest檔案內,宣告元件(Activity,Service)時所加入的Intent Filter設定,每個Activity內可以設定0~多組的intent filter,每一組的Intent Filter都是一份比對規則

當intent發出來時,系統會去檢查Manifest內各元件內的intent filter,而啟動適合的元件,若元件沒有設定filter,那就只能接收到有清楚指定component的intent

三.Intent Filter
Intent filter內會設定的資料包括action,data與category三種。也就是說filter只會與intent裡的這三種資料做比對動作,而在每個filter內可以同時存在著多個data action與category

雖然每個Intent Filter都屬於IntentFilter類別,但因Android系統在元件啟動錢就必需測試其相容性,所以Intent Filter都是以XML方式寫在AndroidManifest.xml檔內,而不以Java Code去產生。唯一的例外是broadcast receivers的intent filter可以透過Context.registerReceiver()來動態設定

Context.registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
在註冊時,把filter動態加入

Intent Filter內要設定的值,包括action,data與category都定義在Intent Class內,也就是說在Intent物件內設定這3種資料的值與Intent Filter內要設定這3種資料的值都定義在Intent Class內,在JavaCode裡,可以透過Class引用參數,但在Manifest內設定,需要設定字串值,就要去查Class內參數實體的字串值

例:Manifest.xml設定filter
 <intent-filter . . . >  
      <category android:name="android.intent.category.DEFAULT" />  
      <category android:name="android.intent.category.BROWSABLE" />  
      . . .  
 </intent-filter>  

JavaCode設定intent Object的Category
intent.setCategory(Intent.CATEGORY_DEFAULT);

四.Intent Test 找到要接收intent的元件
當intent發出來時,會與元件在Manifest內所定義的intent filter做比對,比對時需進行3個test,當這3個test都通過時,才會確認這元件可以接手處理這Intent。若同時有不只一個的Activity或Service通過Test,那系統會問你要啟動哪一個,若都不符合,則會發生錯誤

五.Intent Test-Action Test
1.當一個intent object若沒有指定Action,則這項pass
2.filter內至少要有一項action,若都沒有就沒有任何intent
  可以通過這filter


 <intent-filter . . . >  
  <action android:name="com.example.project.SHOW_CURRENT" />  
  <action android:name="com.example.project.SHOW_RECENT" />            
      . . .  
 </intent-filter>  

六.Intent Test-Category Test
1.若intent有設定Category,必須intent object可以通過所有filter設定
  的Category,Test才會pass
2.若intent沒有設定Category,則設定pass
3.當執行startActivity()而使用沒有明確設定目標的intent,都會當作他
  至少會有一個Category: Intent.CATEGORY_DEFAULT
  (也就是"android.intent.category.DEFAULT")    

因此若Activity要能夠接收到這intent,則在Mainfest內定義這Activity的intent filter部份需要有Category為"android.intent.category.DEFAULT"的值,才會有可能接收到,也就是說在Manifest內的Activity,至少要有Intent.CATEGORY_DEFAUL(也就是"android.intent.category.DEFAULT")的值,而在已經設定為啟動的Activity內多設定Intent.CATEGORY_DEFAUL,也可以但並無用處

在filter內設定category值,需設定完整字串值,這部份查Intent Class,因為在xml tag接受的值是字串,而在Java Code內設定intent的Category就可以用Class的常數去書寫

七.Intent Test-Data Test
每個data tag都包含了URI與data type (MIME media type)
而URI會以scheme, host, port,與 path來表示
也就是可以把一個完整的URI看成
scheme://host:port/path
若host沒指定,則port可略
data type可以用*代表允許任何型態的資料
如text/*" or "audio/*"

URI為
content://com.example.project:200/folder/subfolder/etc

則設定Filter的寫法為
 <intent-filter . . . >  
      <data android:mimeType="video/mpeg" android:scheme="content" android:host="com.example.project" android:port="200" android:path="folder/subfolder/etc"/>   
      <data android:mimeType="audio/mpeg" android:scheme="http" . . . />  
      . . .  
 </intent-filter>  

data在filter與intent內data比對的原則是
1.當filter內沒有設定任何data tag,而intent內也沒有設定URI與data type,
  那這test就通過
2.當filter有設定URI,沒有設定data type,而intent object也是只有URI沒有
  data type,這時候通過,這通常只會發生在mailto: 與tel: 時
3.當filter內只有設定data type 沒有設定URI,而intent object有設定相同
  的data type無URI則通過
4.當filter內設定的data type與URI都與intent Object內設定的對應即通過
  若filter內只有設定data type而URI不設定,只有在intent Object內的
  data type有對應,而URI為content: 或file:才會通過

八.Example
1.設定元件可以顯示local端 任何Image檔案
 <data android:mimeType="image/*" />  
當要由local contentProvider顯示檔案,這樣寫即可,不需再指定URI部份用content:或file:
2.設定允許播放來自internet的任何影片檔
 <data android:scheme="http" android:type="video/*" />  
當使用者透過web page連結要開啟一個資源,會先使用html page開啟看看,若不行,則會與未指定對象
的intent一樣,去查找哪一個Activity適合去開啟這個資源,若不知道,則會開啟Download Manager去下載
3.設定啟動預設執行的Activity
 <intent-filter . . . >  
      <action android:name="code android.intent.action.MAIN" />  
      <category android:name="code android.intent.category.LAUNCHER" />  
 </intent-filter>  
不需透過任何intent去觸發,在開啟App即會自動執行這個Activity

九.Intent與Intent Filter
Intent Filter的作用,不僅是找出intent所要啟動的元件,還包括了設定元件該出現在Device的相關訊息
例如在Filter內設定了
"android.intent.action.MAIN"與"android.intent.category.LAUNCHER"
這元件會出現在device最上層的Launch清單上

若元件的filter設定了android.intent.category.HOME"
那這元件就會顯示在Home screen上

利用PackageManager Class的相關method針對指定intent找出適合的元件
透過query..() method可以讓你找到可以接收指定intent的component
透過resolve..()可以找到最適合接收指定intent的component
例如queryIntentActivities()可以取得所有適合的Activity清單

2010年10月20日 星期三

Android Intent物件

一.說明
在Android內三個核心元件activities, services, and broadcast receivers,都是靠Intents傳遞訊息來啟動

1.啟動Activity
透過將intent放到 Context.startActivity(intent) 或 Activity.startActivityForResult(intent)內來啟動Activity,或取得一個已存在的Activity去執行。另外可透過Activity.setResult(resultCode,intent)取得由呼叫Activity.startActivityForResult()所回傳的資訊

2.啟動Service
透過放intent到Context.startService(intent),去初始化啟動一個Service,亦可將intent傳給Context.bindService(intent),建立元件與service的連線。

3.發布給Broadcast Receivers
將intent物件傳給任何broadcast methods,可以發布給所有有興趣的broadcast receivers,例如Context.sendBroadcast(), Context.sendOrderedBroadcast(), or Context.sendStickyBroadcast()

當有intent被發出時(以上3種方式),Android會找到適合的物件回應這intent,也就是說屬於broadcast的不會去處發到service,而透過startActivity()傳遞的intent只會被Activity接收到

二.Intent Object
intent物件是一個資訊包,他包括了要接收到這intent的元件所會有興趣的資料,如要執行哪些動作,要用到哪些資料
與Android系統所會有興趣的資料,如哪些類別的元件要來接收這intent,與要如何去啟動目標的Activity
一個Intent物件包含以下資訊

1.Component name:ComponentName Class,非必填
指定需要去處理這個intent的Component,這欄位資料為ComponentName 類別,包括這元件的完整class名稱(如com.oz.)與註冊在manifest內的Applcation package name,可利用 setComponent(), setClass(), or setClassName()寫入,用getComponent()讀取

ComponentName cn=intent.getComponent();
cn.getClassName()

2.Action:String,非必填
指定這intent要執行的動作,在Intent Class內已經定義好幾個const代表要執行的動作

ACTION_CALL:初始化phone call
ACTION_EDIT:顯示資料讓使用者編輯
可透過setAction() 設定,利用getAction()讀取,若要使用自己定義的Action sring,使用時需加完整的package路徑
如"com.example.project.SHOW_COLOR"

3.Data:,非必填
包含資料的URI與資料的MIME type,不同的Action會需要不同的data type,譬如說
當action是設定Action_EDIT,data欄位會是需要要編輯的文件URI
當action是設定ACTION_CALL,data欄位將會是一個 tel:電話號碼的URI
當action是設定ACTION_VIEW,data欄位會是http:的URI
接收到的Activity就會去下載顯示這URI

當Activity去處理這些data時,會需要知道他的MIME Type才知道要如何處理
譬如說image檔案就不會有play功能出現

大多數都能由URI去猜測data type,譬如說,content: 的URI,資料會是在device上,可利用setData() setType() setDataAndType()來設定,而利用getData() and the type by getType()來讀取

4.Category: string Set,非必填
設定那一類型的元件可以去處理這個intent,在一個intent內可以放多個Category
以下已經預定的常數為
1.CATEGORY_BROWSABLE:target Activity可以被browswer開啟,
  如email或image
2.CATEGORY_GADGET:這Activity可以嵌在這GADGET的另一個
  Activity內
3.CATEGORY_HOME:Activity會顯示在使用者開啟device的第
  一個畫面,也就是Home按鈕開啟的畫面上
4.CATEGORY_LAUNCHER:Activity會被列在最上層的launcher上
5.CATEGORY_PREFERENCE:target Activity是preference panel
  也就是屬於preference panel才能處理接收這intent 

透過addCategory()加入,透過removeCategory()移除,透過getCategories()取得SET

5.Extras:Bundle類別,非必填
intent要傳遞給元件的其他資訊,會以Key-value pairs型態存在,有一些intent個別會有一些特別的extra資料存在
例如
ACTION_TIMEZONE_CHANGED 會有一個extra 'time-zone',值是最新的time zone
ACTION_HEADSET_PLUG有 'state' 值為"plugged"或"unplugged"
SHOW_COLOR 會有'color' 值為色碼值
可透過一系列的putXXXExtra()設定,getXXXExtra()取得
或用putExtra(Bundle)設定 getExtra()設定取得

在intent裡加入Extra有很多方式
可以先產生一個Bundle物件,把所有要加入的值都放到Bundle內
再利用intent.putExtra(bundle)放進去
也可以利用intent.putExtra(string key,string value)加入
putExtra可以呼叫多次,所有加入的值都會被累加到extra物件上
不管加入多少,都可以透過
如 intent.getExtras().getString(stringKey)方式取得資料

6.Flags:String,非必填
通知Android系統如何去啟動這Activity,例如要把這Activity加入到哪個Task內(或是啟動一個新的Task)在Intent Class內已經建好這些相關常數

Android Resources 資源檔-使用(三)

resourceID的值由兩個部份組成type(如string)與name(如hello)
取得Resource的方式
一.在Java Code中使用resource
1.取得resourceID的語法為
package_name.R.resource_type.resource_name
若在自己專案內package_name可以不用寫

R.string.hello
android.R.color.secondary_text_dark
2.取得Resource Class
利用 Context.getResources()取得Resource Class
再利用Resource提供的各項method來取得各類型的resource
3.範例
例1:
Resources res=Context.getResources();
String str=res.getString(R.string.hello)
例2:
TextView.setText(rsid:int)就可直接使用,用自己找出resources
例3:
imageView.setImageResource(R.drawable.myimage);
二.在XML中使用resource
1.取得resourceID的語法為
@package_name:resource_type/resource_name
如果是在自己專案內的resource就不用寫package_name
在tag內將resourceID指定給tag,tag即會利用resourceID取得資源
2.使用sttle的語法為
?package_name:resource_type/resource_name

2.範例
例1:
 <?xml version="1.0" encoding="utf-8"?>  
 <EditText xmlns:android="http://schemas.android.com/apk/res/android"  
      android:layout_width="fill_parent"  
      android:layout_height="fill_parent"  
      android:textColor="@android:color/secondary_text_dark"  
      android:text="@string/hello" />       
以上範例,textColor用到android內建的資源,所以用@android:color/secondary_text_dark
而text用到是自己專案內的資源,所以用@string/hello
例2:
 <EditText id="text"  
           android:layout_width="fill_parent"  
           android:layout_height="wrap_content"  
           android:textColor="?android:textColorSecondary"  
           android:text="@string/hello_world" />       

三.使用系統內建resource
若要使用系統預設的resource,可用android.R取得
注意:R是本身專案的resource檔案,而android.R是系統提供的預設resource檔


四.執行過程中的異動
當使用者的Device在使用過程中做了變動,譬如說,旋轉或改變語系,系統會因為這樣的改變而將正在進行的Activity進行onDestroy(),然後進行onCreate()重新顯示以套用新的改變。
而在進行onDestroy()前會進行資料儲存動作,好讓重新建立後可以回復資料,其流程如下
onSaveInstanceState()->onDestroy()->onCreate()->onRestoreInstanceState()
其執行方式有以下兩種方式,各有優缺點
1.保留資訊,自動重新啟動
當config改變發生時,允許Activity在自動restart,並把狀態資料帶到Activity新的instance上,若要重新建立新的instance,如果資料來源是來自網路,可能會因為重新建立連線而發生更久的時間。
通常用來儲存狀態用的都是bundle物件,但bundle物件並不適合儲存大量資料(如點陣圖),所以在runtime時要保留資料會是用以下作法
1.Override onRetainNonConfigurationInstance()回傳你要儲存
  的物件,onRetainNonConfigurationInstance()會發生在
  onStop()與onDestroy()之間
2.當create後呼叫getLastNonConfigurationInstance()取回物件

儲存
@Override
public Object onRetainNonConfigurationInstance() {
    final MyDataObject data = collectMyLoadedData();
    return data;
}    
取回
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance();
    if (data == null) {
        data = loadMyData();
    }
    ...
}    
2.取得通知,自己手動處理改變的訊息
當config改變發生時,只發出相關通知,讓使用者自己決定是否要restart,為了效能考量,在部份config發生改變時,並不自動restart Activity,就需要使用者自己手動去處理外觀異動的部份,而無法享受到使用衍生res所帶來的方便
作法如下:
1.先在Manifest內設定Activity要監聽哪些事件變化
2.覆寫onConfigurationChanged(),當有config改變時,
  這裡會接收到新的config物件

manifest.xml
 <activity android:name=".MyActivity"  
       android:configChanges="orientation|keyboardHidden"  
       android:label="@string/app_name">  

Activity內
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
    // Checks whether a hardware keyboard is available
    if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
        Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show();
    } else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
        Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show();
    }
}    

Android Resources 資源檔-Sample與使用範例(二)

一.anim/:XML檔案
定義所有的tween動畫
例:res/anim/hyperspace_jump.xml
 <set xmlns:android="http://schemas.android.com/apk/res/android"  
      android:shareInterpolator="false">  
      <scale  
           android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
           android:fromXScale="1.0"   
           android:toXScale="1.4"   
           android:fromYScale="1.0"   
           android:toYScale="0.6"   
           android:pivotX="50%"  
           android:pivotY="50%"  
           android:fillAfter="false"  
           android:duration="700" />  
      <set  
           android:interpolator="@android:anim/accelerate_interpolator"  
           android:startOffset="700">  
           <scale  
                android:fromXScale="1.4"   
                android:toXScale="0.0"  
                android:fromYScale="0.6"  
                android:toYScale="0.0"   
                android:pivotX="50%"   
                android:pivotY="50%"   
                android:duration="400" />  
           <rotate  
                android:fromDegrees="0"   
                android:toDegrees="-45"  
                android:toYScale="0.0"   
                android:pivotX="50%"   
                android:pivotY="50%"  
                android:duration="400" />  
      </set>  
 </set>  
在Java內使用動畫
ImageView image = (ImageView) findViewById(R.id.image);
Animation hyperspaceJump = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
image.startAnimation(hyperspaceJump);

二.color/:XML檔案
定義colors state list,也就是以一個物件的方式設定在各種狀態時的color變化,如button會有各種state的color變化,可將這樣的color state設定成xml
例:res/color/button_text.xml:
 <?xml version="1.0" encoding="utf-8"?>  
 <selector xmlns:android="http://schemas.android.com/apk/res/android">  
      <item android:state_pressed="true"  
            android:color="#ffff0000"/> <!-- pressed -->  
      <item android:state_focused="true"  
            android:color="#ff0000ff"/> <!-- focused -->  
      <item android:color="#ff000000"/> <!-- default -->  
 </selector>  
在XML Layout上套用到Button上
 <Button  
 android:layout_width="fill_parent"  
 android:layout_height="wrap_content"  
 android:text="@string/button_text"  
 android:textColor="@color/button_text" />  

三.drawable/:bitmap檔案
包括(.png .9.png .jpg .gif),或透過XML檔案所描述的圖形,
如State lists,Color drawables,Shapes

四.layout/:XML檔案
定義使用者使用介面的layout,每一個Layout會相當於我們看到的一個page

五.menu/:XML檔案
定義該App的menu,例如Options Menu, Context Menu, or Sub Menu
例:res/menu/example_menu.xml:
 <menu xmlns:android="http://schemas.android.com/apk/res/android">  
      <item android:id="@+id/item1"  
            android:title="@string/item1"  
            android:icon="@drawable/group_item1_icon" />  
      <group android:id="@+id/group">  
           <item android:id="@+id/group_item1"  
                 android:title="@string/group_item1"  
                 android:icon="@drawable/group_item1_icon" />  
           <item android:id="@+id/group_item2"  
                 android:title="G@string/group_item2"  
                 android:icon="@drawable/group_item2_icon" />  
      </group>  
      <item android:id="@+id/submenu"  
            android:title="@string/submenu_title" >  
           <menu>  
                <item android:id="@+id/submenu_item1"  
                      android:title="@string/submenu_item1" />  
           </menu>  
      </item>  
 </menu>  
在Activity的Java內使用
public boolean onCreateOptionsMenu(Menu menu) {
  MenuInflater inflater = getMenuInflater();
  inflater.inflate(R.menu.example_menu, menu);
  return true;
}

六.raw/:任意檔案用他原本的資料格式儲存
系統不會對檔案做壓縮處理,要開啟這些檔案的InputStream,要透過Resources.openRawResource()呼叫該resourceID(R.raw.filename)取得,若是希望透過原始檔名來取得檔案,建議可以把檔案存在/assets/目錄下
在/assets/目錄下的檔案是沒有resourceID的,都是透過AssetManager來存取

七.values/:XML檔案
包含一些簡單的值設定,如string,color,style,通常會把同類型的寫在一個檔案內
1.arrays.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <resources>  
      <array name="icons">  
           <item>@drawable/home</item>  
           <item>@drawable/settings</item>  
           <item>@drawable/logout</item>  
      </array>  
      <array name="colors">  
           <item>#FFFF0000</item>  
           <item>#FF00FF00</item>  
           <item>#FF0000FF</item>  
      </array>  
 </resources>  

JAVA使用
Resources res = getResources();
TypedArray icons = res.obtainTypedArray(R.array.icons);
Drawable drawable = icons.getDrawable(0);
TypedArray colors = res.obtainTypedArray(R.array.icons);
int color = colors.getColor(0,0);
2.colors.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <resources>  
   <color name="opaque_red">#f00</color>  
   <color name="translucent_red">#80ff0000</color>  
 </resources>  

JAVA使用
Resources res = getResources();
int color = res.getColor(R.color.opaque_red);

XML使用
 <TextView  
 android:layout_width="fill_parent"  
 android:layout_height="wrap_content"  
 android:textColor="@color/translucent_red"  
 android:text="Hello"/>  
3.dimens.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <resources>  
      <dimen name="textview_height">25dp</dimen>  
      <dimen name="textview_width">150dp</dimen>  
      <dimen name="ball_radius">30dp</dimen>  
      <dimen name="font_size">16sp</dimen>  
 </resources>  

Java使用
Resources res = getResources();
float fontSize = res.getDimension(R.dimen.font_size);

XML使用
 <TextView  
 android:layout_height="@dimen/textview_height"  
 android:layout_width="@dimen/textview_width"  
 android:textSize="@dimen/sixteen_sp"/>  
4.string.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <resources>  
      <string name="hello">Hello!</string>  
 </resources>  

JAVA使用
String string = getString(R.string.hello);

XML使用
 <TextView  
 android:layout_width="fill_parent"  
 android:layout_height="wrap_content"  
 android:text="@string/hello" />  
5.style.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <resources>  
      <style name="CustomText" parent="@style/Text">  
           <item name="android:textSize">20sp</item>  
           <item name="android:textColor">#008</item>  
      </style>  
 </resources>  

XML使用
 <?xml version="1.0" encoding="utf-8"?>  
 <EditText  
      style="@style/CustomText"  
      android:layout_width="fill_parent"  
      android:layout_height="wrap_content"  
      android:text="Hello, World!" />  

八.xml/:任何其他的xml檔案放在這目錄
以Resource.getXML()讀取,各式的XML設定檔config都放在這目錄下

Android Resources 資源檔-基本概念(一)

一.說明
在Android下會需要用到的各種資源都會放在res/目錄下,包括版面,圖片,文字字串,資料陣列,顏色...等各式實體內容都會放在這目錄下,而在res/下主要了包含以下8個目錄,分別代表8種不同類型的resource
1.anim/:XML檔案,ㄐ定義所有的tween動畫
2.color/:XML檔案,定義colors state list,也就是以一個物件的
  方式設定在各種狀態時的color變化
3.drawable/:bitmap檔案,包括(.png .9.png .jpg .gif)
4.layout/:XML檔案,定義使用者使用介面的layout
5.menu/:XML檔案,定義該App的menu,例如Options Menu, Context Menu, or Sub Menu
6.raw/:任意檔案用他原本的資料格式儲存
7.values/:包含一些簡單的值設定,如string,color,style
8.xml/:任何其他的xml檔案放在這目錄

二.作業原理
在Android將整個專案Compile時,會將所有在res/目錄下的資源都會被Compile成一個R Class,而在res下的各種類型,則會成為R的subClass 如R.string R.drawable都是一個 class 。所以透過R Class可以讓你直接找到資源的resourceID,再利用resourceID來取到resource實體內容。無論資料內容是任何類型的資料,resourceID都只是個int值,而非實體資料內容,要取得實體內容,都需要依照要取得的resource類型,透過resourceID來取得
例如
在res/values/strings.xml內有一筆
 <string name='hello'>測試</string>  
因此R.string.hello即是這筆資料的resourceID,透過getString()才能取得真正的內容
String string = getString(R.string.hello);

三.R下SubClass
R下面的subclass,並非由各目錄的名稱或xml檔案名稱所訂,而是對應到資料類型。譬如說R.string這個次類別,string是來自於strings.xml內有tag,至於這tag所依附的xml檔名,是可以任意的設定(並非一定要設成strings.xml)
也可以把不同類型的資料放到同一個xml檔案內,只是通常會把相同資源放在同一個xml檔案內,方便管理

四.res下更多的衍生類別目錄
除了標準的八種類型目錄外,在res下可以看到更多的其他衍生出來的目錄。
譬如說有layout/ 也可看到layout-land/目錄,這些衍生出來的目錄,都是因應可以讓你開發的應用程式,可以因偵測到使用者device的條件不同,而提供有不同的使用介面與設定,包括解析度尺寸不同,或多語系,都可設定各自的顯視介面,這些目錄名稱的命名都是有規則的,在規則性的命名下,Android系統即會自動判斷要取用哪個目錄下的資源,來顯示在使用者的Device上

例如
在res/下除了有一個 layout/目錄提供標準的版面給使用者外,另外還有一個layout-land/目錄提供給橫向螢幕使用,也就是說當使用者以直式使用時,畫面上是以layout/目錄下的設定來顯示,當使用者把device轉向成橫式時,就會自動切換到以layout-land/目錄下的設定顯示

五.res衍生目錄命名規則
目錄名稱命名方式為resources_name-config_qualifier
resources_name:即原來資源類型的名稱,如string,color,array,...
config_qualifier:依照各類型資源各有不同的值可用
例如:
以Screen orientation螢幕方向來分,config_qualifier允許的值為port直,land橫
res/layout:一般標準layout
res/layout-land:針對橫向時用的layout

幾個常見的config_qualifier包括

1.Language:用來儲存依照不同語系地區所提供的resource
  例 值:en ,fr,tw,cn
  產生的目錄會是
  values-tw/
2.Screen size:螢幕解析度
  值:small,normal,large
3.Wider/taller screens:螢幕形狀,長形或一般
  值:long,notlong
4.Screen orientation:螢幕是直式或橫式
  值:port直,land橫
5.Dock mode:一般或車上模式 
可以用多個config_qualifier串接如 drawable-port-hdpi/,但順序需依照規格書內列表的順序描述

六.res衍生目錄需要用到重複資源的處理方式
當有一份resource(例如圖檔),要給多種設定檔使用,可以不用copy到每個folder各有一份,只需要建立Alias即可,並非所有resource都可提供Alias機制,如animation, menu, raw, 與其他在xml/ 目錄下的都不行
1.drawable 圖檔
例:如果有一張圖檔icon.png原本放在drawable目錄下,要給多個設定檔使用
但又不希望直接copy檔案到各目錄

1.將icon.png rename為 icon_oz.png(只要不是原檔名就好)
將檔案放到drawable/目錄下
2.產生一個icon.xml檔案
 <?xml version="1.0" encoding="utf-8"?>  
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"  
      android:src="@drawable/icon_oz" />  
放到各drawable-xxx/目錄下
3.使用上用
R.drawable.icon可取得
2.layout
例:有一份layout要提供多個設定檔使用
1.將原layout main.xml 改名為main_oz.xml
放到res/layout/
2.產生一個main.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <merge>  
      <include layout="@layout/main_oz"/>  
 </merge>  
放到各目錄下
3.使用上
R.layout.main
3.string或其他
在要alias的項目填上對應資料即可
 <?xml version="1.0" encoding="utf-8"?>  
 <resources>  
      <string name="hello">Hello</string>  
      <string name="hi">@string/hello</string>  
 </resources>  

2010年10月19日 星期二

Android基本概念

一.基本概念
Android Application是使用Java開發,compile成Java code,再利用Appt Tool將相關的resource包裝成apk檔,讓使用者可以下載安裝到他的device上,每個Application會以下列方式在系統執行。
1.每個App跑自己獨立的Linux Process,在不使用時關閉
2.每個Process有自己的VM,所以Ap是在一個完全隔離的環境下運作
3.預設每個App指定一個唯一的Linux user ID,App file只允許該
  App與該User使用,若要讓不同的App共用資料則要設定相同的
  User ID

二.元件
Android一個相當重要的特性是,每個App內包含了許多的元件,每個元件的功能都可以提供其他的App使用,你所開發的App想要使用其他App已經開發好的功能元件,不需要在程式內全部包進來或是去link它,也就是說系統會自行判斷,可以任何需要的時候去啟動任何Application的任何部份功能。

Android App並沒有一個單一的程式進入點(如main()),而是存在著以下四種元件,在必要時就實體化來使用執行
1.Activities
    每個Activity都繼承自Activity Class。
    Activity負責提供使用者介面讓使用者操作與互動。
    一個App可以包含一到多個Activity,在App起始時啟動,一個
    Activity,再由已開啟的Activity去開啟其他的Activity。
    每個Activity都會包含一個Window用來顯示畫面,預設window會
    填滿整個screen(手機),但window可以設定的更小或浮動在其他
    window上,例如popup window,window上所放的物件都是繼承自
    View Class,每個view都佔據著window內的一個矩形區塊,上層
    的view負責其子元素的layout安排,而最底層的child view則負
    責直接回應使用者的動作與輸入,利用Activity.setContentView()
    設定Activity最上層使用的View
    
2.Services
    Service提供一個可以在背景定時執行,無使用者介面的服務。
    譬如說在背景播放音樂,或是在internet上取得資料提供給
    Activity使用。    
    
3.Broadcast receivers
    繼承自BroadcastReceiver Class
    Broadcast receiver 是用來接收廣播的訊息並做回應,許多的
    廣播是來自於系統,譬如說時區改變、電池電力不足或使用者改
    變語系等,另外廣播也可來自於App的其他元件所發出來,例如
    App在下載完資料可以提供給其他App使用時,可以透過廣播讓其
    他App的Broadcast receiver可以接收到並使用
    
    Broadcast receiver沒有UI,但他可啟動Activity去顯示回應,
    或使用NotificationManager去提示使用者。
    Notification可以是device振動、或是閃爍...播放音效等可以
    吸引使用者注意,通常都會在螢幕上放一個icon,當Broadcast
    receiver接收到訊息要提示使用者,可以用NotificationManager
    讓icon有所變化    
    
4.Content providers
    繼承自ContentProvider
    Content provider提供可以讓其他App使用的data,data可以用
    file或sqlite形式儲存,提供讓其他App可以讀取與儲存資料的
    方法。App並不能直接呼叫ContentProvider的method,而是需要
    透過ContentResolver物件來呼叫ContentProvider。
    ContentResolver可以跟任何的ContentProvider做溝通,利用他
    來管理內部程序上的溝通

三.使用intent啟動元件
除了ContentProvider是透過ContentResolver來驅動使用外,其他三種元件的啟動都是透過Intent來啟動,一個intent物件是包含了要執行的內容資訊。對activities 與 services來說,intent包含了要執行的action與要用的data URI,譬如開啟圖片的連結位置等資訊,對Broadcast receiver來說,包含了要發布的action,例如當相機按鈕被按下時,將這按下按鈕的訊息發布給接收者

以下是各種元件的啟動方式
1.Activity
    透過傳遞intent物件給Context.startActivity()來啟動。接收
    到這intent的Activity,在Activity內可以透過getIntent()取
    得該intent資料。    
    一個Activity通常是由另一個Activity所觸發,如果在觸發的
    Activity後想要得到回傳資料,則改用
    Activity.startActivityForResult()來啟動Activity。
    例如要啟動另一個Activity讓使用者可以選取圖片,當使用者
    選好後,希望把選好的圖片回傳回來,回傳的資料會是用intent
    物件被回傳到原呼叫者的onActivityResult()內
2.Service
    透過傳遞intent到 Context.startService()內或是呼叫Service
    的onStart()來啟動Service。
    同樣的可以將intent傳給Context.bindService()在元件與Service
    間建立一個持續性的連線,當建立連線時,系統即會自動觸發
    Service內的onBind(),同時把intent物件丟給onBind(),若在呼
    叫onBind時,若還沒建立連線,則會自動呼叫bindService()建立,
    接下來就可以使用Service本身的method來用
3.Broadcast receiver
     透過傳遞intent到Context.sendBroadcast()、Context.sendOrderedBroadcast(),
     與Context.sendStickyBroadcast(),就可以把intent包好的訊息
     廣播出去,系統就會自動觸發有興趣的Broadcast receiver內部的
     onReceive(),同時onReceive()會接收到這個intent物件在做後續
     的處理程序    

四.關閉元件
ContentProvider只回應ContentResolver的需求,Broadcast receiver只在回應廣播時啟動,所以這兩種元件都不需要手動去關閉它,需要被關閉的元件只有Activity與Service。
1.Activity本身可透過finish()來關閉,而要關閉其他的Activity,
  例如利用startActivityForResult(),所啟動的Activity可以利用
  finishActivity()來關閉其他Activity
2.service本身可以透過stopSelf()關閉,或由外部透過
  Context.stopService()關閉,當元件已經不再被使用或當系統記
  憶體不足時會被強制關閉
五.manifest設定檔
一個Android程式包含了許多的元件還有resource檔案,在Android使用之前,需先確認資料的存在,每個App內都會有一個結構性的描述檔 AndroidManifest.xml,包含了包括activity,service,receiver,provider 等元素宣告,activity,service,provider若沒宣告在manifest檔案內,在系統內是無法使用的,只有receiver除了可以宣告在manifest內,也可以透過Context.registerReceiver()動態產生註冊到系統內

2010年10月1日 星期五

Air File實體檔案路徑

在開發AIR專案,如果需要利用File對使用者端做檔案存取
取得需要的實體檔案路徑,需要透過File的static變數來取得
以下是各變數所對應在Windows下的實體檔案位置

1.File.userDirectory:使用者目錄
C:\Documents and Settings\username

2.File.applicationDirectory:AIR APP執行檔所在路徑
D:\MyAirApp
3.File.applicationStorageDirectory:使用者本機可供該AIR應用程式,儲存資料的路徑
C:\Documents and Settings\username\Application Data\MyAirApp\Local Store

4.File.desktopDirectory:使用者桌面
C:\Documents and Settings\username\桌面

5.File.documentsDirectory:使用者我的文件資料夾
C:\Documents and Settings\username\My Documents

2010年9月27日 星期一

Flex 使用fxg

要在Flash CS5內將圖檔輸出成fxg檔案,供Flex使用,以下步驟流程

一.Flash FXG輸出

在Flash上繪製圖片,可繪製多個物件同時輸出,Export Image,
選擇fxg格式,即自動產生FXG File
如果flash內的物件有使用到外部的圖檔,那麼在輸出fxg檔案的同時,
會產生一個asset目錄,包含外部點陣圖檔案
例如MyBall.fxg
在所輸出的fxg檔案內可看到
 1.<Graphic viewWidth viewHeight>:  
     <Graphic>為fxg document的root node,viewWidth   
     viewHeight即為flash所設定的stage大小  
 2.<Library>:當場景上有多個物件會被定義到Libray內,  
     可以重複使用裡面所定義的物件       

二.放置到Flex可連結到的目錄
可將輸出的fxg檔案放置到Flex對應的class Path內
例如 com/ozzysun/flex/fxg/MyBall.fxg
就可把fxg看作在nameSpace com.ozzysun.flex.fxg下的一個物件類別

FXG本身是一個獨立的文件,其內部不可參考到別的fxg或mxml檔案
但可以連結到點陣圖或是系統字型

三.在Flex Application使用fxg物件

fxg物件只能被加到spark container內,不能加到mx container內
  <s:Application backgroundColor="0xFFFFFF"     
    xmlns:s="library://ns.adobe.com/flex/spark"  
    xmlns:oz="com.ozzysun.flex.fxg.*">  
      <oz:MyBall id="graphic1"/>  
   </s:Application>  

四.在ActionScription上使用fxg物件

在AS中fxg物件會被當作是park.core.SpriteVisualElement物件
並使用addElement加到spark container內

var _item:SpriteVisualElement=new MyBall();
vGroup.addElement(_item);

五.FXG Document語法架構

fxg檔案以當作文件的根節點,下面可包含0~多個container(如Group)
或繪圖元素(如Rect,Ellipse,BitmapImage)
根節點下可以包含有,若有,一定要放在其他tag之前
如果這兩個tag都有,那就把放在第一位

六.FXG的座標與大小控制

fxg使用可以使用兩種座標系統,document coordinater與user coordinater
document coordinater是以整個輸出的swf左上方為參考點
user coordinater則是以這個fxg document的tag為參考點
預設fxg內部元素都會使用user coordinater

每個fxg內部元素都會有width height屬性可以設定,而在根節點上的
viewWidth viewHeight為整個fxg元件大小,如果內部元素寬高小於viewWidth viewHeight
就會出現空白間距

2010年9月23日 星期四

颱風 回家

高鐵左營站擠滿了要北上的乘客
坐在車廂裡看個車子緩緩的移動

早上8點半,硬是把還在睡覺的這對母女挖起來
妹妹張開眼笑笑後,還是繼續抱著被子翹著屁股賴床
好不容易讓他有點醒過來的感覺
就要出門坐車

這個假日自己一個人要把妹妹帶回高雄
塞滿的背包裡除了自己的筆電
還多放了妹妹的畫板 還有那黃色的小鴨鴨
一桶的小饅頭餅乾 一瓶泡好的牛奶再加上一瓶水
我們在回家的路上

南下列車 車廂沒有坐滿
跟妹妹在最後一排的座位上 一路玩回左營
坐計程車回家,車進巷子內
遠遠看到老媽就在門口等著我們回來
還沒下車
看到遠遠的阿嬤
妹妹就阿嬤阿嬤的叫著

妹妹還是跟在台北一樣 精神超好 不會想睡覺
到樓上 把妹妹的車車拿下來
外面鄰居的小朋友 已經等著跟妹妹玩
果然他回來 一點都沒不適應 想媽媽的問題

禮拜天 雨變大了風也變強了 這是今年第一個有影響的颱風
關在家裡不能出門 看樣子沒辦法回台北
除了睡覺 就是跟妹妹玩
還有就是老媽煮的飯菜 整天吃不停
難得 可以好好的睡一覺
躺在 老家的床上 還是感覺比較溫暖
看著妹妹在調皮搗蛋
老媽也被逗的開心的一直笑著

下午風雨更大了
妹妹吵著要出去
只好把鐵門打開一些
放個小椅子在門口
讓妹妹好奇的看到外面下雨的景象
妹妹 好奇的把腳伸到門外 吹著風淋著雨
臉上盡是開心的笑容

這次的颱風 雨下了一天一夜
家裡的鐵門門柱也被風吹開來
看到新聞才知道 整個高雄受災是如此嚴重

禮拜一早上一早搭計程車到左營
再搭高鐵回台北
坐上車
開始會想念妹妹了
想念他叫爸爸的聲音

2010年9月16日 星期四

PHP Send Mail

$to = 'user@xxx.com' . ', ';
$subject = '信件標題';
$message = '內容';
$headers  = 'MIME-Version: 1.0' . "\n";
$headers .= 'Content-type: text/html; charset=utf-8' . "\n";
$headers .= 'From: sender@xxx.com' . "\n";
if(!mail($to, $subject, $message, $headers)){
    die("send error!");
}else{
    echo "send mail ok!";
} 


如果$from $to $msg資料是透過$_POST或$_GET取得
則需加""處理
mail("$to", "$subject", "$message", $headers)

2010年9月10日 星期五

My Wish List

等我有錢 我就買給你
等我有錢 我就送你~~~
如果有錢我要買~~~
我的Wish List好像越來越長
能實現的機會越來越小

還記得自己幾年前的生活
想要買個電腦,去領個錢就買了
買個PS2 嗯嗯...下個月領薪水就可以買了
需要個硬碟....馬上衝去光華商場敗了下來
離現在最近 敗的奢侈品 大概就是那台
手把已經已經壞掉的Wii了.....還是因為太少在玩
讓電池漏液弄壞手把~~

現在要養家養小孩
生活除了忙 還是忙
假日的娛樂 大概就是去24小時紅茶店寫程式
沒時間玩電動,電影也只能等到小孩睡覺後才能好好看完一部
PS3出來了....看起來我是沒什麼興趣
也許新的XBox360出來 搭配新的Kinect出來 會想體驗看看

想買台Android手機,有個好理由是把自己寫的程式放上去測試
但還是跟自己說,還是等Android2.2出來再買吧...

買個硬碟吧,理由是該把電腦內的資料好好備份下來
家裡那台用了5年的電腦也該換了

再買台AIO的觸控電腦送給老爸吧....
現在老爸對電腦這麼有興趣在學
那麼大的AIO電腦,應該會比現在給他用的那台老舊筆電好很多

買台可以看漫畫的平板吧,現在的平板發展已經可以達到我想要
看漫畫的理想了,但是我有時間看嗎

想去日本,又到了有年假又可以看楓紅的季節
但是今年的日圓升值,要存錢去日本,應該是很困難
好想好想~~~~

想買雙勃肯鞋,之前在德國買的勃肯壞了,好想再買一雙
....這大概是最容易實現,也最不會買了有道德愧疚的一個了

今天早上又多了一個大的Wish,想帶著家人到再到德國走走
還要去上次沒去的布拉格...
當然要是妹妹可以很乖的一起出遊的條件下
我想這是現在最大的一個願望吧...

如果哪天真中了統一發票
還是中了樂透
就可以一次都把他完成
現在就先放在口袋裡~~

Flash跨網域JS注意要項

在Flash程式開發應用於網頁上時
常會需要用到與JS的互動,也就是呼叫JS或被JS呼叫
抑或載入外部檔案等,如果發生跨網域的狀況
常會讓工作無法順利執行下去
以下幾點概念可以讓CrossDomain問題,降到最低

1.swf所屬網域,以其所在網頁為準
當你在A網域放了一個網頁A.htm,在這網頁內連結了B網域上的
swf與JS File,如果你在執行的A.htm上的flash有呼叫到了JS上的
function,雖然swf與JS實體檔案同在B domain上,但是在這時候,會被視為非
同一個Domain

2.讓Flash呼叫外部script function
在網頁上嵌入Flash的Tag 有一個參數allowScriptAccess預設值為SameDomain
亦即允許swf與同Domain上的JS做互動,若需要跨網域呼叫執行,則需要將值設定
為always,例如在A Domain上的swf被嵌入到B Domain上的網頁上時,要讓他可以
執行在A Domain上的JS Function,就需要做always設定
但通常在安全性考量,大部分允許讓你貼embed code的網站都會把這個參數忽略掉
而如果要完全不允許flash與script做互動,則可以設定成none

3.讓Flash可以讓script呼叫執行
如果要讓JS可以操作執行Flash內的function
當然是利用ExternalInterface來連結,但若是涉及跨網域的呼叫執行
則需要先在Flash內設定
Security.allowDomain(設定允許的domain)
這樣就可以允許跨網域被呼叫了

4.載入跨網域外部檔案到flash內
要載入非同網域的圖片或檔案到flash內,需要在提供被讀取資料的網站下
放置crossdomain.xml這policy file,然後在flash內使用
Security.loadPolicyFile(policy file路徑),
先讀取,接下來就可以任意的讀取該網站上的資料