【声明】

欢迎转载,但请保留文章原始出处→_→

生命壹号:http://www.cnblogs.com/smyhvae/

文章来源:http://www.cnblogs.com/smyhvae/p/3866570.html

【正文】

本文将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信。

一、Android当中的多线程:

在Android当中,当一个应用程序的组件启动的时候,并且没有其他的应用程序组件在运行时,Android系统就会为该应用程序组件开辟一个新的线程来执行。默认的情况下,在一个相同Android应用程序当中,里面的组件都是运行在同一个线程里的,这个线程称之为Main线程。当我们通过某个组件来启动另一个组件的时候,这个时候默认都是在同一个线程当中完成的。当然,我们可以自己来管理我们的Android应用的线程,我们可以根据我们自己的需要来给应用程序创建额外的线程。

二、Main Thread 和 Worker Thread:

在Android当中,通常将线程分为两种,一种叫做Main Thread,除了Main Thread之外的线程都可称为Worker Thread。

当一个应用程序运行的时候,Android操作系统就会给该应用程序启动一个线程,这个线程就是我们的Main Thread,这个线程非常重要,它主要用来加载UI界面,完成系统和用户之间的交互,并将交互后的结果又展示给用户,所以Main Thread又被称为UI Thread。

Android系统默认不会给应用程序组件创建一个额外的线程,所有的这些组件默认都是在同一个线程中运行。然而,某些时候当我们的应用程序需要完成一个耗时操作的时候(如访问网络或者是对数据库进行查询),此时UI Thread就会被阻塞。例如,当我们点击一个Button,然后希望其从网络中获取一些数据,如果此操作在UI Thread当中完成的话,UI线程就会处于阻塞的状态,此时,我们的系统不会调度任何其它的事件,更糟糕的是,当我们的整个现场如果阻塞时间超过5秒钟(官方描述),这个时候就会出现 著名的ANR (Application Not Responding)的问题,此时,应用程序会弹出一个框,让用户选择是否退出该程序。对于Android开发来说,出现ANR的现象是绝对不能被允许的。

另外,由于Android UI控件不是线程安全的,所以我们不能在UI Thread之外的线程当中对UI控件进行操作。因此在Android的多线程编程当中,有两条非常重要的原则必须遵守:

  • 不能在UI Thread当中进行耗时操作,以免阻塞UI Thread
  • 不能在UI Thread之外的线程当中操纵UI元素

 三、如何处理UI Thread 和 Worker Thread之间的通信:

我们既不能在主线程当中处理耗时的操作,又不能在工作线程中来访问我们的UI控件,那么我们比如从网络中要下载一张图片,又怎么能将其更新到UI控件上呢?这就关系到了主线程和工作线程之间的通信问题了。在Android当中,提供了异步消息处理机制的两种方式来解决线程之间的通信问题,一种是通过Handler的机制(这种方式在后面的博客中将详细介绍),还有一种就是今天要详细讲解的 AsyncTask 机制。

四、AsyncTask:

AsyncTask:异步任务,从字面上来说,就是在UI主线程运行的时候,异步完成一些操作。AsyncTask允许我们在后台执行一个异步任务。我们可以将耗时的操作放在异步任务当中来执行,并随时将任务执行的结果返回给UI线程来更新UI控件。通过AsyncTask我们可以轻松解决多线程之间的通信问题。

怎么来理解AsyncTask呢?通俗来说,AsyncTask就相当于Android给我们提供了一个多线程编程的一个框架,其介于Thread和Handler之间,我们如果要定义一个AsyncTask,就需要定义一个类来继承AsyncTask这个抽象类,并实现其唯一的一个 doInBackgroud 抽象方法。

要掌握AsyncTask,我们就必须要一个概念,总结起来就是: 3个泛型,4个步骤。

我们来看看AsyncTask这个抽象类的定义,当我们定义一个类来继承AsyncTask这个类的时候,需要为其指定3个泛型参数:

  1. AsyncTask <Params, Progress, Result>
  • Params: 指定的是我们传递给异步任务执行时的参数的类型
  • Progress: 指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型
  • Result: 指定的是异步任务执行完后返回给UI线程的结果的类型

我们在定义一个类继承AsyncTask类的时候,必须指定好这三个泛型的类型,如果都不指定的话,则都将其写成Void,例如:

  1. AsyncTask <Void, Void, Void>

4个步骤:当我们执行一个异步任务时,需要按照下面的4个步骤分别执行:

  • onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出ProgressDialog
  • doInBackground(Params... params): 在onPreExecute()方法执行完后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread来执行这个方法(即在worker thread当中执行),执行完后将执行结果发送给最后一个 onPostExecute 方法,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作
  • onProgressUpdate(Progess... values): 这个方法也是在UI Thread当中执行的,在异步任务执行的时候,有时需要将执行的进度返回给UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进度,就可以使用这个方法来更新进度。这个方法在调用之前,我们需要在 doInBackground 方法中调用一个 publishProgress(Progress) 的方法来将进度时时刻刻传递给 onProgressUpdate 方法来更新
  • onPostExecute(Result... result): 当异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上

为什么AsyncTask抽象类只有一个 doInBackground 的抽象方法呢??原因是,我们如果要做一个异步任务,我们必须要为其开辟一个新的Thread,让其完成一些操作,而在完成这个异步任务时,我可能并不需要弹出ProgressDialog,并不需要随时更新ProgressDialog的进度条,也并不需要将结果更新给UI界面,所以除了 doInBackground 方法之外的三个方法,都不是必须有的,因此必须要实现的方法是 doInBackground 方法。

4个步骤简洁版描述如下:

  第一步:表示任务执行前的操作

  第二步:主要完成耗时操作

  第三步:主要是更新UI操作

  第四步:产生最终结果

以下实例中代表的含义为:

  第一步:显示进度条

  第二步:(此任务必不可少)在后台执行任务,将进度值传给第三步,将结果传给第四步;

  第三步:进度值更新

  第四步:产生最终结果

五、【实例】通过AsyncTask来从网络上下载一张图片:

下面通过两个代码示例,来看看如何通过AsyncTask来从网络上下载一张图片,并更新到ImageView控件上。

在这之前,必须要执行的操作是:添加网络授权。下面的例子将有详细的操作描述。

【实例一】从网络下载图片,弹出一个ProgressDialog,但不显示实时进度:

1、添加网络授权:

因为手机默认不能访问网络,所以首先要在清单文件 AndroidManifest.xml中添加网络授权。

方法如下:

打开AndroidManifest.xml文件,点击"Permissions"按钮,然后点击“Add”:

弹出对话框后,选择最后一项:Users Permission:

接着选择其中的Internet选项:

按Ctrl+S保存即可。

紧接着,我们在清单文件中就能看到对应自动生成的代码:

其实,直接在AndroidManifest.xml文件中添加上这一行代码也是可以的。

2、完整版代码如下:

activity_main.xml的代码:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:paddingBottom="@dimen/activity_vertical_margin"
  6. android:paddingLeft="@dimen/activity_horizontal_margin"
  7. android:paddingRight="@dimen/activity_horizontal_margin"
  8. android:paddingTop="@dimen/activity_vertical_margin"
  9. tools:context=".MainActivity" >
  10. <ImageView
  11. android:id="@+id/imageView1"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:layout_alignParentTop="true"
  15. android:layout_centerHorizontal="true" />
  16. <Button
  17. android:id="@+id/button1"
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content"
  20. android:layout_alignParentBottom="true"
  21. android:layout_centerHorizontal="true"
  22. android:layout_marginBottom="136dp"
  23. android:text="下载网络图片" />
  24. </RelativeLayout>

MainActivity.java的代码:

  1. package com.example.downloadimage01;
  2. import org.apache.http.HttpEntity;
  3. import org.apache.http.HttpResponse;
  4. import org.apache.http.client.HttpClient;
  5. import org.apache.http.client.methods.HttpGet;
  6. import org.apache.http.impl.client.DefaultHttpClient;
  7. import org.apache.http.util.EntityUtils;
  8. import android.app.Activity;
  9. import android.app.ProgressDialog;
  10. import android.graphics.Bitmap;
  11. import android.graphics.BitmapFactory;
  12. import android.os.AsyncTask;
  13. import android.os.Bundle;
  14. import android.view.Menu;
  15. import android.view.View;
  16. import android.view.View.OnClickListener;
  17. import android.widget.Button;
  18. import android.widget.ImageView;
  19. public class MainActivity extends Activity {
  20. private ImageView imageView ;
  21. private Button button ;
  22. private ProgressDialog dialog ;
  23. //来自网络的图片
  24. private String image_path = "http://imgsrc.baidu.com/forum/pic/item/7c1ed21b0ef41bd51a5ac36451da81cb39db3d10.jpg" ;
  25. @Override
  26. protected void onCreate(Bundle savedInstanceState) {
  27. super.onCreate(savedInstanceState);
  28. setContentView(R.layout.activity_main);
  29.  
  30. //添加弹出的对话框
  31. dialog = new ProgressDialog(this) ;
  32. dialog.setTitle("提示") ;
  33. dialog.setMessage("正在下载图片,请稍后···") ;
  34.  
  35. imageView = (ImageView)findViewById(R.id.imageView1) ;
  36. button = (Button)findViewById(R.id.button1) ;
  37. button.setOnClickListener(new OnClickListener() {
  38.  
  39. @Override
  40. public void onClick(View v) {
  41. //点击按钮时,执行异步任务的操作
  42. new DownTask().execute(image_path) ;
  43. }
  44. }) ; //注意,这个地方的分号容易遗忘
  45. }
  46. /*
  47. * 异步任务执行网络下载图片
  48. * */
  49. public class DownTask extends AsyncTask<String, Void, Bitmap> {
  50. //上面的方法中,第一个参数:网络图片的路径,第二个参数的包装类:进度的刻度,第三个参数:任务执行的返回结果
  51. @Override
  52. //在界面上显示进度条
  53. protected void onPreExecute() {
  54. dialog.show() ;
  55. };
  56. protected Bitmap doInBackground(String... params) { //三个点,代表可变参数
  57. //使用网络链接类HttpClient类完成对网络数据的提取
  58. HttpClient httpClient = new DefaultHttpClient() ;
  59. HttpGet httpget = new HttpGet(params[0]) ;
  60. Bitmap bitmap = null ;
  61. try {
  62. HttpResponse httpResponse = httpClient.execute(httpget) ;
  63. if(httpResponse.getStatusLine().getStatusCode()==200){
  64. HttpEntity httpEntity = httpResponse.getEntity() ;
  65. byte[] data = EntityUtils.toByteArray(httpEntity);
  66. bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
  67. }
  68. } catch (Exception e) {
  69. // TODO Auto-generated catch block
  70. e.printStackTrace();
  71. }
  72. return bitmap;
  73. }
  74. //主要是更新UI
  75. @Override
  76. protected void onPostExecute(Bitmap result) {
  77. super.onPostExecute(result);
  78. imageView.setImageBitmap(result) ;//更新UI
  79. dialog.dismiss() ;
  80. }
  81. }
  82. @Override
  83. public boolean onCreateOptionsMenu(Menu menu) {
  84. // Inflate the menu; this adds items to the action bar if it is present.
  85. getMenuInflater().inflate(R.menu.main, menu);
  86. return true;
  87. }
  88.  
  89. }

运行后,点击按钮,显示结果如下:

【实例二】从网络下载图片,弹出能显示进度值的对话框:

注:既然要显示进度值,所以此处的进度条风格要设置为水平。

1、添加网络授权(同上)

2、完整版代码如下:

activity_main.xml的代码和【实例一】中的一样;

MainActivity.java的代码:

  1. package com.example.smyh001downloadimage01;
  2.  
  3. import java.io.ByteArrayOutputStream;
  4. import java.io.InputStream;
  5.  
  6. import org.apache.http.HttpEntity;
  7. import org.apache.http.HttpResponse;
  8. import org.apache.http.client.HttpClient;
  9. import org.apache.http.client.methods.HttpGet;
  10. import org.apache.http.impl.client.DefaultHttpClient;
  11.  
  12. import android.app.Activity;
  13. import android.app.ProgressDialog;
  14. import android.graphics.Bitmap;
  15. import android.graphics.BitmapFactory;
  16. import android.os.AsyncTask;
  17. import android.os.Bundle;
  18. import android.view.Menu;
  19. import android.view.View;
  20. import android.view.View.OnClickListener;
  21. import android.widget.Button;
  22. import android.widget.ImageView;
  23.  
  24. public class MainActivity extends Activity {
  25.  
  26. private ImageView imageView ;
  27. private Button button ;
  28. private ProgressDialog dialog ;
  29. //来自网络的图片
  30. private String image_path = "http://imgsrc.baidu.com/forum/pic/item/7c1ed21b0ef41bd51a5ac36451da81cb39db3d10.jpg" ;
  31. @Override
  32. protected void onCreate(Bundle savedInstanceState) {
  33. super.onCreate(savedInstanceState);
  34. setContentView(R.layout.activity_main);
  35.  
  36. //添加弹出的对话框
  37. dialog = new ProgressDialog(this) ;
  38. dialog.setTitle("提示") ;
  39. dialog.setMessage("正在下载图片,请稍后···") ;
  40. //将进度条设置为水平风格,让其能够显示具体的进度值
  41. dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) ;
  42. dialog.setCancelable(false) ; //用了这个方法之后,直到图片下载完成,进度条才会消失(即使在这之前点击了屏幕)
  43.  
  44. imageView = (ImageView)findViewById(R.id.imageView1) ;
  45. button = (Button)findViewById(R.id.button1) ;
  46. button.setOnClickListener(new OnClickListener() {
  47.  
  48. @Override
  49. public void onClick(View v) {
  50. //点击按钮时,执行异步任务的操作
  51. new DownTask().execute(image_path) ;
  52. }
  53. }) ; //注意,这个地方的分号容易遗忘
  54.  
  55. }
  56.  
  57. /*
  58. * 异步任务执行网络下载图片
  59. * */
  60. public class DownTask extends AsyncTask<String, Integer, byte[]> {
  61. //上面的方法中,第一个参数:网络图片的路径,第二个参数的包装类:进度的刻度,第三个参数:任务执行的返回结果
  62. @Override
  63. //在界面上显示进度条
  64. protected void onPreExecute() {
  65. dialog.show() ;
  66. };
  67.  
  68. protected byte[] doInBackground(String... params) { //三个点,代表可变参数
  69. //使用网络链接类HttpClient类完成对网络数据的提取,即完成对图片的下载功能
  70. HttpClient httpClient = new DefaultHttpClient() ;
  71. HttpGet httpget = new HttpGet(params[0]) ;
  72. byte[] result = null ;
  73. ByteArrayOutputStream outputStream = new ByteArrayOutputStream() ;
  74. InputStream inputStream = null ;
  75.  
  76. try {
  77. HttpResponse httpResponse = httpClient.execute(httpget) ;
  78. if(httpResponse.getStatusLine().getStatusCode()==200){
  79.  
  80. HttpEntity httpEntiry = httpResponse.getEntity();
  81. inputStream = httpEntiry.getContent();
  82. // 先要获得文件的总长度
  83. long file_length = httpResponse.getEntity().getContentLength() ;
  84. int len = 0 ;
  85. // 每次读取1024个字节
  86. byte[] data = new byte[1024] ;
  87. // 每次读取后累加的长度
  88. int total_length = 0 ;
  89. while ((len = inputStream.read(data))!=-1) {
  90. // 每读一次,就将total_length累加起来
  91. total_length+=len ;
  92. // 得到当前图片下载的进度
  93. int progress_value = (int) ((total_length / (float)file_length)*100);
  94. // 时刻将当前进度更新给onProgressUpdate方法
  95. publishProgress(progress_value) ;
  96. outputStream.write(data, 0, len);
  97. }
  98. // 边读边写到ByteArrayOutputStream当中
  99. result = outputStream.toByteArray();
  100. //bitmap = BitmapFactory.decodeByteArray(result, 0, result.length) ;
  101. }
  102. } catch (Exception e) {
  103. // TODO Auto-generated catch block
  104. e.printStackTrace();
  105. } finally {
  106. httpClient.getConnectionManager().shutdown();
  107. }
  108. return result;
  109. }
  110.  
  111. @Override
  112. protected void onProgressUpdate(Integer... values) {
  113. // TODO Auto-generated method stub
  114. super.onProgressUpdate(values);
  115. // 更新ProgressDialog的进度条
  116. dialog.setProgress(values[0]);
  117. }
  118.  
  119. //主要是更新UI
  120. @Override
  121. protected void onPostExecute(byte[] result) {
  122. super.onPostExecute(result);
  123. // 将doInBackground方法返回的byte[]解码成要给Bitmap
  124. Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0, result.length) ;
  125. // 更新我们的ImageView控件
  126. imageView.setImageBitmap(bitmap) ;//更新UI
  127. // 使ProgressDialog框消失
  128. dialog.dismiss() ;
  129. }
  130. }
  131.  
  132. @Override
  133. public boolean onCreateOptionsMenu(Menu menu) {
  134. // Inflate the menu; this adds items to the action bar if it is present.
  135. getMenuInflater().inflate(R.menu.main, menu);
  136. return true;
  137. }
  138.  
  139. }

运行后,显示结果如下:

【工程文件】

链接:http://pan.baidu.com/s/1dDvhXkt

密码:47ce

六、AsyncTask的重要知识点:

明白了AsyncTask的工作原理后,继续补充一下AsyncTask的一些其他知识点:

1、Cancelling a Task

我们可以在任何时刻来取消异步任务的执行,通过调用 cancel(boolean)方法,调用完这个方法后系统会随后调用 isCancelled() 方法并且返回true。如果调用了这个方法,那么在 doInBackgroud() 方法执行完之后,就不会调用 onPostExecute() 方法了,取而代之的是调用 onCancelled() 方法。如果有必要的话,为了确保Task已经被取消了,我们需要经常调用 isCancelled() 方法来判断。

2、在使用AsyncTask做异步任务的时候必须要遵循的原则:

  • AsyncTask类必须在UI Thread当中加载,在Android Jelly_Bean版本后这些都是自动完成的
  • AsyncTask的对象必须在UI Thread当中实例化
  • execute方法必须在UI Thread当中调用
  • 不要手动的去调用AsyncTask的四个方法,这些都是由Android系统自动调用的
  • AsyncTask任务只能被执行一次

【总结】

到此,有关AsyncTask的总结就到此为止了,本文主要讲解了Android中的多线程知识,并且详细地讲解了 AsyncTask 异步任务的概念和实现机制,并通过实例来了解 AsyncTask 的执行过程,最后还补充了 AsyncTask 的一些重要知识点,包括如何取消一个 AsyncTask 以及在使用 AsyncTask 时所必须遵循的规则。建议初学者(包括我)在理解这方面的问题时可以多参考官方的API文档。

我的公众号

想学习代码之外的软技能?不妨关注我的微信公众号:生命团队(id:vitateam)。

扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:

Android 多线程----AsyncTask异步任务详解的更多相关文章

  1. Android应用AsyncTask处理机制详解及源码分析

    1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个知识点.前面我们分析了Handler异步机制原理(不了解的可以阅读我的<Android异步消息处理机 ...

  2. 【转载】Android应用AsyncTask处理机制详解及源码分析

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果] 1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个 ...

  3. Android App优化之ANR详解

    引言 背景:Android App优化, 要怎么做? Android App优化之性能分析工具 Android App优化之提升你的App启动速度之理论基础 Android App优化之提升你的App ...

  4. android多线程-AsyncTask之工作原理深入解析(下)

    关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...

  5. android多线程-AsyncTask之工作原理深入解析(上)

    关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...

  6. Android高效率编码-第三方SDK详解系列(一)——百度地图,绘制,覆盖物,导航,定位,细腻分解!

    Android高效率编码-第三方SDK详解系列(一)--百度地图,绘制,覆盖物,导航,定位,细腻分解! 这是一个系列,但是我也不确定具体会更新多少期,最近很忙,主要还是效率的问题,所以一些有效的东西还 ...

  7. Android Telephony分析(三) ---- RILJ详解

    前言 本文主要讲解RILJ工作原理,以便更好地分析代码,分析业务的流程.这里说的RILJ指的是RIL.java (frameworks\opt\telephony\src\java\com\andro ...

  8. Android注解支持Support Annotations详解

    ###注解支持(Support Annotations)Android support library从19.1版本开始引入了一个新的注解库,它包含很多有用的元注解,你能用它们修饰你的代码,帮助你发现 ...

  9. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

随机推荐

  1. 依赖于spring 4.x的spring组件

    1.Spring Data MongoDB 1.6.x开始依赖于spring 4.x: 2.@Conditional注解: 3.spring-data-redis 1.4.x开始依赖于spring 4 ...

  2. Erlang高阶函数

    对于函数式语言来说,函数也想普通的数据类型一样无处不在.函数即可以当成参数进行传递,也可以当成函数的返回值.当我第一次学习函数式编程的时候,我被这样的写法弄的头昏脑涨.下面我举例说明下(例子摘录自Le ...

  3. miniSipServer简单而不简单,轻松落地,实现电脑对固话、手机通讯

    最近沉迷于SIP通讯,网内通讯全免费,落地也就几分钱,而且无漫游全国拨打,想想真是心动呢,只要有网落就ok!. 对于sipserver,现在的市场上软件很多,免费的.收费的应有尽有,这里不一一例举.综 ...

  4. 微信CRM六大模块的详解

    微信团队一直强调企业微信的主要功能是服务而非营销工具,微信5.0将公众号区分为服务号和订阅号,10月底平台为服务号开放高级接口,包括客服接口.网页授权等,可见服务是微信公众号的核心价值和方向.前一阵很 ...

  5. 获取经过跳转后的url地址

    粗略一算,不写code已经好几个月了. 昨日受兄弟所托,为他写了一个小小的程序. 程序功能: 自动获取跳转后的Url地址 如下图所示: (newUrl.txt为转换后的地址信息...) 实现过程: 每 ...

  6. IOS 开发一些常用的地址

    1.开发者中心 https://developer.apple.com/membercenter/index.action 2.itunesconnect https://itunesconnect. ...

  7. UIView简单动画

    UIView动态实现的效果有以下几种: 1.动态改变frame 2.动态改变color 3.动态改变alpha 4.动态改变bounds 首先,我们先看几种BasicView动画 #pragma ma ...

  8. 我的android学习经历12

    自动匹配输入的内容(文章最后有一个问题有兴趣的可以解答一下,谢谢大神了) 这个主要是两个控件MultiAutoCompleteTextView和AutoCompleteTextView 这两个控件和T ...

  9. iOS之UI--关于modal

    modal的效果展示: 关于modal的涉及到的知识点: 1.当一个控制器被销毁的时候,它里面所有子控制器的业务逻辑都不能够处理 2.当一个控制器被销毁的时候,它里面所有子控件的业务逻辑都不能够处理 ...

  10. 做一些Spring AOP做过的事,封装 jdk动态代理成为一个黑盒子

      怎么使用eclise 抽取方法,请看  利用eclipse 抽取代码片段为方法   抽取完成之后,还需要 ① 将Collection.class换成  target.getClass(),targ ...