• 异步请求的基本实现


    UI 进程的限制

    对于一个合格的安卓应用来说,流畅的界面操作是必不可少的。但是实际的应用会有不少的IO操作,例如更新数据库,访问本地文件或者网络,这些都需要消耗不少时间。如果界面线程和这些IO混合在一起,就会拖慢界面。这个时候,就需要将这些耗时的工作剥离,转由其他的异步线程来处理。

    异步和同步

    java 程序是一步一步的执行的,比如有三个任务,task1, task2,task3,默认情况下,这三个任务按顺序执行。

    task1.run();
    task2.run();
    task3.run();
    

    task2必须等待task1执行完毕后才能开始,task3同理。假设task1是一个IO类的任务,比如访问远端API,那么在请求发出和收到回复之间的时间, cpu是空闲的。这就造成了资源的浪费。

    有一种办法,可以让这段空闲的时间做其他的事情,这就是异步线程。其实也就是再启动一个线程, java 中可以用 thread类 或者 实现 runnable接口来实现一个线程。android 中不必这么做,sdk 提供了更方便的实现。那就是 AsyncTask。

    安卓中的简单实现

    AsyncTask,即异步任务。只需要继承并重写几个生命周期方法,就可以实现一个异步线程。

    要点

    AsyncTask 的要点有两部分

    • 生命周期方法

      有三个重要的方法, 按照执行的时机先后,依次是 onPostExecute, doInBackground, onPostExecute,分别表异步任务执行前的工作,待执行任务,和执行结束后的工作

      onProgressUpdate 和 publishProgress 支持自定义进度。在 doInBackground 中对具体业务进度进行分析后,得出一个进度值(类型自定),通过 publishProgress 发布进度,onProgressUpdate
      得到执行(参数就是刚才发布的进度值)。

    • 更新UI

      大部分时候,task 进行中和结束后会更新UI,比如进度条,可能是更新一个结果列表(listView)。那么,如何更新呢? 在 activity 中自然是可以findViewById,然后更新。但是 task 中没有这样的context。目前知道的办法是,创建 task 的时候,将这个 listView 作为构造方法的参数传递进去,然后就可以将它存储为 task 的成员变量,进而在任务结束后操作。

    基本结构

    下面的类用于遍历获取目录中所有文件的数目

    //定义类的时候指定了线程相关的3个参数的类型,分别是启动参数,进度参数,返回值
    //File 是执行execute方法时的参数类型, 第一个 Integer 是进度的参数类型,第二个 Integer 是后台线程返回数据的类型,即 doInBackground 的返回值类型
    public class FileCrawler extends AsyncTask<File, Integer, Integer> {
        
        @Override
        // params 就是下面执行execute的时候传入的参数 directoryPath
        protected Long doInBackground(File ...params) {
           //这里执行一些耗时的代码
        }
    
        @Override
        //categories 是 doInBackground 返回的结果
        protected void onPostExecute(Integer sum){
            
            //异步线程结束后,执行这里。通常可以在这里更新UI
        }
    
    }
    

    可以直接在activity的onCreate中调用

    new FileCrawler(getBaseContext()).execute(directoryPath);
    

    例子

    文件遍历是一个比较复杂的问题,尤其对于大量的文件,直接用递归的话可能会出现内存溢出问题。apache 的 common io 是一个不错的工具包,有很多io相关的工具类。这里使用其中的 FileUtils来遍历文件。

    完整的代码

    FileCrawler.java

    /**
     * Created by wangpi on 6/30/2016.
     */
    public class FileCrawler extends AsyncTask<File, Integer, Integer>{
        private TextView view;
        public FileCrawler(TextView view ){
            this.view = view;
        }
    
        @Override
        protected Integer doInBackground(File... folders) {
            Collection<File> files = null;
            for(File folder : folders){
                if(folder.exists() && folder.isDirectory()){
                    if(files == null) {
                        files = FileUtils.listFiles(folder, null, true);
                    }else{
                        files.addAll(FileUtils.listFiles(folder, null, true));
                    }
                }
            }
            if(files != null){
                return files.size();
            }else{
                return 0;
            }
        }
    
        @Override
        protected void onPostExecute(Integer sum){
            view.setText("File amout : " + sum);
        }
    }
    

    MainActivity.java

    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            File[] folders = {Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)};
            new FileCrawler((TextView)findViewById(R.id.info)).execute(folders);
        }
    }
    
    
  • 相关阅读:
    我的算法日志:数据结构之顺序队列与循环队列
    我的算法日志:排序算法之快速排序
    算法:冒泡排序
    算法:桶排序(简易版)
    Android:配置LitePal 3.0
    Android:简单粗暴的二维码生成与扫描
    Linux
    Python
    Linux
    Python
  • 原文地址:https://www.cnblogs.com/Rexxar/p/5627855.html
Copyright © 2020-2023  润新知