App Overview

I Use Douban Api instead of Google Book Api for this demo.

【Android 基础7.1 7.2】AsyncTask & AsyncTaskLoader_第1张图片

AsyncTask Inro

AsyncTask is an abstract class, which means you must subclass it in order to use it. In this example the AsyncTask performs a very simple background task: it sleeps for a random amount of time. In a real app, the background task could perform all sorts of work, from querying a database, to connecting to the internet, to calculating the next Go move to beat the current Go champion.

An AsyncTask subclass has the following methods for performing work off of the main thread:

  • onPreExecute(): This method runs on the UI thread, and is used for setting up your task (like showing a progress bar).
  • doInBackground(): This is where you implement the code to execute the work that is to be performed on the separate thread.
  • onProgressUpdate(): This is invoked on the UI thread and used for updating progress in the UI (such as filling up a progress bar)
  • onPostExecute(): Again on the UI thread, this is used for updating the results to the UI once the AsyncTask has finished loading.

【Android 基础7.1 7.2】AsyncTask & AsyncTaskLoader_第2张图片

So, in a word, onPreExecute() , onProgressUpdate() and onPostExecute() is run on UI thread, doINBackground() run on worker thread.

Params

When you create an AsyncTask subclass, you can configure it using these parameters:

  • Params: The data type of the parameters sent to the task upon executing the doInBackground() override method.
  • Progress: The data type of the progress units published using the onProgressUpdated()override method.
  • Result: The data type of the result delivered by the onPostExecute() override method.

Simple implement

When onPreExecute() , onProgressUpdate() and onPostExecute() is run on UI thread, we can define a callback to expose these method, so we can call in Activity, and do not need to pass UI elements to AsyncTask. So In Java, a callback is a interface.

  • Define a callback:

      interface Callback<T, STATUS> {      fun onNext(t: T)      fun onUpdate(status: STATUS)      fun onError(t: Throwable)  }
  • Hold a weak reference in AsyncTask:

    class SearchMovieAsyncTask(private val callback: WeakReference<Callback<ArrayList<Movie>, Boolean>>) :    AsyncTask<String, Boolean, ArrayList<Movie>?>() {}
      override fun doInBackground(vararg querys: String?): ArrayList<Movie>? {      val query = querys[0] ?: return null      publishProgress(true)      return NetUtil.getMovieList(query)  }  override fun onProgressUpdate(vararg values: Boolean?) {      callback.get()?.onUpdate(values[0] ?: true)  }  override fun onPostExecute(result: ArrayList<Movie>?) {      super.onPostExecute(result)      if (result != null) {          callback.get()?.onNext(result)      } else {          callback.get()?.onError(NullPointerException(result))      }  }
  • Implement callback in MainActivity:

            callback = object : SearchMovieAsyncTask.Callback<ArrayList<Movie>, Int> {            override fun onUpdate(status: Int) {                progressBar.visibility = View.VISIBLE            }            override fun onNext(movies: ArrayList<Movie>) {                adapter.clear()                adapter.addAll(movies)                progressBar.visibility = View.INVISIBLE            }            override fun onError(t: Throwable) {                Toast.makeText(this@MainActivity, "Error: ${t.message}", Toast.LENGTH_SHORT).show()            }        }

AsyncTaskLoader

This is same as define a custom callback, but Android already done it for us.It called AsyncTaskLoader.

If you want a more flexible interaction a custom callback is ok.

Create an AsyncTaskLoader

import android.support.v4.content.AsyncTaskLoaderclass MovieLoader(val mContext: WeakReference<Context>, val query: String) :    AsyncTaskLoader<ArrayList<Movie>>(mContext.get()!!) {}

Implement loadInBackground

Notice the similarity between this method and the initial doInBackground() method from AsyncTask.

    override fun loadInBackground(): ArrayList<Movie>? {        return NetUtil.getMovieList(query)    }

Implement required methods

Inside the onStartLoading() method stub, call forceLoad() to start the loadInBackground() method. The loader will not start loading data until you call the forceLoad() method.

    override fun onStartLoading() {        super.onStartLoading()        forceLoad()    }

Modify MainActivity

class MainActivity : AppCompatActivity(), LoaderManager.LoaderCallbacks<ArrayList<Movie>> {        override fun onCreateLoader(id: Int, args: Bundle?): Loader<ArrayList<Movie>> {        return MovieLoader(WeakReference(this), args?.getString("query")!!)    }    override fun onLoadFinished(loader: Loader<ArrayList<Movie>>, list: ArrayList<Movie>?) {        adapter.clear()        adapter.addAll(list ?: emptyList())        progressBar.visibility = View.INVISIBLE    }    override fun onLoaderReset(list: Loader<ArrayList<Movie>>) {    }}

Start Loader

The restartLoader() method is defined by the LoaderManager, which manages all the loaders used in an activity or fragment. Each activity has exactly one LoaderManager instance that is responsible for the lifecycle of the Loaders that the activity manages.

val queryBundle = Bundle()queryBundle.putString("query", s)Log.d(TAG, "onQueryTextSubmit: restart loader")this@MainActivity.supportLoaderManager.restartLoader(0, queryBundle, this@MainActivity)

Restore Loader

    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main_search)                if (supportLoaderManager.getLoader<ArrayList<Movie>>(0) != null) {            supportLoaderManager.initLoader(0, null, this);        }     }

NetUtil

Without any library, just use raw java to do network and parse json:

object NetUtil {    const val TAG = "NetUtil"    val API = "https://api.douban.com/v2/movie/search?q=%s&apikey=0b2bdeda43b5688921839c8ecb20399b&start=0&count=20"    fun getMovieList(query: String): ArrayList<Movie>? {        val url = URL(API.format(query))        var urlConnection: URLConnection? = null        var bufferReader: BufferedReader? = null        var json: String = ""        try {            urlConnection = url.openConnection() as HttpURLConnection            with(urlConnection) {                requestMethod = "GET"                connect()            }            val inputStream = urlConnection.inputStream            bufferReader = BufferedReader(InputStreamReader(inputStream))            Log.d(TAG, "doInBackground: start read")            json = buildString {                var line = bufferReader.readLine()                while (line != null) {                    append(line)                    append("\n")                    line = bufferReader.readLine()                }            }            if (json.isEmpty()) {                return null            }        } catch (e: IOException) {            e.printStackTrace()        } finally {            bufferReader?.close()        }        Log.d(TAG, "doInBackground: $json")        val movieList = ArrayList<Movie>()        try {            val jsonObject = JSONObject(json)            val movieArray = jsonObject.getJSONArray("subjects")            var i = 0            while (i < movieArray.length()) {                val subject = movieArray.getJSONObject(i)                val title = subject.getString("title")                val year = subject.getString("year")                movieList.add(Movie(subject.getString("id"), title, year))                i++                Log.d(TAG, "doInBackground: title: $title, year: $year")            }        } catch (e: Exception) {            e.printStackTrace()        }        return movieList    }}

更多相关文章

  1. Android手机操作系统中实现图片浏览
  2. Android 利用Matrix实现图片随手指平移、旋转、缩放
  3. Android中网络编程以及与服务器上Web项目的基础交互
  4. Android应用程序基础知识
  5. 巧用Android图片资源,打造更精致的APP
  6. Android Studio 基础 之 如何取消使用 Android X 的操作(附有详细
  7. Android 实现图片保存到本地并调用本地地址显示图片
  8. Android设置拍照或者上传本地图片

随机推荐

  1. android快捷方式的创建与删除
  2. Android(安卓)3G网络下 http refused 解
  3. Android(安卓)设置全屏,画图,加载位图
  4. [Android]自定义系统菜单的背景
  5. android友盟注意事项
  6. Js001-数据变量与函数
  7. centos8.0配置静态IP详解及永久关闭防火
  8. JS 对象模拟数组
  9. PHP 基于 SW-X 框架,搭建WebSocket服务器(
  10. 百度小程序源码之追格资讯小程序源码下载