App Overview

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

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.

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. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. ANDROID 经典开源项目
  2. Android自定义组合控件
  3. android获取通讯录
  4. android使用actionbar与fragment
  5. android 酷欧天气完整项目
  6. 触摸事件的机制
  7. ui?
  8. Android Volley的简单使用
  9. Android与JS通过JSBridge(BridgeWebView
  10. 下载显示网路图片的例子