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

  前两篇我们分析android的异步线程类HandlerThread与IntentService,它们都是android系统独有的线程类,而android中还有另一个比较重要的异步线程类,它就是AsyncTask。本篇我们将从以下3点深入分析AsyncTask。

  • AsyncTask的常规使用分析以及案例实现
  • AsyncTask在不同android版本的下的差异
  • AsyncTask的工作原理流程

一、AsyncTask的常规使用分析以及案例实现

  AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后会把执行的进度和最终结果传递给主线程并更新UI。AsyncTask本身是一个抽象类它提供了Params、Progress、Result 三个泛型参数,其类声明如下:

  1. public abstract class AsyncTask<Params, Progress, Result> {

  由类声明可以看出AsyncTask抽象类确实定义了三种泛型类型 Params,Progress和Result,它们分别含义如下:

  • Params :启动任务执行的输入参数,如HTTP请求的URL
  • Progress : 后台任务执行的百分比
  • Result :后台执行任务最终返回的结果类型

  如果AsyncTask不需要传递具体参数,那么这三个泛型参数可以使用Void代替。好~,我们现在创建一个类继承自AsyncTask如下:

  1. package com.zejian.handlerlooper;
  2. import android.graphics.Bitmap;
  3. import android.os.AsyncTask;
  4. /**
  5. * Created by zejian
  6. * Time 16/9/4.
  7. * Description:
  8. */
  9. public class DownLoadAsyncTask extends AsyncTask<String,Integer,Bitmap> {
  10. /**
  11. * onPreExecute是可以选择性覆写的方法
  12. * 在主线程中执行,在异步任务执行之前,该方法将会被调用
  13. * 一般用来在执行后台任务前对UI做一些标记和准备工作,
  14. * 如在界面上显示一个进度条。
  15. */
  16. @Override
  17. protected void onPreExecute() {
  18. super.onPreExecute();
  19. }
  20. /**
  21. * 抽象方法必须覆写,执行异步任务的方法
  22. * @param params
  23. * @return
  24. */
  25. @Override
  26. protected Bitmap doInBackground(String... params) {
  27. return null;
  28. }
  29. /**
  30. * onProgressUpdate是可以选择性覆写的方法
  31. * 在主线程中执行,当后台任务的执行进度发生改变时,
  32. * 当然我们必须在doInBackground方法中调用publishProgress()
  33. * 来设置进度变化的值
  34. * @param values
  35. */
  36. @Override
  37. protected void onProgressUpdate(Integer... values) {
  38. super.onProgressUpdate(values);
  39. }
  40. /**
  41. * onPostExecute是可以选择性覆写的方法
  42. * 在主线程中执行,在异步任务执行完成后,此方法会被调用
  43. * 一般用于更新UI或其他必须在主线程执行的操作,传递参数bitmap为
  44. * doInBackground方法中的返回值
  45. * @param bitmap
  46. */
  47. @Override
  48. protected void onPostExecute(Bitmap bitmap) {
  49. super.onPostExecute(bitmap);
  50. }
  51. /**
  52. * onCancelled是可以选择性覆写的方法
  53. * 在主线程中,当异步任务被取消时,该方法将被调用,
  54. * 要注意的是这个时onPostExecute将不会被执行
  55. */
  56. @Override
  57. protected void onCancelled() {
  58. super.onCancelled();
  59. }
  60. }

  如代码所示,我们创建一个继承自AsyncTask的异步线程类,在泛型参数方面,传递String类型(Url) , Integer类型(显示进度),Bitmap类型作为返回值。接着重写了抽象方法doInBackground(),以及覆写了onPreExecute()、onProgressUpdate()、onPostExecute()、onCancelled()等方法,它们的主要含义如下:

  • (1)onPreExecute(), 该方法在主线程中执行,将在execute(Params… params)被调用后执行,一般用来做一些UI的准备工作,如在界面上显示一个进度条。
  • (2)doInBackground(Params…params), 抽象方法,必须实现,该方法在线程池中执行,用于执行异步任务,将在onPreExecute方法执行后执行。其参数是一个可变类型,表示异步任务的输入参数,在该方法中还可通过publishProgress(Progress… values)来更新实时的任务进度,而publishProgress方法则会调用onProgressUpdate方法。此外doInBackground方法会将计算的返回结果传递给onPostExecute方法。
  • (3)onProgressUpdate(Progress…),在主线程中执行,该方法在publishProgress(Progress… values)方法被调用后执行,一般用于更新UI进度,如更新进度条的当前进度。
  • (4)onPostExecute(Result), 在主线程中执行,在doInBackground 执行完成后,onPostExecute 方法将被UI线程调用,doInBackground 方法的返回值将作为此方法的参数传递到UI线程中,并执行一些UI相关的操作,如更新UI视图。
  • (5)onCancelled(),在主线程中执行,当异步任务被取消时,该方法将被调用,要注意的是这个时onPostExecute将不会被执行。

  我们这里再强调一下它们的执行顺序,onPreExecute方法先执行,接着是doInBackground方法,在doInBackground中如果调用了publishProgress方法,那么onProgressUpdate方法将会被执行,最后doInBackground方法执行后完后,onPostExecute方法将被执行。说了这么多,我们还没说如何启动AsyncTask呢,其实可以通过execute方法启动异步线程,其方法声明如下:

  1. public final AsyncTask<Params, Progress, Result> execute(Params... params)
  • 1

  该方法是一个final方法,参数类型是可变类型,实际上这里传递的参数和doInBackground(Params…params)方法中的参数是一样的,该方法最终返回一个AsyncTask的实例对象,可以使用该对象进行其他操作,比如结束线程之类的。启动范例如下:

  1. new DownLoadAsyncTask().execute(url1,url2,url3);
  • 1

  当然除了以上介绍的内容外,我们在使用AsyncTask时还必须遵守一些规则,以避免不必要的麻烦。

  • (1) AsyncTask的实例必须在主线程(UI线程)中创建 ,execute方法也必须在主线程中调用
  • (2) 不要在程序中直接的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法
  • (3) 不能在doInBackground(Params… params)中更新UI
  • (5) 一个AsyncTask对象只能被执行一次,也就是execute方法只能调用一次,否则多次调用时将会抛出异常

  到此,AsyncTask的常规方法说明和使用以及注意事项全部介绍完了,下面我们来看一个下载案例,该案例是去下载一张大图,并实现下载实时进度。先来看看AsynTaskActivity.java的实现:

  1. package com.zejian.handlerlooper;
  2. import android.content.Context;
  3. import android.os.AsyncTask;
  4. import android.os.Environment;
  5. import android.os.PowerManager;
  6. import android.widget.Toast;
  7. import com.zejian.handlerlooper.util.LogUtils;
  8. import java.io.File;
  9. import java.io.FileOutputStream;
  10. import java.io.IOException;
  11. import java.io.InputStream;
  12. import java.io.OutputStream;
  13. import java.net.HttpURLConnection;
  14. import java.net.URL;
  15. /**
  16. * Created by zejian
  17. * Time 16/9/4.
  18. * Description:
  19. */
  20. public class DownLoadAsyncTask extends AsyncTask<String, Integer, String> {
  21. private PowerManager.WakeLock mWakeLock;
  22. private int ValueProgress=100;
  23. private Context context;
  24. public DownLoadAsyncTask(Context context){
  25. this.context=context;
  26. }
  27. /**
  28. * sync method which download file
  29. * @param params
  30. * @return
  31. */
  32. @Override
  33. protected String doInBackground(String... params) {
  34. InputStream input = null;
  35. OutputStream output = null;
  36. HttpURLConnection connection = null;
  37. try {
  38. URL url = new URL(params[0]);
  39. connection = (HttpURLConnection) url.openConnection();
  40. connection.connect();
  41. // expect HTTP 200 OK, so we don't mistakenly save error report
  42. // instead of the file
  43. if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
  44. return "Server returned HTTP " + connection.getResponseCode()
  45. + " " + connection.getResponseMessage();
  46. }
  47. // this will be useful to display download percentage
  48. // might be -1: server did not report the length
  49. int fileLength = connection.getContentLength();
  50. // download the file
  51. input = connection.getInputStream();
  52. //create output
  53. output = new FileOutputStream(getSDCardDir());
  54. byte data[] = new byte[4096];
  55. long total = 0;
  56. int count;
  57. while ((count = input.read(data)) != -1) {
  58. // allow canceling with back button
  59. if (isCancelled()) {
  60. input.close();
  61. return null;
  62. }
  63. total += count;
  64. // publishing the progress....
  65. if (fileLength > 0) // only if total length is known
  66. publishProgress((int) (total * 100 / fileLength));
  67. //
  68. Thread.sleep(100);
  69. output.write(data, 0, count);
  70. }
  71. } catch (Exception e) {
  72. return e.toString();
  73. } finally {
  74. try {
  75. if (output != null)
  76. output.close();
  77. if (input != null)
  78. input.close();
  79. } catch (IOException ignored) {
  80. }
  81. if (connection != null)
  82. connection.disconnect();
  83. }
  84. return null;
  85. }
  86. @Override
  87. protected void onPreExecute() {
  88. super.onPreExecute();
  89. // take CPU lock to prevent CPU from going off if the user
  90. // presses the power button during download
  91. PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
  92. mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
  93. getClass().getName());
  94. mWakeLock.acquire();
  95. //Display progressBar
  96. // progressBar.setVisibility(View.VISIBLE);
  97. }
  98. @Override
  99. protected void onPostExecute(String values) {
  100. super.onPostExecute(values);
  101. mWakeLock.release();
  102. if (values != null)
  103. LogUtils.e("Download error: "+values);
  104. else {
  105. Toast.makeText(context, "File downloaded", Toast.LENGTH_SHORT).show();
  106. }
  107. }
  108. /**
  109. * set progressBar
  110. * @param values
  111. */
  112. @Override
  113. protected void onProgressUpdate(Integer... values) {
  114. super.onProgressUpdate(values);
  115. // progressBar.setmProgress(values[0]);
  116. //update progressBar
  117. if(updateUI!=null){
  118. updateUI.UpdateProgressBar(values[0]);
  119. }
  120. }
  121. /**
  122. * get SD card path
  123. * @return
  124. */
  125. public File getSDCardDir(){
  126. if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
  127. // 创建一个文件夹对象,赋值为外部存储器的目录
  128. String dirName = Environment.getExternalStorageDirectory()+"/MyDownload/";
  129. File f = new File(dirName);
  130. if(!f.exists()){
  131. f.mkdir();
  132. }
  133. File downloadFile=new File(f,"new.jpg");
  134. return downloadFile;
  135. }
  136. else{
  137. LogUtils.e("NO SD Card!");
  138. return null;
  139. }
  140. }
  141. public UpdateUI updateUI;
  142. public interface UpdateUI{
  143. void UpdateProgressBar(Integer values);
  144. }
  145. public void setUpdateUIInterface(UpdateUI updateUI){
  146. this.updateUI=updateUI;
  147. }
  148. }

  简单说明一下代码,在onPreExecute方法中,可以做了一些准备工作,如显示进度圈,这里为了演示方便,进度圈在常态下就是显示的,同时,我们还锁定了CPU,防止下载中断,而在doInBackground方法中,通过HttpURLConnection对象去下载图片,然后再通过int fileLength =connection.getContentLength();代码获取整个下载图片的大小并使用publishProgress((int) (total * 100 / fileLength));更新进度,进而调用onProgressUpdate方法更新进度条。最后在onPostExecute方法中释放CPU锁,并通知是否下载成功。接着看看Activity的实现:
activity_download.xml

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:customView="http://schemas.android.com/apk/res-auto"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent">
  5. <com.zejian.handlerlooper.util.LoadProgressBarWithNum
  6. android:id="@+id/progressbar"
  7. android:layout_width="wrap_content"
  8. android:layout_height="wrap_content"
  9. customView:progress_radius="100dp"
  10. android:layout_centerInParent="true"
  11. customView:progress_strokeWidth="40dp"
  12. customView:progress_text_size="35sp"
  13. customView:progress_text_visibility="visible"
  14. customView:progress_value="0"
  15. />
  16. <Button
  17. android:id="@+id/downloadBtn"
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content"
  20. android:text="start download"
  21. android:layout_centerHorizontal="true"
  22. android:layout_below="@id/progressbar"
  23. android:layout_marginTop="40dp"
  24. />
  25. </RelativeLayout>

AsynTaskActivity.java

  1. package com.zejian.handlerlooper;
  2. import android.Manifest;
  3. import android.app.Activity;
  4. import android.content.pm.PackageManager;
  5. import android.os.Bundle;
  6. import android.support.v4.app.ActivityCompat;
  7. import android.support.v4.content.ContextCompat;
  8. import android.view.View;
  9. import android.widget.Button;
  10. import com.zejian.handlerlooper.util.LoadProgressBarWithNum;
  11. import com.zejian.handlerlooper.util.LogUtils;
  12. /**
  13. * Created by zejian
  14. * Time 16/9/4.
  15. * Description:AsynTaskActivity
  16. */
  17. public class AsynTaskActivity extends Activity implements DownLoadAsyncTask.UpdateUI {
  18. private static int WRITE_EXTERNAL_STORAGE_REQUEST_CODE=0x11;
  19. private static String DOWNLOAD_FILE_JPG_URL="http://img2.3lian.com/2014/f6/173/d/51.jpg";
  20. private LoadProgressBarWithNum progressBar;
  21. private Button downloadBtn;
  22. @Override
  23. protected void onCreate(Bundle savedInstanceState) {
  24. super.onCreate(savedInstanceState);
  25. setContentView(R.layout.activity_download);
  26. progressBar= (LoadProgressBarWithNum) findViewById(R.id.progressbar);
  27. downloadBtn= (Button) findViewById(R.id.downloadBtn);
  28. //create DownLoadAsyncTask
  29. final DownLoadAsyncTask downLoadAsyncTask= new DownLoadAsyncTask(AsynTaskActivity.this);
  30. //set Interface
  31. downLoadAsyncTask.setUpdateUIInterface(this);
  32. //start download
  33. downloadBtn.setOnClickListener(new View.OnClickListener() {
  34. @Override
  35. public void onClick(View v) {
  36. //execute
  37. downLoadAsyncTask.execute(DOWNLOAD_FILE_JPG_URL);
  38. }
  39. });
  40. //android 6.0 权限申请
  41. if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
  42. != PackageManager.PERMISSION_GRANTED) {
  43. //android 6.0 API 必须申请WRITE_EXTERNAL_STORAGE权限
  44. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
  45. WRITE_EXTERNAL_STORAGE_REQUEST_CODE);
  46. }
  47. }
  48. @Override
  49. public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
  50. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  51. doNext(requestCode,grantResults);
  52. }
  53. private void doNext(int requestCode, int[] grantResults) {
  54. if (requestCode == WRITE_EXTERNAL_STORAGE_REQUEST_CODE) {
  55. if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  56. // Permission Granted
  57. LogUtils.e("Permission Granted");
  58. } else {
  59. // Permission Denied
  60. LogUtils.e("Permission Denied");
  61. }
  62. }
  63. }
  64. /**
  65. * update progressBar
  66. * @param values
  67. */
  68. @Override
  69. public void UpdateProgressBar(Integer values) {
  70. progressBar.setmProgress(values);;
  71. }
  72. }

  在AsynTaskActivity中实现了更新UI的接口DownLoadAsyncTask.UpdateUI,用于更新主线程的progressBar的进度,由于使用的测试版本是android6.0,涉及到外部SD卡读取权限的申请,所以在代码中对SD卡权限进行了特殊处理(这点不深究,不明白可以google一下),LoadProgressBarWithNum是一个自定义的进度条控件。ok~,最后看看我们的运行结果:

  效果符合预期,通过这个案例,相信我们对AsyncTask的使用已相当清晰了。基本使用到此,然后再来聊聊AsyncTask在不同android版本中的差异。

二、AsyncTask在不同android版本的下的差异

  这里我们主要区分一下android3.0前后版本的差异,在android
3.0之前,AsyncTask处理任务时默认采用的是线程池里并行处理任务的方式,而在android 3.0之后
,为了避免AsyncTask处理任务时所带来的并发错误,AsyncTask则采用了单线程串行执行任务。但是这并不意味着android
3.0之后只能执行串行任务,我们仍然可以采用AsyncTask的executeOnExecutor方法来并行执行任务。接下来,编写一个案例,分别在android
2.3.3 和 android 6.0上执行,然后打印输出日志。代码如下:

  1. package com.zejian.handlerlooper;
  2. import android.app.Activity;
  3. import android.os.AsyncTask;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.widget.Button;
  7. import com.zejian.handlerlooper.util.LogUtils;
  8. import java.text.SimpleDateFormat;
  9. import java.util.Date;
  10. /**
  11. * Created by zejian
  12. * Time 16/9/5.
  13. * Description:
  14. */
  15. public class ActivityAsyncTaskDiff extends Activity {
  16. private Button btn;
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_async_diff);
  21. btn= (Button) findViewById(R.id.btn);
  22. btn.setOnClickListener(new View.OnClickListener() {
  23. @Override
  24. public void onClick(View v) {
  25. new AysnTaskDiff("AysnTaskDiff-1").execute("");
  26. new AysnTaskDiff("AysnTaskDiff-2").execute("");
  27. new AysnTaskDiff("AysnTaskDiff-3").execute("");
  28. new AysnTaskDiff("AysnTaskDiff-4").execute("");
  29. new AysnTaskDiff("AysnTaskDiff-5").execute("");
  30. }
  31. });
  32. }
  33. private static class AysnTaskDiff extends AsyncTask<String ,Integer ,String>{
  34. private String name;
  35. public AysnTaskDiff(String name){
  36. super();
  37. this.name=name;
  38. }
  39. @Override
  40. protected String doInBackground(String... params) {
  41. try {
  42. Thread.sleep(2000);
  43. }catch (Exception ex){
  44. ex.printStackTrace();
  45. }
  46. return name;
  47. }
  48. @Override
  49. protected void onPostExecute(String s) {
  50. super.onPostExecute(s);
  51. SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  52. LogUtils.e(s+" execute 执行完成时间:"+df.format(new Date()));
  53. }
  54. }
  55. }

  案例代码比较简单,不过多分析,我们直接看在android 2.3.3 和 android 6.0上执行的结果,其中android 2.3.3上执行Log打印如下:

在 android 6.0上执行Log打印如下:

   从打印log可以看出AsyncTask在android 2.3.3上确实是并行执行任务的,而在 android
6.0上则是串行执行任务。那么了解这点有什么用呢?其实以前我也只是知道这回事而已,不过最近在SDK开发中遇到了AsyncTask的开发问题,产生问题的场景是这样的,我们团队在SDK中使用了AsyncTask作为网络请求类,因为现在大部分系统都是在Android

3.0以上的系统运行的,所以默认就是串行运行,一开始SDK在海外版往外提供也没有出现什么问题,直到后面我们提供国内一个publisher海外版本时,问题就出现了,该publisher接入我们的SDK后,他们的应用网络加载速度变得十分慢,后来他们一直没排查出啥问题,我们这边也在懵逼中……直到我们双方都找到一个点,那就是publisher的应用和我们的SDK使用的都是AsyncTask作为网络请求,那么问题就来,我们SDK是在在Application启动时触发网络的,而他们的应用也是启动Activity时去访问网络,所以SDK比应用先加载网络数据,但是!!!AsyncTask默认是串行执行的,所以!!只有等我们的SDK网络加载完成后,他们应用才开始加载网络数据,这就造成应用的网络加载延迟十分严重了。后面我们SDK在内部把AsyncTask改为并行任务后问题也就解决了(当然这也是SDK的一个BUG,考虑欠佳)。在Android

3.0之后我们可以通过下面代码让AsyncTask执行并行任务,其AsyncTask.THREAD_POOL_EXECUTOR为AsyncTask的内部线程池。

  1. new AysnTaskDiff("AysnTaskDiff-5").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
  • 1

   第一个参数传递是线程池,一般使用AsyncTask内部提供的线程池即可(也可以自己创建),第二个参数,就是最终会传递给doInBackground方法的可变参数,这里不传,所以直接给了空白符。执行效果就不再演示了,大家可以自行测试一下。
   ok~,到此AsyncTask在不同android版本中的差异也分析完,感觉文章有点长了,那么AsyncTask工作原理分析就放到下篇吧,晚安。。

简易源码下载:源码地址

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

主要参考资料:
https://developers.android.com
《android开发艺术探索》

android多线程-AsyncTask之工作原理深入解析(上)的更多相关文章

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

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

  2. Android ListView工作原理完全解析,带你从源码的角度彻底理解

    版权声明:本文出自郭霖的博客,转载必须注明出处.   目录(?)[+] Adapter的作用 RecycleBin机制 第一次Layout 第二次Layout 滑动加载更多数据   转载请注明出处:h ...

  3. Android ListView工作原理完全解析(转自 郭霖老师博客)

    原文地址:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android所有常用的原生控件当中,用法最复杂的应该就是ListVie ...

  4. Android ListView工作原理全然解析,带你从源代码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android全部经常使用的原生控件其中.使用方法最复杂的应该就是 ...

  5. Android 多线程-----AsyncTask详解

    您可以通过点击 右下角 的按钮 来对文章内容作出评价, 也可以通过左下方的 关注按钮 来关注我的博客的最新动态. 如果文章内容对您有帮助, 不要忘记点击右下角的 推荐按钮 来支持一下哦 如果您对文章内 ...

  6. Android 多线程----AsyncTask异步任务详解

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  7. 深入理解AsyncTask的工作原理

    一.为什么需要工作者线程 我们知道,Android应用的主线程(UI 线程)肩负着绘制用户界面和及时响应用户操作的重任,为了避免“用户点击按钮后没反应”这样的糟糕用户体验,我们就要确保主线程时刻保持着 ...

  8. AsyncTask的工作原理

    AsyncTask是Android本身提供的一种轻量级的异步任务类.它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程更新UI.实际上,AsyncTask内部是封装了Thread和 ...

  9. 路由及路由器工作原理深入解析3:路由与port

        日志"路由及路由器工作原理深入解析1"http://user.qzone.qq.com/2756567163/blog/1438322342介绍了"为什么要使用路 ...

随机推荐

  1. bzoj 1191 匈牙利算法

    只需要做一遍匈牙利,只要有一个没法匹配上就break就行了 /************************************************************** Proble ...

  2. algorithm ch2 insertsort

    刚开始看到insertsort,思路就是使用新来的元素与前述已经排好序的元素比较.然后进行插入或者跳到下一次比较. 实现的代码如下: void InsertSort(int *pArray, int ...

  3. android 使用开源库zxing生成二维码,扫描二维码【转】

    转自:http://blog.csdn.net/qq_16064871/article/details/52422723 zxing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库 ...

  4. Javacore分析(转载)

    本文转自(http://www.ibm.com/developerworks/cn/websphere/library/techarticles/1406_tuzy_javacore/1406_tuz ...

  5. bootstrap,ECMA

    前端UI(布局)框架 bootstrap Amaze UI BootStrap 全局css样式 栅格系统 container 容器 超小屏幕 手机 vw <768px 宽度 100% 小屏幕 平 ...

  6. 2.kafka单节点broker的安装与启动

    下载kafka,http://kafka.apache.org/downloads kafka下面的文件结构如下: 进入bin目录,启动kafka之前要先启动zookeeper ./zookeeper ...

  7. Centos7/RHEL 7 配置静态路由

    如图: 业务地址:192.168.10.0/24    192.168.20.0/24管理地址:172.168.10.0/24    172.168.20.0/24 需求:每台主机配置两张网卡,分别连 ...

  8. mvvm command的使用案例

    主界面如下: 前台代码: <Window x:Class="WpfApp1.MainWindow"        xmlns="http://schemas.mic ...

  9. 大数据量的Mysql数据库备份策略

    Centos下mysql常用的三种备份方法 http://www.centoscn.com/CentOS/Intermediate/2013/0807/1160.html xtrabackup备份 h ...

  10. int 与 String 与 char 之间的互相转换

    int 转 String: //方式一: int i1 = 888; String s1 = Integer.toString(i1); //方式二: int i2 = 888; String s2 ...