Android进阶——性能优化之尽量多使用AsyncTask进行短时间网络通信
来源:互联网 发布:学编程需要什么基础 编辑:程序博客网 时间:2024/06/06 08:35
引言
对于我们Android 开发来说,网络操作应该是最普遍不过的操作了吧,因为没有网络操作的APP应该就没有存在的价值吧,往往网络操作这部分又通常是耗时的,所以为了良好的用户体验,我们必须把耗时操作放到非UI线程,而实现方式有很多种,比较常见的应该就是Handler+Thread 和AsyncTask这两种了吧,这两种方式各有利弊,尤其是涉及到与UI交互的时候使用起来更得注意额外处理一些逻辑,但是从一定程度上AsyncTask使用起来更简捷方便些。
一、异步任务AsyncTask概述
总所周知,在Android程序开始运行的时候会单独启动一个进程,默认情况下所有这个程序操作都在这个进程中进行。一个Android程序默认情况下只有一个进程,但一个进程中可以有多个线程,其中最重要的一个线程叫做UI线程(也叫Main Thread),除了UI线程外的线程都叫子线程(Worker Thread)。UI线程主要负责控制UI界面的显示、更新、交互、组件的创建等。因此,UI线程中的操作延迟越短越好(流畅)。把一些耗时的操作(网络请求、数据库操作、逻辑计算等)放到单独的线程,可以避免主线程阻塞。在API 3之前,我们都是使用Thread+Handler的方式进行非UI和UI交互,API 3的时候 Android给我们提供了一种轻量级的异步任务类AsyncTask,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线中更新UI。AsyncTask封装了Thread和Handler,通过AsyncTask可以更加方便地执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的后台任务,建议使用线程池。因为AsyncTask的设计是围绕线程和处理器的一个辅助类,并不构成一个通用的线程框架。Asynctasks应该用于短作业(最多几秒钟)如果你需要保持线程运行很长一段时间,我们强烈建议您使用不同的java.util.concurrent包如执行API提供的线程池和Futuretask。
二、AsyncTask原型
Asynctask是一个抽象的泛型类,它提供了Params,Progress和Result这三个泛型参数,其中Params表示参数的类型,Progress表示后台任务执行进度的类型,而Result则表示后台任务返回数据的类型,如果AsyncTask确实不需要传递具体的参数,那么这三个泛型参数可以用Void来代替。该类中实现异步操作,并提供接口反馈当前异步执行结果及进度,这些接口中有直接运行在主线程中的(如 onPostExecute,onPreExecute等)。
public abstract class AsyncTask<Params, Progress, Result>{ public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } }; mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; } ...}
- Params:传递给AsyncTask的类型,作为doInBackground的参数类型
- Progress:作为onProgressUpdate和publishProgress的参数类型
- Result:由doInBackground返回,作为onPostExecute的参数类型
三、AsyncTask的执行流程
onPreExecute():在主线程中执行,一般在异步任务执行之前被调用,可以用于做些UI初始化工作。比如弹出进度加载框
doInBackground(Params… params):在线程池中执行用于执行异步任务,params参数表示异步任务输入的参数(源自执行异步任务调用execute(Params… params)方法时候传入)。另外通常在此方法中通过调用publishProgress方法来更新任务的进度(publishProgress方法会调用onProgressUpdata方法),而且还会将计算结果返回到onPostExecute方法中。
onProgressUpdata(Progress…values):在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用。
onPostExecute(Result result):在主线程中执行,在一部任务执行之后,此方法会被调用,其中result参数是后台任务的返回值,即doInBackground的返回值。比如可以利用返回的结果更新UI,或者关闭进度条对话框等。
一般来说基本流程是 onPreExecute先执行,接着是doInBackground,最后才是onPostExecute。除了上述四个方法以外,AsyncTask还提供了onCancelled()方法,他同样是在主线程中执行,当异步任务被取消时,onCancelld()方法会被调用,这时候onPostExecute则不会被调用。
四、AsyncTask的使用步骤
1、继承AsyncTask实现onPreExecute、doInBackground、onProgressUpdata、onPostExecute方法,并指定要传入的相应参数类型
/** *从自定义异步任务的原型可以得知,这个异步任务是需要在doInBackground里执行一个需要传入N个String类型作为形参的方法 */ protected class SendHttpTask extends AsyncTask<String, Void, Void> { @Override protected void onPreExecute() { LogUtil.showLog("",false); super.onPreExecute(); } @Override protected void onPostExecute(Void aVoid) { LogUtil.showLog("",false); super.onPostExecute(aVoid); } @Override protected void onProgressUpdate(Void... values) { LogUtil.showLog("",false); super.onProgressUpdate(values); } @Override protected Void doInBackground(String... params) { LogUtil.showLog("",false); String type = params[0];//传入的第一个参数 String content = params[1];//传入的第二个参数 sendHttp.sendHttp(type, content); return null; } }
2、直接new 创建对象并通过调用execute(Params… params)方法执行异步任务,其中参数为泛型不定参数,类型不定,参数个数不定,取决于我们创建自定义AsyncTask时候传入的参数类型,而且execute方法返回的是AsyncTask对象
private SendHttpTask sendCommonTask;/**错误示范 if (sendCommonTask == null) { sendCommonTask = new SendHttpTask(); } sendCommonTask.execute("0", idEdtQuestion.getText().toString().trim());*/sendCommonTask= (SendHttpTask) new SendHttpTask().execute("0",idEdtQuestion.getText().toString().trim());
五、AsyncTask在使用的过程中的注意事项
AsyncTask的类必须是在主线程中加载,这就意味着第一次访问AsyncTask必须发生在主线程,当然这个过程在Android 4.1及以上版本已经被系统自动完成了。在Android 5.0的源码中,可以查看ActivityThread的mian方法,它会调用AsyncTask的init方法,这就满足了AsyncTask的类必须在主线程中进行加载这个条件了。
AsyncTask的对象必须在主程中创建。
execute方法必须在UI线程调用。
不要在程序中手动去调用onpreExecute(),doInBackground, onProgressUpdata和onPostExecute方法,这些方法是由系统自动调用的。
一个AsyncTask对象只能执行一次,因为本质也是Thread嘛,即同一实例只能调用一次execute方法,否则会报运行时异常,比如楼上的错误示范。
在Android 1.6之前,AsyncTask是串行执行任务的,Android 1.6的时候AsyncTask开始采用线程池来处理并行任务,但是从Android 3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask有采用一个线程来串行执行任务。尽管如此,在Android 3.0之后的版本,我们仍可以通过AsyncTask的executeOnExecutor方法来并行执行认为。
运行中可以随时调用cancel(boolean)方法取消任务,如果成功调用isCancel()会返回true,并不会执行onPostExecute(),取而代之的是调用onCancelled()。从源码看,如果这个任务已经执行了这个时候调用cancel是不会真正的把task结束,而是继续执行,只不过改变的是执行之后的回调方法的onPostExecute还是onCancelled.
当异步任务中涉及到UI操作的时候,需要注意谨防内存溢出的问题,一般可遵循以下规范,如果作用于长时间的任务,且是内部类,那么保存了Context或者Activity的引用,会导致相关资源不会被GC及时回收有可能导致溢出,所以第一,在Activity生命周期结束前,可以通过调用cancel方法取消AsyncTask,第二,如果一定要写成内部类的形式,对Context采用弱引用WeakRefrence,在使用之前判断是否为空。
- Android进阶——性能优化之尽量多使用AsyncTask进行短时间网络通信
- Android性能优化之AsyncTask
- android菜鸟进阶之路—— AsyncTask的使用
- Android进阶——性能优化之Android Monitor、MAT、TraceView、Allocation Tracking、Lint的使用
- Android进阶之性能优化
- Android网络编程之使用HttpClient进行Get方式通信
- Android高手进阶——Android内存性能优化
- Android高手进阶——Android内存性能优化
- Android高手进阶——Android内存性能优化
- Android 网络通信(Asynctask类的使用)
- JAVA 尽量使用局部变量优化性能
- 尽量使用httpclient进行网络连接
- android 使用AsyncTask代替thread进行网络请求
- Android 使用Socket进行网络通信
- Android中基于TCP协议的网络通信之使用Socket进行通信
- Android中基于TCP协议的网络通信之使用Socket进行通信
- Android进阶-Android性能优化
- android线程通信之Asynctask
- ubuntu笔记8
- Python requests模块
- Eclipse 导入Maven项目
- Map集合方法及常用实现类
- JQuery插件:ajaxFileUpload.js
- Android进阶——性能优化之尽量多使用AsyncTask进行短时间网络通信
- proxy分析
- 微信小程序 movable-view
- Android开机log和常见异常的分析
- 开启第三方地图(高德)
- iOS依赖库管理工具之CocoaPods
- Linux环境下Zookeeper的安装与配置
- Redis安装及使用
- Invalid location of tag 的解决方案