2015年12月29日 星期二

Android 判斷 裝置是否有藍芽 判斷是否有開啟!?

要設權限  
BLUETOOTH             讓程式有權限連接裝置、傳輸資料。
BLUETOOTH_ADMIN 讓程式有權限搜尋裝置及設定藍芽。



BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();//獲得當前的藍芽
if(adapter!=null){
   此手機有支援藍芽
}else{
   此手機無支援藍芽
}

if(adapter.isEnabled()!=true){//如果藍芽未開啟
     //則打開藍芽(會問使用者)
     Intent enabler=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
     startActivity(enabler);

     //則打開藍芽(不問使用者)
      adapter.enable();

}else{
     藍芽已開啟
}
-----------------------------------------------
藍芽名稱:adapter.getName()
藍芽位址:adapter.getAddress()
藍芽adapter狀態:adapter.getState()
adapter.disable();//關閉藍芽
------------------------------------------------
//開放讓別人搜尋自己設備的藍芽300秒
Intent di = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
di.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(di);

2015年12月11日 星期五

在TextView上實作超連結

  1. 在string.xml上先增加一段字串
   1: <string name="herfText"><a href = "www.yahoo.com.tw">YAHOO</a></string>


  1. 在TextView 上設定text
  2.    2:       android:id="@+id/text"
       3:       android:layout_width="wrap_content"
       4:       android:layout_height="wrap_content"
       5:       android:layout_alignParentTop="true"
       6:       android:layout_alignParentLeft="true"
       7:       android:layout_margin="10dp"
       8:       android:textSize="16sp"
       9:       android:text="@string/herfText" />
  1. coding
    1  : title = (TextView)findViewById(R.id.text);
    2: title.setMovementMethod(LinkMovementMethod.getInstance());


如要在同一個TextView 加入多個超連結,  只需將string改為:


   1: <string name="herfText">
   2: <a><a href = "www.yahoo.com.tw">YAHOO</a>\n<a href="www.google.com">GOOGLE</a></a>
   3: </string>

2015年12月9日 星期三

判斷是否有GooglePlayService

if (HXGCMServiceHelper.isGooglePlayServiceAvailable(this, null)) 

public class HXGCMServiceHelper {

    static final private String DB_NAME = "GCMServiceDB";
    static final private String KEY_REGISTER_ID = "registerID";

    static final public int REQUEST_CODE_RECOVER_PLAY_SERVICE = 1;
    static final public int REQUEST_RESULT_CANCEL = 1;


    //region    =   Checking Version    =    static public void registerWithCheckingVersion(Activity activity, String senderID, HXGCMServiceListener listener)
    {
        if (!isGooglePlayServiceAvailable(activity, listener)) return;

        register(activity, senderID, listener);
    }

    /**     * Result code will always return 1 -> cancel. Open it when this situation is solved.     *///    static public void receivedMessageFromOnActivityResult(int requestCode, int resultCode, HXGCMServiceListener listener)//    {//        switch (requestCode)//        {//            case REQUEST_CODE_RECOVER_PLAY_SERVICE:////                if (resultCode != REQUEST_RESULT_OK) listener.userCancelUpdateService();////                break;//            default://        }//    }
    /**     * Will check Google Service is available or not, if not, will present alert.     */    static public boolean isGooglePlayServiceAvailable(Activity activity, HXGCMServiceListener listener)
    {
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();

        int status = googleAPI.isGooglePlayServicesAvailable(activity);
        if (status != ConnectionResult.SUCCESS)
        {
            if (googleAPI.isUserResolvableError(status))    /// Maybe go update.            {
                showErrorDialog(activity, status, listener);
            }
            else {
                if (listener != null) listener.isNotSupportGooglePlayService();
            }

            return false;
        }

        return true;
    }

    static private void showErrorDialog(Activity activity, int code, final HXGCMServiceListener listener)
    {
        GoogleApiAvailability.getInstance().getErrorDialog(activity, code, REQUEST_CODE_RECOVER_PLAY_SERVICE, new DialogInterface.OnCancelListener() {
            @Override            public void onCancel(DialogInterface dialog) {

                if (listener != null) listener.userCancelUpdateAlert();

            }

        }).show();
    }

    //endregion


    static public void register(Context context, String senderID, HXGCMServiceListener listener)
    {
       if (!hasPlayServices(context)) return;

        String registerID = getRegisterID(context);

        //  Already register.        if (registerID != null)
        {
            listener.registerDone(registerID);
            return;
        }

        registerGCMService(context, senderID, listener);
    }

    static public boolean hasPlayServices(Context context)
    {
        return GooglePlayServicesUtil.isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS;
    }

    static private void registerGCMService(final Context context, final String senderID, final HXGCMServiceListener listener)
    {
        new Thread(new Runnable() {

            @Override            public void run() {
                GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
                String regid;
                try {
                    regid = gcm.register(senderID);
                    saveRegisterID(context, regid);

                    if (listener != null) listener.registerDone(regid);

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    static private void saveRegisterID(Context context, String registerID)
    {
        SharedPreferences db = context.getSharedPreferences(DB_NAME, 0);
        db.edit()
                .putString(KEY_REGISTER_ID, registerID)
                .commit();
    }

    static private String getRegisterID(Context context)
    {
        return context.getSharedPreferences(DB_NAME, 0).getString(KEY_REGISTER_ID, null);
    }


    public interface HXGCMServiceListener
    {
        public void registerDone(String registerID);
        public void isNotSupportGooglePlayService();
        public void userCancelUpdateAlert();

        /**         *  Use when update result return from onActivityResult.         *///        public void userCancelUpdateService();    }

}

Intent 標籤 FLAG_ACTIVITY_CLEAR_TOP & FLAG_ACTIVITY_NEW_TASK 用法

FLAG_ACTIVITY_CLEAR_TOP:
 如果設置,並且這個Activity已經在當前的Task中運行,因此,不再是重新啟動一個這個Activity的實例,而是在這個Activity上方的所有Activity都將關閉,然後這個Intent會作為一個新的Intent投遞到老的Activity(現在位於頂端)中。
    例如,假設一個Task中包含這些Activity:A,B,C,D。如果D調用了startActivity(),並且包含一個指向Activity B的Intent,那麼,C和D都將結束,然後B接收到這個Intent,因此,目前stack的狀況是:A,B。
    上例中正在運行的Activity B既可以在onNewIntent()中接收到這個新的Intent,也可以把自己關閉然後重新啟動來接收這個Intent。如果它的啟動模式聲明為“standard”(默認值),
    並且你沒有在這個Intent中設置FLAG_ACTIVITY_SINGLE_TOP標誌,那麼它將關閉然後重新創建;對於其它的啟動模式,或者在這個Intent中設置FLAG_ACTIVITY_SINGLE_TOP標誌,都將把這個Intent投遞到當前這個實例的onNewIntent()中。
    這個啟動模式還可以與FLAG_ACTIVITY_NEW_TASK結合起來使用:用於啟動一個Task中的根Activity,它會把那個Task中任何運行的實例帶入前台,然後清除它直到根Activity。這非常有用,例如,當從Notification Manager處啟動一個Activity


FLAG_ACTIVITY_NEW_TASK:
一個Activity一般通過調用startActivity()啟動並加入到Task中。它同調用者一樣,進入同一個Task。
   然而,如果傳遞給startActivity()的Intent對像中包含FLAG_ACTIVITY_NEW_TASK時,系統會搜索一個新的Task來容納新的Activity。
   通常,如標誌的名字所示,是一個新的Task。然而,並不是必須是。如果已經存在一個Task與新Activity的affinity相同,這個Activity就會加入到那個Task中。如果不是,啟動一個新的Task。
  如果啟動它的acitve和新Activity的affinity相同,那麼新Activity的會進入啟動它的acitve所在的Task.


啟決定性作用的是FLAG_ACTIVITY_NEW_TASK這個flag.
原因是,當我們的打開B時,因為使用了new_task屬性,所以系統就會為B尋找一個最具
affinity的activity(也就是A)如果找到了,系統會將此activity(也就是A)設置為前台狀態,就是background,然後將B歸併到A的Task中去,並且壓入頂(如果B之前已經存在於A的Task中那麼CLEAR_TOP屬性將會把B之上得所有activity清除掉,然後將B壓入棧頂).問題分析到這裡,應該已經很清楚了,也就是說A和B一定具有相同的affinity,查閱文檔發現,因為A和B存在於同一個.apk下也就是同一個package下,所以默認具有相同的affinity.下面貼上affinity的相關文檔:

    什麼是Affinity
在某些情況下,Android需要知道一個Activity屬於哪個Task,即使它沒有被啟動到一個具體的Task裡。這是通過任務共用性(Affinities)完成的。任務共用性(Affinities)為這個運行一個或多個Activity的Task提供了一個獨特的靜態名稱,默認的一個活動的任務共用性(Affinity)是實現了該Activity的.apk包的名字。

當開始一個沒有Intent.FLAG_ACTIVITY_NEW_TASK標誌的Activity時,任務共用性affinities不會影響將會運行該新活動的Task:它總是運行在啟動它的Task裡。但是,如果使用了NEW_TASK標誌,那麼共用性(affinity)將被用來判斷是否已經存在一個有相同共用性(affinity)的Task。如果是這樣,這項Task將被切換到前面而新的Activity會啟動於這個Task的頂層。

這種特性在您必須使用NEW_TASK標誌的情況下最有用,尤其是從狀態欄通知或桌面快捷方式啟動活動時。結果是,當用戶用這種方式啟動您的應用程序時,它的當前Task將被切換到前台,而且想要查看的Activity被放在最上面。


必須在application  設定  android:launchMode="singleTop"

2015年12月8日 星期二

Synchronized 用法

用法

Synchronized使用時,需指定一個物件,系統會Lock此物件,當程式進入Synchrnoized區塊或Method時,該物件會被Lock,直到離開Synchronized時才會被釋放。在Lock期間,鎖定同一物件的其他Synchronized區塊,會因為無法取得物件的Lock而等待。待物件Release Lock後,其他的Synchronized區塊會有一個取得該物件的Lock而可以執行。



1. Synchronized Method
synchronized public void syncMethod() {

}
此種synchronized用法鎖定的物件為Method所屬的物件,只要物件被new出超過一個以上的Instance,就有可能保護不到Method內程式。但如果此物件只會被new出一個Instance,譬如new出來後就放到ServletContext,要用的時候從ServletContext中拿出來執行,就可以避免此情況。
2. Synchronized Static Method
synchronized static public void syncMethod() {

}
此種synchronized用法鎖定的物件為Method所屬的物件的Class,不管被new出幾個的Instance,都能夠保證同一個時間只會有一個Thread在執行此Method。
3. Synchronized(this)
public void syncMethod() {
  synchronized(this) {
    …
  }
}
此種synchronized用法與synchronized method用法一樣,都是鎖定Method所屬的物件本身。
4. Synchronized(SomeObject)
public void syncMethod() {
  synchronized(SomeObject) {
    …
  }
}
此種synchronized用法鎖定的是SomeObject,如果SomeObject是同一個Class的兩個不同Instance,那synchronized區塊內就有可能被同時執行。如果每一個Synchronized的SomeObject都是同一個Instance(或者SomeObject本身就是Static),就可以保證區塊內同時間只會有一個Thread執行。
當使用Synchornized(SomeObject)時,SomeObject本身處於被Lock狀態,但此時其他的Thread是可以去更改SomeObject裡面的值,Lock只是同步化的狀態,不表示不能更改資料。
使用時機
Synchronized的使用時機很難定義,比較常見的情況是,當程式中會取出某一個共用的物件且會判斷物件內容值,再更新物件內容,此情況大部分都需要synchronized保護。