搜尋此網誌

2015年8月30日 星期日

【Android】Volley - 好用官方的httpclient library

Volley是Gogle在Google I/O 2013所發表的網路框架,主要是為了加強Android網路應用的效能。推出Volley的原因是:
  • 目前廣泛使用的HttpURLConnectionHttpClient有已知的問題和bug是不易修復的,甚至HttpClient可能不再被維護
  • 目前在Android上抓取網路資料的標準作法,是需要透過執行緒,再把結果送回主程序,過程稍嫌複雜
可說是集中非同步的網路通訊優點,同時提供了字串、JSON、圖片三種請求方式。內部再把Http和執行緒封裝起來。還提供Cache,使得在performance上改善不少。
Google建議使用Volley來存取資料量不大且頻繁的網路通訊,Volley在大量資料的傳輸上,效能很差。

目前沒有Google官方提供的Volley封裝檔,建議如下步驟:

String、Json、Image三個的寫法差不多,都是先從URL連結啟動請求之後,將請求加到Queue去處理(請注意,這是非同步的),若成功則在onResponse事件中取得回傳值,若失敗則會在onErrorResponse得到錯誤訊息。

for Gradle

compile 'com.mcxiaoke.volley:library:1.0.19'

Premission (AndroidManifest.xml)

別忘了,Volley 是需要是用網路的,所以記得加上這一行。


<uses-permission android:name="android.permission.INTERNET" />

Example

RequestQueue mQueue = Volley.newRequestQueue(context);

  • StringRequest 
String url ="http://www.google.com";
StringRequest stringRequest = new StringRequest(url,new Response.Listener<String>() {
  @Override
  public void onResponse(String response) {
   Log.d("TAG", response);
  }
 }, new Response.ErrorListener() {
  @Override
  public void onErrorResponse(VolleyError error) {
   Log.e("TAG", error.getMessage(), error);
  }
 });
 
mQueue.add(stringRequest);
  • JsonRequest
String url ="http://my-json-feed";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, "UTF-8",
  new Response.Listener<JSONObject>() {
   @Override
   public void onResponse(JSONObject response) {
    Log.d("TAG", response.toString());
   }
  }, new Response.ErrorListener() {
   @Override
   public void onErrorResponse(VolleyError error) {
    Log.e("TAG", error.getMessage(), error);
   }
  });
 
mQueue.add(jsonObjectRequest);
  • Image Request
String url="http://i.imgur.com/rwTYZzF.png";
ImageRequest imageRequest = new ImageRequest(
  url, new Response.Listener<Bitmap>() {
  @Override
  public void onResponse(Bitmap response) {
   imageView.setImageBitmap(response);
  }
 }, 0, 0, null, new Response.ErrorListener() {
   @Override
   public void onErrorResponse(VolleyError error) {
    imageView.setImageResource(R.drawable.default_image);
   }
  });
mQueue.add(imageRequest);

可稍微改寫一下JsonRequest使得資料更好取得
String url = "http://my-json-feed";
        // 取得資料並編碼
        JsonArrayPostRequest jRequest = new JsonArrayPostRequest(url,
                new Response.Listener<JSONArray>() {

                    public void onResponse(JSONArray response) {

                        //... easy to do something

                    }
                }, new Response.ErrorListener() {

            public void onErrorResponse(VolleyError error) {
                VolleyLog.d(TAG, "Error: " + error.getMessage());

            }
        });
        // 設定執行為最高優先權
  jRequest.setPriority(Request.Priority.HIGH);
        
  mQueue.add(jRequest);

ref:
http://www.androidhive.info/2014/05/android-working-with-volley-library-1/
http://code.tutsplus.com/tutorials/an-introduction-to-volley--cms-23800
https://github.com/mcxiaoke/android-volley
http://blog.csdn.net/guolin_blog/article/details/17482095

2015年8月27日 星期四

【工具】刪除資料夾或檔案出現「找不到此項目」

在筆記本上輸入:

DEL /F /A /Q \\?\%1
RD /S /Q \\?\%1

接著,將檔案名儲存為 .bat的副檔名

將無法刪除的檔案或是資料夾拖曳到此bat圖示上即可

【Android】runOnUiThread vs Looper.getMainLooper().post in Android

ref:http://stackoverflow.com/a/13974916

The following behaves the same when called from background threads
via Looper.getMainLooper()
    Runnable task = getTask();
    new Handler(Looper.getMainLooper()).post(task);
via Activity#runOnUiThread()
    Runnable task = getTask();
    runOnUiThread(task);
The only difference is when you do that from the UI thread since
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}
will check if the current Thread is already the UI thread and then execute it directly. Posting it as a message will delay the execution until you return from the current UI-thread method.
There is also a third way to execute a Runnable on the UI thread which would be View#post(Runnable) - this one will always post the message even when called from the UI thread. That is useful since that will ensure that the View has been properly constructed and has a layout before the code is executed.

2015年8月26日 星期三

【Android】add (vertical) divider/seam to a horizontal LinearLayout?

ref:Add devider or seams between each layouts

【Android】How can I add the new “Floating Action Button” between two widgets/layouts

ref:add the new “Floating Action Button” between two widgets/layouts

Best practice:
  • Add compile 'com.android.support:design:22.2.0' to gradle file
  • Use CoordinatorLayout as root view.
  • Add layout_anchorto the FAB and set it to the top view
  • Add layout_anchorGravity to the FAB and set it to: bottom|right|end

【Android】Android Support Design TabLayout: Gravity Center and Mode Scrollable

簡單來說,問題是

設定tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);

手機直立顯示,Tab在畫面上看起來很正常,超出螢幕的寬度,可以用scroolable解。



當手機橫置顯示時,Tab的總寬度小於螢幕寬度太多,造成視覺上很奇怪,如何解?

答案:

As I didn't find why does this behaviour happen I have used the following code:
float myTabLayoutSize = 360;
if (DeviceInfo.getWidthDP(this) >= myTabLayoutSize ){
    tabLayout.setTabMode(TabLayout.MODE_FIXED);
} else {
    tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
Basically, I have to calculate manually the width of my tabLayout and then I set the Tab Mode depending on if the tabLayout fits in the device or not.
The reason why I get the size of the layout manually is because not all the tabs have the same width in Scrollable mode, and this could provoke that some names use 2 lines as it happened to me in the example.

在不同顯示下,使用不同的顯示方式。
上述解答,應需加
app:tabGravity="fill"
才可以達到想要的效果。

2015年8月22日 星期六

【Note】Personal Blog is worth reading

http://www.lightskystreet.com/
http://frank-zhu.github.io/tools/2014/08/23/android-tools-and-plugin/

【Android】AsyncTask cant be executed twice

問題:
Cannot execute task: the task has already been executed (a task can be executed only once)
http://stackoverflow.com/questions/19345118/async-task-cant-be-executed-twice

解答:
As the exception itself explains, you cannot execute an AsyncTask more than once, unless you create a new instance of it and call .execute.
For example:
async = new AsyncTask();
async.execute();
*in order to execute more than once, you need to re-create the instance (using new) the number of times you want to execute it.
但有人說沒作用

問題:
Android restart AsyncTask
http://stackoverflow.com/questions/11586704/android-restart-asynctask

解答:
改成使用Thread 和 HandleMessage實作
Thank you for all your comments they helped a lot. I decided to do away with the AsyncTask. I ended using a normal runnable Thread and using Handlers to post messages back to the UI thread. here is the code:
        // Start thread here only for IsSocketConnected
        new Thread(new Runnable() {

            public void run() {

                //Add your code here..
                IsSocketConnected();

            }
        }).start();


// handler that deals with updating UI
public Handler myUIHandler = new Handler()
{
    @Override
    public void handleMessage(Message msg)
    {
        if (msg.what == Bluetooth.STATE_CONNECTED)
        {
            //Update UI here...
            Log.d(TAG, "Connected");




            // Discover available devices settings and create buttons
            CreateButtons(btnList);

        } else if(msg.what == Bluetooth.STATE_NONE) {

            Log.d(TAG, "NOT Connected");
        }
}
// in the IsSocketConnected() I call this 
Message theMessage = myUIHandler.obtainMessage(Bluetooth.STATE_CONNECTED);
myUIHandler.sendMessage(theMessage);//Sends the message to the UI handler.
This is working so far. Thank you again. Hope this helps someone