對於多線程的操做:有兩種方式:網絡
1.繼承Thread類。new Thread(){run()}.start();多線程
2.實現Runnable類。new Thread(){new Runnable(){}}.start();異步
對於多線程的異步操做,處理方式有兩種:oop
對於Handler+Thread分爲主線程與副線程的操做,只要咱們對Looper對象操做便可,將消息message或者runnable進行send或者post便可。佈局
主線程:runOnUiThread(runnable action)、view.post(runnable action)、主線程的Handler.post(runnable action)、Handler.sendMessage(message)post
副線程:副線程的Handler.post(runnable action)性能
對於主線程的handler.sendMessage()再也不闡述,在activity上聲明一個Handler,默認handler構造器就是與主線程的Looper綁定,即在Handler的handleMessage()都是在主線程上的操做。ui
對於不管主線程仍是副線程,針對handler.post(runnable action)的狀況,Hanlder的封裝以下:spa
/** * UI線程 handler **/ private static Handler mUiHandler; /** *副線程handler **/ private static Handler SUB_THREAD1_HANDLER; /** * 副線程1 */ private static HandlerThread SUB_THREAD1; /** * 鎖 **/ private static final Object mMainHandlerLock = new Object(); /** * 取得UI線程Handler * * @return */ public static Handler getMainHandler() { if (mUiHandler == null) { synchronized (mMainHandlerLock) { // if (mUiHandler == null) { mUiHandler = new Handler(Looper.getMainLooper()); // } } } return mUiHandler; } /** * 得到副線程1的Handler.<br> * 副線程能夠執行比較快但不能在ui線程執行的操做.<br> * 此線程禁止進行網絡操做.若是須要進行網絡操做. * 請使用NETWORK_EXECUTOR</b> * * @return handler */ public static Handler getSubThread1Handler() { if (SUB_THREAD1_HANDLER == null) { synchronized (ThreadManager.class) { SUB_THREAD1 = new HandlerThread("SUB1"); SUB_THREAD1.setPriority(Thread.MIN_PRIORITY);//下降線程優先級 SUB_THREAD1.start(); SUB_THREAD1_HANDLER = new Handler(SUB_THREAD1.getLooper()); } } return SUB_THREAD1_HANDLER; }
view.post()與handler.post()的區別,使用不當可能致使內存泄露:.net
相關:http://blog.csdn.net/a740169405/article/details/69668957
若是調用view.post()方法的線程對象被GC-root引用(慎用static修飾Thread),則會形成內存泄漏
由於:
GC-root->Thread->ThreadLocal->ViewRootImpl->runnable
可是主線程除外,由於雖然主線程的runQueue沒法被回收,可是每次執行完performTraversals(),都會將runQueue中的對象執行並清除。
常常咱們將線程池對象定爲static進行復用,所以須要慎用view.post().
共同點:第一種runOnUiThread,和第二種view.post()都是要求主線程執行,都是經過獲取主線程的handler,經過handler.post(),把action封裝成message傳到Looper的消息循環中,當handler再次處理該message時,直接調用action的run方法。
區別:view.post(runnable action)是在view初始化完成後才執行post(runnnable),而runOnUiThread()是主線程當即執行,若是在onCreate()進行初始化activity時,須要對佈局文件中的控件進行調整時,直接使用runOnUiThread代替view.post可能會形成view的信息獲取都爲空。
由於在activity建立時,生命週期onCreate(),佈局文件初始化還沒完成,在onCreate()方法上,僅僅是將控件的相關信息寫入內存,還沒映射到設備上,所以控件信息還沒初始化,廣泛上初始化完成要在onResume()方法以後。
咱們能夠經過調用handler的post方法,把Runnable對象(通常是Runnable的子類)傳過去;handler會在looper中調用這個Runnable的Run方法執行。
Runnable是一個接口,不是一個線程,通常線程會實現Runnable。因此若是咱們使用匿名內部類是運行在UI主線程的,若是咱們使用實現這個Runnable接口的線程類,則是運行在對應線程的。
View.post(Runnable)方法。在post(Runnable action)方法裏,View得到當前線程(即UI線程)的Handler,而後將action對象post到Handler裏。在Handler裏,它將傳遞過來的action對象包裝成一個Message(Message的callback爲action),而後將其投入UI線程的消息循環中。在Handler再次處理該Message時,有一條分支(未解釋的那條)就是爲它所設,直接調用runnable的run方法。而此時,已經路由到UI線程裏,所以,咱們能夠毫無顧慮的來更新UI。
若是咱們要進行耗時的操做,好比下載操做,咱們不能再UI線程;也不能直接在副線程直接進行下載,由於咱們要考慮多線程直接的顧慮,咱們引入線程池。
/** * AsyncTask的默認線程池Executor. 負責長時間的任務(網絡訪問) 默認3個線程 */ public static final Executor NETWORK_EXECUTOR; static { NETWORK_EXECUTOR = initNetworkExecutor(); } private static Executor initNetworkExecutor() { Executor result; // 3.0以上 if (Build.VERSION.SDK_INT >= 11) { //result = AsyncTask.THREAD_POOL_EXECUTOR; result = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); } // 3.0如下, 反射獲取 else { Executor tmp; try { Field field = AsyncTask.class.getDeclaredField("sExecutor"); field.setAccessible(true); tmp = (Executor) field.get(null); } catch (Exception e) { tmp = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); } result = tmp; } if (result instanceof ThreadPoolExecutor) { //線程數改成CPU 核數 +1 ((ThreadPoolExecutor) result).setCorePoolSize(FitmixUtil.getPhoneCpuCoreNum() + 1); } return result; } /** * 在網絡線程上執行異步操做. 該線程池負責網絡請求等操做 長時間的執行(如網絡請求使用此方法執行) 固然也能夠執行其餘 線程和AsyncTask公用 * * @param run */ public static void executeOnNetWorkThread(Runnable run) { try { NETWORK_EXECUTOR.execute(run); } catch (RejectedExecutionException e) { } }
引言:
我不太贊成封裝好就會影響性能的說法,在我實際的運用中,真正的缺點來自於AsyncTask的全局線程池只有5個工做線程,也就是說,一個APP若是運用AsyncTask技術來執行線程,那麼同一時間最多隻能有5個線程同時運行,其餘線程將被阻塞(注:不運用AsyncTask執行的線程,也就是本身new出來的線程不受此限制),因此AsyncTask不要用於多線程取網絡數據,由於極可能這樣會產生阻塞,從而下降效率。
AsyncTask是封裝好的線程池,比起Thread+Handler的方式,AsyncTask在操做UI線程上更方便,由於onPreExecute()、onPostExecute()及更新UI方法onProgressUpdate()均運行在主線程中,這樣就不用Handler發消息處理了;
一個異步任務的執行通常包括如下幾個步驟:
1.execute(Params... params),執行一個異步任務,須要咱們在代碼中調用此方法,觸發異步任務的執行。
2.onPreExecute(),在execute(Params... params)被調用後當即執行,通常用來在執行後臺任務前對UI作一些標記。
3.doInBackground(Params... params),在onPreExecute()完成後當即執行,用於執行較爲費時的操做,此方法將接收輸入參數和返回計算結果。在執行過程當中能夠調用publishProgress(Progress... values)來更新進度信息。
4.onProgressUpdate(Progress... values),在調用publishProgress(Progress... values)時,此方法被執行,直接將進度信息更新到UI組件上。
5.onPostExecute(Result result),當後臺操做結束時,此方法將會被調用,計算結果將作爲參數傳遞到此方法中,直接將結果顯示到UI組件上。