2011年4月8日 星期五

SD card read/write功能

SD card read/write功能
功能:讀寫SD card

AndroidManifest.xml
    加入權限"android.permission.WRITE_EXTERNAL_STORAGE"

 Xxx.java
    // Write
    private writeToSdCard() {
        File vSDCard= null;
        try {
            // 獲得外部外接裝置位置
            vSDCard= Environment.getExternalStorageDirectory();
 
            // vSDCard.getParent() - "/" ; vSDCard.getName() - "sdcard"
            FileWriter vFile = new FileWriter(vSDCard.getParent() + vSDCard.getName() + "/Log.txt", true);
            // 使用這種方式有可能會得到錯誤的路徑,所以改用下面的方式
            // vSDCard.getAbsolutePath() - 擷取目前位置路徑
            FileWriter vFile = new FileWriter(vSDCard.getAbsolutePath() + "/Log.txt", true);
    
            // write the data to file
            vFile.append("," + status + "," + level + "," + "\n");
            vFile.close();
        }
        catch (Exception e) {
        }
    }

    // Read
    private void readFromSdCard() {
        File vSDCard= null;
        try {
            // 獲得外部外接裝置位置
            vSDCard= Environment.getExternalStorageDirectory();
 
            // read data form sd card file
            FileReader vFile = new FileReader( vSDCard.getAbsolutePath() + "/sd_test.txt" );
            StringBuffer sb = new StringBuffer();
            int c;
            // if value = "-1", it mean the end of the file
            while ((c = vFile.read()) != -1) {
                sb.append((char) c);
            }
            vFile.close();
        }
        catch (Exception e) {
        }
    }

Timer物件

Timer物件
可以用來排定"排程",在設定的週期裡重複執行
使用到HandlerMessage物件

    // 新增Timer Task
    public void OnCreate (Bundle bundle) {
        ..........
        timer = new Timer();
        // 這裡的時間以毫秒(ms)為單位
        timer.schedule(new mytask(), 1, 1000);
        start_time = System.currentTimeMillis();
    }

    public void OnDestory () {
        super.onDestory();
        timer.cancel();
    }

    private class mytask extends TimerTask {
        public void run() {
            Message message = new Message();
            message.what = 1;
            mHandler.sendMessage(message);
        }
    }

    private Handler mHandler = new Handler(){
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                Toast.makeText(
                    BattService.this,
                    String.valueOf((System.currentTimeMillis()-start_time)/1000) + "s",
                    Toast.LENGTH_LONG).show();
                record_log();
            }
        };
    };

BroadcastReceiver物件

BroadcastReceiver物件
有部分資訊,會經由Android系統透過廣播的方式傳送給應用程式或服務。
而BroadcastReceiver就是用來接收這一類訊息的物件

    // 加入filter,選擇要receiver的對象
    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_BATTERY_CHANGED);
    registerReceiver(mBroadcastReceiver, filter);

    // BroadcastReceive(以電池為例)
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
                switch (intent.getIntExtra("status", 0)) {
                case BatteryManager.BATTERY_STATUS_UNKNOWN:
                    bat_status = "unknown";
                    break;
                case BatteryManager.BATTERY_STATUS_CHARGING:
                    bat_status = "charge";
                    break;
                case BatteryManager.BATTERY_STATUS_DISCHARGING:
                    bat_status = "discharge";
                    break;
                case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
                    bat_status = "not_charge";
                    break;
                case BatteryManager.BATTERY_STATUS_FULL:
                    bat_status = "full";
                    break;
                }
   
                bat_level = intent.getIntExtra("level", 0);
            }
        }
    };

    // close when leaving
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mBroadcastReceiver);
    }

設定Brightness功能

設定Brightness功能
在提及設定Brightness功能之前要先介紹一下目前Android設定Brightness的方式。
目前Android設定Brightness的方式大致上分為二種:
1. 調整目前AP的亮度,離開AP會返回系統設定亮度
2. 調整系統亮度,但是設定值要在亮度有被修改時才會更新
    例如:進入設定亮度頁面,再離開,或修改AP亮度。

若要在AP裡設定系統亮度,則需要使用到上述二個部分。
相關程式碼如下:

AndroidManifest.xml
    加入權限"android.permission.WRITE_SETTINGS"

Xxx.java
// 可以利用SeekBar物件當作設定值的輸入
// 修改系統亮度設定
    // 先將亮度設定模式調整為手動
    Settings.System.putInt(
        getContentResolver(),
        Settings.System.SCREEN_BRIGHTNESS_MODE,
        Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
    // 修改系統亮度設定 (setting rage : 0~255)
    Settings.System.putInt(getContentResolver(),Settings.System.SCREEN_BRIGHTNESS,value);

    // 修改目前視窗亮度 (setting rage : 0.0~1.0)
    WindowManager.LayoutParams lp = getWindow().getAttributes();
    lp.screenBrightness = value/255f;
    getWindow().setAttributes(lp);

*當設定值0時,會造成Android系統將整個螢幕關閉的問題。

Rotation問題

Rotation問題
問題:
在Android的系統裡,當Activity在執行的狀態下,旋轉螢幕,系統會將Activity關閉,重新啟動。當這種情形發生時,有可能會造成目前狀態下的資料遺失。

解決方案:
目前提供二種解決方法:
1. 當旋轉事件發生時,利用SharedPreferences物件將參數儲存,然後在重新啟動時再將參數重新導入。

// 偵測旋轉的動作
    // 在AndroidiManifest.xml的activity裡加入下面程式碼
    AndroidiManifest.xml
    <activity
        ....
        android:configChanges="orientation|keyboardHidden"
        .....
    </activity>

    Xxx.java
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (this.getResources().getConfiguration().orientation ==
            Configuration.ORIENTATION_LANDSCAPE)  {
            // 旋轉方向變為landscape時執行
        }
        else if (this.getResources().getConfiguration().orientation ==
            Configuration.ORIENTATION_PORTRAIT) {
            // 旋轉方向變為portrait時執行
        }
    }

2. 將AP的畫面鎖定在同一方向


    在AndroidiManifest.xml的activity下加入
    AndroidiManifest.xml
    <activity
        ....
        android:screenOrientation="portrait"
        .....
    </activity>

Wake up lock功能

Wake up lock功能
功能:程式執行時,鎖定在Wake up狀態

AndroidManifest.xml
Add "android.permission.WAKE_LOCK" user permission

    private PowerManager.WakeLock wl;

    // 利用PowerManager取得service,設定wake up狀態
    public void onCreate(Bundle savedInstanceState) {
        .............................
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "My Tag");
        wl.acquire();

    }

    // 離開時,釋放控制權
    protected void onDestroy() {
        super.onDestroy();
        wl.release();
    }

2011年4月7日 星期四

Dialog物件

Dialog物件
Dialog物件分成4種:
    AlertDialog, ProgressDialog, DatePickerDialog, TimePickerDialog
這裡只介紹最基本的AlertDialog
其他使用方式可在官網的Dev Gudie - Framework Topics - User Interface - Creating Dialogs查詢

Adding buttons
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder

        .setMessage("Are you sure you want to exit?")
        
.setCancelable(false)
        // 有setPositiveButton, setNegativeButton, setNeutralButton
        
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
           
public void onClick(DialogInterface dialog, int id) {
               
MyActivity.this.finish();
            
}
       
})
       
.setNegativeButton("No", new DialogInterface.OnClickListener() {
           
public void onClick(DialogInterface dialog, int id) {
                dialog
.cancel();
           
}
       
});
    AlertDialog alert = builder.create();

Adding a list
    final CharSequence[] items = {"Red", "Green", "Blue"};
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder
.setTitle("Pick a color");
    builder
.setItems(items, new DialogInterface.OnClickListener() {
       
public void onClick(DialogInterface dialog, int item) {
           
Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
       
}
    });
    AlertDialog alert = builder.create();


Adding checkboxes and radio buttons
    final CharSequence[] items = {"Red", "Green", "Blue"};
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder
.setTitle("Pick a color");
    builder
.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
       
public void onClick(DialogInterface dialog, int item) {
           
Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
       
}
    });
    AlertDialog alert = builder.create();

2011年4月6日 星期三

Button物件

Button物件
大部分用於觸發某項功能時使用
通常會使用到OnClickListener這個事件

OnClickListener為例,下列三種寫法都可以達成同樣的功能
1. 一般標準的寫法
    // Button的宣告
    btn_start = (Button)findViewById(R.id.start);
    btn_start.setOnClickListener(start);

    private OnClickListener start = new OnClickListener() {
        public void onClick(View v) {
            // function
        }
    };

2. 簡化的寫法
    btn_start = (Button)findViewById(R.id.start);
    btn_start.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            // function
        }
    });

3. 使用implements的寫法
    先在Activity implements OnClickListener
    public class sample extends Activity implements OnClickListener {
        .......
        public void OnCreate (Bundle bundle) {
            // import button id
            btn1 = (Button)findViewById(R.id.button1);
            btn2 = (Button)findViewById(R.id.button2);
            btn3 = (Button)findViewById(R.id.button3);
           
            btn1.setOnClickListener(this);
            btn2.setOnClickListener(this);
            btn3.setOnClickListener(this);
        }

        public void onClick (View v) {
            if (v == btn1) {
                .........
            }
            else if (v == btn2) {
                .........
            }
            else if (v == btn3) {
                .........
            }   
        }

Spinner物件

Spinner物件
下拉式選單,需要應用到ArrayAdapter物件

程式碼
    private Spinner spinner;
    private String[] format = new String[] {
        "Item1",  "Item2",
    };

    ArrayAdapter<String> adapter =
        new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, format);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
   
    spinner = (Spinner) findViewById(R.id.spinner);
    spinner.setAdapter(adapter);
    spinner.setOnItemSelectedListener(select);

    private OnItemSelectedListener select = new OnItemSelectedListener() {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int pos, long arg3) {
            // pos代表所選項目的位置,從0開始累加
        }
        public void onNothingSelected(AdapterView<?> arg0) {
        }
    }

另外Spinner的items也可以在main.xml裡宣告
main.xml
    <Spinner
       
android:id="@+id/spinner"
       
android:layout_width="fill_parent"
       
android:layout_height="wrap_content"
       
android:prompt="@string/planet_prompt"
   
/>

String.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
   
<string name="planet_prompt">Choose a planet</string>
   
<string-array name="planets_array">
       
<item>Mercury</item>
       
<item>Venus</item>
       
<item>Earth</item>
       
<item>Mars</item>
       
<item>Jupiter</item>
       
<item>Saturn</item>
       
<item>Uranus</item>
       
<item>Neptune</item>
   
</string-array>
</resources>


public void onCreate(Bundle savedInstanceState) {
   
super.onCreate(savedInstanceState);
    setContentView
(R.layout.main);

    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
        
this, R.array.planets_array, android.R.layout.simple_spinner_item);
    adapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
   

    Spinner spinner = (Spinner) findViewById(R.id.spinner);
    
spinner.setAdapter(adapter);
    ........
}

Service類別

Service類別
Service沒有提供與用戶進行互動的展示層,為一背景執行的程式,一般來說,若是不需要UI操作的程序則可使用Service來完成。

Service一般是由Activity或Context物件來啟動,啟動的方式分為二種:
    透過startService()啟動:啟動後直到Service呼叫自身的stopSelf或stopService時才停止
    透過bindService()啟動:當綁定的Context被銷毀時,停止執行

生命週期如下所示:
程式碼
    public class ExampleService extends Service {
        int mStartMode;       // indicates how to behave if the service is killed
       
IBinder mBinder;      // interface for clients that bind
       
boolean mAllowRebind; // indicates whether onRebind should be used

        public void onCreate() {
           
// The service is being created
       
}
       
public int onStartCommand(Intent intent, int flags, int startId) {
           
// The service is starting, due to a call to startService()
           
return mStartMode;
       
}
        public IBinder onBind(Intent intent) {
           
// A client is binding to the service with bindService()
           
return mBinder;
       
}
       
public boolean onUnbind(Intent intent) {
           
// All clients have unbound with unbindService()
           
return mAllowRebind;
       
}
        public void onRebind(Intent intent) {
           
// A client is binding to the service with bindService(),
           
// after onUnbind() has already been called
       
}
       
public void onDestroy() {
           
// The service is no longer used and is being destroyed
       
}
    }

Intent & Bundle物件

Intent & Bundle物件

Intent
用於應用程式之間的通訊,例如說從一個Activity要呼叫其他的Activity(Server...)

程式碼
    Intent intent = new Intent(Test.this, Test2.class);
    startActivity(intent);
    startService(intent);

另外Intent裡也可以放入"動作"屬性
    Intent intent = new Intent(Intent.ACTION_SEND);
    intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
    startActivity
(intent);

若是需要回傳值的時候可以使用"startActivityForResult()"的方法,如下
    private void pickContact() {
        Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
        startActivityForResult
(intent, PICK_CONTACT_REQUEST);
    }
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       
if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
    
        // coding the function which you want to do
       
}
    }


IntentFilter
當Intent元件之間在傳遞時,若需要告知Android系統自己能夠回應或處理哪些Intent,則可以使用IntentFilter物件。
IntentFilter可以過濾元件無法回應及處理的Intent,只將自己的Intent接收進來處理。
通常應用於Boradcast Receiver元件上。

PendingIntent
在Service裡無法使用startActivity()這種方法,這時候就可以使用PendingIntent這個物件

程式碼
    Intent intent = new Intent(this,Test.class);
    PendingIntent pending =
        PendingIntent.getActivity(
            this, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
    try {
        pending.send();
    } catch (CanceledException e) {
        e.printStackTrace();
    }

Bundle
用來傳送不同程序間的資料,通常與Intent一起使用

程式碼
    Test.java
    Intent intent = new Intent(this,Test.class);
    Bundle bundle = new Bundle();
    bundle.putInt("brightness", value);
    intent.putExtras(bundle);

    Test2.java
    Bundle bundle = this.getIntent().getExtras();
    int value = bundle.getInt("brightness");

Activity類別

Activity類別

Activity是Android裡最常見的一種元件,可將每一個Activity看成一個螢幕,為使用者提供進行互動的可視介面,應用程式可根據需求包含一個或多個Activity,這些Activity一般都是繼承自android.app套件下的Activity類別,而Activity之間的執行是互相獨立的。

Activity的生命週期如下圖所示:
主要分成六個部分:
    onCreate():Activity啟動時執行,通常用來初始化變數及設定Layout
    onStart():Create完之後會到這邊,執行Activity啟動後要執行的動作
    onResume():暫停之後,重新啟動
    onPause():暫停,當不是在最上層顯示時,會執行此程序
    onStop():停止,當程序很久沒有被呼叫時觸發
    onDestroy():銷毀,Activity離開時執行

程式碼:
    public class Test extends Activity {
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.test);
        }
        protected void onStart() {
           
super.onStart();
        }
        protected void onResume() {
           
super.onResume();
        }
        protected void onPause() {
           
super.onPause();
        }
        protected void onStop() {
           
super.onStop();
        }
        protected void onDestroy() {
            super.onDestroy();
        }
    }

一般除了onCreate()以外,其他的都用protected宣告,避免外部其他人使用,造成問題