对于多线程的操做:有两种方式:网络
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组件上。