Thursday, June 14, 2012

[Note]Android Threads, Handlers and AsyncTask


先看過Processes and Threads會有比較清楚的概念
當Adnroid Application 啟動後, 系統會建一個主要的thread 稱 "main thread" or "UI thread", 所有的components 皆跑在這個UI thread, system calls 也是透過UI thread dispatched給各個component, ex: onKeyDown, touch event.
UI thread 如因大量運算或等待而blocked, 預設超過5秒ANR(Application Not Responding)就會發生.
且Android UI components 並非thread-safe, 使用上要特別小心.
所以:
1. long time computation使用另外的thread, 不要寫在 UI Thread.
2. 不要在UI thread 之外使用UI component method.
透過Thread, Handler and AsyncTask perform asynchronous processing, 避免UI thread block.

Android 提供以下的method, 可在其它的thread 下調用 UI thread.
Activity.runOnUiThread(Runnable)
View.post(Runnable) <-- used in example code.
View.postDelayed(Runnable, long)
或是使用Handler or AsyncTasks class 達到同樣的效果.

* Handler
有2個主要用途:
(1) message scheduling,  post action at specific point.
(2) 將其它thread發出來的action 放入message queue中, 避免race condition.
 
處理message 需要override handleMessage(), 透過sendMessage() or sendEmptyMessage() method.
執行Runnanble則是使用post() method.
一個Activity 只需有一個Handler instance.

* AsyncTask
使用AsyncTask必需繼承它, 且override doInBackground() method.

4 steps:
呼叫execute() 開始執行, 之後onPerExecute()接著自動被呼叫, 通常用來 initial status of task.
接著doInBackground() 被調用, 一般為long time computation時使用.
call publishProgress()後會調用onProgressUpdate(), onProgressUpdate()調用於UI thread, 一般用來update progress bar, UI animate.
publishProgress() trigger時間點是無法預期的.
doInBackground() 結束後會trigger onPostExecute()調用於UI thread, 用來返回結果.
 
* Thread, Handler 在Avtivity 結束後 thread就結束, 但AsyncTack則否.
Ans: 
So, even if AsyncTask finished, thread does not die. But thread in thread pool can be killed.
 
Examples
Layout XML file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/run" />

    <ProgressBar
        android:id="@+id/progressBar1"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp" />

</LinearLayout>
 
Thread example code:
package com.samchen.samdemos.threads;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

public class DemoThreads extends Activity {
    final boolean isThread = true;
    final String TAG = "DemoThreads";
    private ProgressBar mProgress;
    private int mProgressStatus = 0;
    boolean isRunning = false;
   
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.demothreads);

        Button btnRun = (Button) findViewById(R.id.button1);
        mProgress = (ProgressBar) findViewById(R.id.progressBar1);

        btnRun.setOnClickListener(new Button.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                if(isRunning){
                    Log.d(TAG,"thread is runing");
                    Toast.makeText(getApplicationContext(),
                            getString(R.string.running),
                            Toast.LENGTH_SHORT).show();
                    return;
                }else
                    isRunning = true;
               
                if (isThread) {
                    // thread example
                    new Thread(new Runnable() {
                        public void run() {
                            while (mProgressStatus < 100) {
                                // update the bar status
                                mProgress.post(new Runnable() {
                                    public void run() {
                                        mProgress.setProgress(mProgressStatus);
                                        Log.d(TAG, "update mProgressStatus : "
                                                + mProgressStatus);
                                    }
                                });

                                // do something long
                                SystemClock.sleep(500);
                                mProgressStatus++;
                            }
                        }

                    }).start();

                } else {
                    // non-thread example
                    while (mProgressStatus < 100) {
                        // update the bar status
                        mProgress.post(new Runnable() {
                            public void run() {
                                mProgress.setProgress(mProgressStatus);
                            }
                        });

                        // do something long
                        //SystemClock.sleep(500);
                        //if use SystemClock.sleep, system will be crash.
                        try{
                            Thread.sleep(500);
                        }catch (InterruptedException e){
                            Log.d(TAG,"InterruptedException!!!!!!!");
                            e.printStackTrace();
                        }
                        mProgressStatus++;
                       
                    }
                }

            }

        });
    }

}

Handler example:
package com.samchen.samdemos.threads;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

public class DemoHandler extends Activity {

    final String TAG = "DemoHandler";
    private ProgressBar mProgress;
    private int mProgressStatus = 0;
    private Handler mHandler;
    boolean isRunning = false;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.demothreads);

        Button btnRun = (Button) findViewById(R.id.button1);
        mProgress = (ProgressBar) findViewById(R.id.progressBar1);
        mHandler = new Handler();

        btnRun.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (!isRunning) {
                    startProgress(mProgress);
                    isRunning = true;
                } else{
                    Log.d(TAG, "thread is runing");
                    Toast.makeText(getApplicationContext(),
                            getString(R.string.running),
                            Toast.LENGTH_SHORT).show();
                }
            }
        });

    }

    public void startProgress(View view) {
        // Do something long
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (mProgressStatus = 0; mProgressStatus <= 100; mProgressStatus++) {
                    //final int value = i;
                    SystemClock.sleep(500);
                   
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            Log.d(TAG, "update mProgressStatus : "
                                    + mProgressStatus);
                            mProgress.setProgress(mProgressStatus);
                        }
                    });
                }
            }
        };
        new Thread(runnable).start();
    }
}

AsyncTask example:
package com.samchen.samdemos.threads;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

public class DemoAsyncTask extends Activity {

    final String TAG = "DemoAsyncTask";
    private ProgressBar mProgress;
    private int mProgressStatus = 0;
    boolean isRunning = false;
    private updateTask mTask;

    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.demothreads);

        mProgress = (ProgressBar) findViewById(R.id.progressBar1);

        Button btnRun = (Button) findViewById(R.id.button1);
        btnRun.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (!isRunning) {
                    mTask = new updateTask();
                    mTask.execute();
                    isRunning = true;
                } else {
                    Log.d(TAG, "thread is runing");
                    Toast.makeText(getApplicationContext(),
                            getString(R.string.running), Toast.LENGTH_SHORT)
                            .show();
                }
            }
        });

    }

    private class updateTask extends AsyncTask<Void, Integer, Void> {

        protected void onPostExecute(Void result) {
           
        }

        protected void onProgressUpdate(Integer... value) {
            Log.d(TAG, "onProgressUpdate : " + value);
            mProgress.setProgress(value[0]);
        }

        protected void onPreExecute() {
            // TODO Auto-generated method stub
            mProgressStatus = 0;
        }

        protected Void doInBackground(Void... params) {
            // TODO Auto-generated method stub

            while (mProgressStatus < 100) {
                Log.d(TAG, "doInBackground mProgressStatus : "
                        + mProgressStatus);
                // do something long
                publishProgress(mProgressStatus);
                SystemClock.sleep(500);
                mProgressStatus++;
            }
            return null;
        }
    }

}

Sunday, June 10, 2012

Comuptex 2012

這次的Computex show 中Micorsofte主要是強打windows 8系統的 Ultrabook, Tablet , AIO(All in One) PC,
主要大廠ASUS , Acer, Compal, Gigabyte, MSI, Samsung ...等都有展出,
除了這些來看看其它有趣的東西吧.
互動感十足的販賣機, 原本以為是單純的transparent panel 播放動畫,
沒想到是touch panel還可以玩game, AUO的面板,
當然這麼大的面板用的是光學觸控(Optical touch).
 
LITEMAX(晶達光電) 的 Spanpixel Resizing LCD透過獨特的面板切割技術, 提供非一般標準比例的LCD顯示器.
做為特殊工業應用, 車站、購物中心,公共資訊...等的顯示應用.
今年掛牌上市的公司, 電子廣告看板模組似乎有不錯的潛力.

讓我想到Always Innovatin 的 HDMI Dongle
家裡的舊電視只要有HDMI port就可以升級成SmartTV,
後來得知國內有几家公司有在做類似的產品, 似乎也是不錯的商機.

Genius 在2011年推出全球首款Ring Mouse, 今年又推出新一代的Ring Presenter.
用的是2.4GHz無線.

Rabbichant 2.0
規格如下:
CPU: AMD G-Series T56N Dual Core
GPU: AMD Radeon HD6320
Screen: 10.4" XGA color LCD(1024x768), touch panel
Memory: 4GB DDR3 memory
Storage: 32GB SSD Drive
Wireless: 802.11 b/g/n, Bluetooth interfaces
LAN: Gigabit Ethernet
Camera: auto-focus CMOS 5.0 megapixels
Battery life: 2.5_3 hours (2 batteries)
Weight: 1.75kg (with 2 batteries)
精傑電子, 主要強調3D graphic處理能力, 應用在3D presentations, 用transparent panel.
總覺得與磐儀科技推的行動醫療平板很像.


手上拿的是Google Glass ?!
記得CES show中的demo有看過這眼鏡, 暫時找不到之前youtbe上的影片..~"~

G. SKILL

ADATA
玩佷大, 液態氮都出場了.



 如果是在Shopping Mall, Pub..等地方, 應該會吸引不少目光.



萬里科技的號稱全球第一台免去背拍照系統,
不過上面這model 看起來笑的有點僵,
這姿式還有笑容可是要維持3分鐘以上吧, 我猜!!
因為要拍20個角度...冏

看似不錯的功能,
但如果是桌機的話, 雖然灰塵不卡在CPU散熱片上, 似乎依舊在機殼裡面?!

拿D3來展示gaming performance讓我嘴角上揚了一下,
為什麼不拿個3D game來展示..只能說D3正夯...XD

另外Grand Hyatt show room list.


其它照片