2014年7月9日 星期三

Android 開發 (五十六) Gradle 如何增加lib

Gradle 跟eclipse的行為很不一樣,在eclipse中當我們缺少lib,需要將lib檔加入 libs folder或者加入 android lib中


但是在 android studio中一切都變了,如今...要import library變得更簡單,我們不再需要繁瑣的import 沒用的project,也不需要每次為了幫別人架設環境用半天了

在 Android Studio 中我們可以利用 file -> Project Structure -> Dependencies 增加我們需要的lib


假設我們需要import external的lib,變得更簡單了,以前我們可能必須import一大堆的project到我們的專案中,現在這一切已經不再必要,你只需要知道版本號之後只需要在上面的search欄中填入你的lib 並且點選ok就完成了,舉個簡單的例子,例如我的project想要import eventbus這個功能
我只需要將 
dependencies {
    compile 'de.greenrobot:eventbus:2.2.1'
}
加入我的dependencies中即可,剩下的gradle會幫你解決所有的問題。

真的是超級方便啊,不過最近在0.81 版本上遇到一個問題,

Manifest merger failed : uses-sdk:minSdkVersion xx cannot be smaller than version L declared in library com.android.support:support-v4:21.0.0-rc1

感覺是0.8的bug,看起來是因為gradle設定檔內使用
compile 'com.android.support:support-v4:+' 造成 gradle去使用最新版本的 support-v4 然而最新版本的 support-v4似乎只支援 L, 所以必須將上面的 dependencies 改成  compile 'com.android.support:support-v4:20.0.0' 這樣就解決了。

Android studio真的很方便,而且也進入beta了,如果是寫新app的人可以直接切過來了,至於必須維護舊app的人,這條路也是必經之路,現在這個時間點也是可以考慮切換的時候了,畢竟eclipse真的很麻煩啊XD。

Android 開發 (五十五) GoogleCloudMessaging

最近在玩Gradle的時候意外發現

GCMRegistrar  Is  Deprecated  



我記得在我剛接觸android時...GCM才剛改版過...如今過了不到一年...他又改版了...

雖然說又改版了,不過使用方式並沒有太大的改變。只是新版的register不能在MAIN_THREAD中執行,必須使用async task去做...

附上簡單的執行片段


        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                String msg;
                try{
                    GoogleCloudMessaging gcm;

                    gcm = GoogleCloudMessaging.getInstance(getApplicationContext());

                    String regid = gcm.register(SENDER_ID);
                    Log.d("Ted","id "+regid);
                    msg = "Device registered, registration ID=" + regid;
                } catch (IOException ex) {
                    msg = "Error :" + ex.getMessage();
                    // If there is an error, don't just keep trying to register.
                    // Require the user to click a button again, or perform
                    // exponential back-off.
                }
                return msg;
            }

            @Override
            protected void onPostExecute(String msg) {

            }
        }.execute(null, null, null);

regid 就是server訊息傳送時所需的token,根據sample code的寫法,只有在第一次執行的時候才會執行register 其他時候都是由sharepreference取得之前的regid (這代表著regid不變?這點我很懷疑)。

其他的使用方式跟以前沒太大的差別,有興趣可以參考 Hello GCM
最後附上 sample code

Android 開發 (五十四) 客製化 progress bar

通常內建的progressbar都長的不是非常的好看,假設我們今天想要客製化一個自己的progress bar,



我們可以利用drawable + Animatable 來完成我們想要的客製化progress bar , 主要轉動的部分當然是由animation來完成的,我們只需要利用drawArc,並且使用animation來更改餵進去的參數即可,
    @Override
    public void draw(Canvas canvas) {
        canvas.drawArc(mBounds, mCurrentAngle, 340, false, mPaint);
    }
不斷的call draw並且更改mCurrentAngle造成progressbar轉動的效果

至於改變參數的方法可以參考下面的code

        mObjectAnimatorAngle = ObjectAnimator.ofFloat(this, mAngleProperty, 360f);
        mObjectAnimatorAngle.setInterpolator(new LinearInterpolator());
        mObjectAnimatorAngle.setDuration(ANGLE_ANIMATOR_DURATION);
        mObjectAnimatorAngle.setRepeatMode(ValueAnimator.RESTART);
        mObjectAnimatorAngle.setRepeatCount(ValueAnimator.INFINITE);

這是4.0之後的寫法,在property改變的時候去設定值,並且call invalidateSelf()使得draw被重複trigger


    private Property<MyProgressDrawable, Float> mAngleProperty
            = new Property<MyProgressDrawable, Float>(Float.class, "angle") {
        @Override
        public Float get(MyProgressDrawable object) {
            return object.getCurrentAngle();
        }

        @Override
        public void set(MyProgressDrawable object, Float value) {
            object.setCurrentAngle(value);
        }
    };
    public void setCurrentAngle(Float angle) {
        mCurrentAngle = angle;
        invalidateSelf();
    }

最後附上 sample code

2014年7月2日 星期三

Android 開發 (五十三) material Design 簡介

Android 開發 (五十二) facebook login + Nest Fragment

當使用facebook login,出現偶發無法login 並且查詢status為 opening的時候,就必須注意是否已經踏入了facebook api的坑中。

facebook login api 必須在每個state 中做事情例如

    public void onStart() {       
        Session.getActiveSession().addCallback(this);
    }

    public void onStop() {
        Session.getActiveSession().removeCallback(this);
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
     Session.getActiveSession().onActivityResult((Activity)context, requestCode, resultCode, data);
    }

當我們在Nest Fragment的時候(ex :TabHost+ Viewpager),onActivityResult可能會沒有被呼叫到,
這就會造成login失敗,最好的方法就是不要在Nest Fragment裡做 facebook login,否則就必須想辦法在ParentFragment (通常為TabHost的那個Fragment)中呼叫 子fragment 的onActivityResult
不過這個方法也不能100%的避掉問題,有時候 ParentFragment的 onActivityResult也不會被呼叫到。

所以回到最原始的解法,當必須在Nest Fragment中呼叫login時,還是偷偷開一個fragment或Activity做login的動作吧..

Android 開發 (五十一) facebook SDK 傳送 xmpp訊息 v1.0 facebook before 3.14

要使用facebook 傳送訊息是一個災難,因為能參考的資料非常少,facebook也只說明要使用xmpp來傳送訊息,所以在這邊提供一些Sample給大家參考。

首先先提供 相關檔案
https://drive.google.com/file/d/0B7nu3f_AuGWEM3l3WGJBQXp3R0E/edit?usp=sharing

裡面有三個檔案

這兩個檔案是跟xmpp相關的設定,不需要做修改,直接丟進workspace裡就行了
FacebookChatManager.java
SASLXFacebookPlatformMecha.java

第三個檔案
SendMessageIntentService.java

我這邊是使用background service來傳送 message 如果有仔細去看code會發現在傳送訊息之間我有使用sleep,這是因為我發現不間斷的傳送會讓訊息loss掉,所以使用這個方式(算是暫時可用的解法)

要使用這個功能,首先必須login 並且擁有"xmpp_login"的權限 如果已經login的話可以使用
newPermission來增加擁有的權限

  Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(
    (Activity)context, newPermission);
  newPermissionsRequest.setCallback(statusCallback);
  Session.getActiveSession().requestNewPublishPermissions(newPermissionsRequest);

只需要在newPermission裡面塞入 "xmpp_login"即可

接著稍微看一下 service裡面做的事情


 @Override
 protected void onHandleIntent(Intent intent) {
  // TODO Auto-generated method stub
  nameList = getNameList(intent);
  if(nameList.size()>0){
   message = intent.getStringExtra(MSG_EXTRA);
   FacebookChatManager facebookChatManager = FacebookChatManager.getInstance(this);

   if (facebookChatManager.connect()) {    
    if (facebookChatManager.logIn(getString(R.string.fb_app_id), Session
      .getActiveSession().getAccessToken())) {

     List<String> resultList = facebookChatManager.findSendMessageList(nameList);    
     facebookChatManager.sendBatchMessage(resultList, message);     
    }

    facebookChatManager.disConnect();

   }
  } 
 }

我將message 以及 friend Id 傳進來在connect 完成之後就使用sendbatch的方式將訊息傳遞出去

facebook目前已經有提供新的做法,但是該做法必須安裝facebook messager 詳細的內容可以參考 http://tedforum.blogspot.tw/2014/05/android-facebook-v20314sdk-chat-api.html