2019-11-23

【Kotlin】Volley -- 輕量 httpclient

參考資料 ----
Volley overview  

github/google/volley


VolleyJetpack 的一員,能讓開發者以簡單的方式寫出與 httpclient 相同功能的程式,並且速度更快。不過 Volley 只適合輕量的網路傳輸,所以諸如檔案的下載或串流的操作,仍建議以原有的方式執行,如:DownloadManager


AndroidManifest.xml 加入網路權限

  1.  
  2. <uses-permission android:name="android.permission.INTERNET" />
  3.  
  4. <application
  5. ...
  6. ...
  7.  



app 層級的 build.gradle 加入相關宣告
  1.  
  2. ...
  3. ...
  4.  
  5. dependencies {
  6. ...
  7. implementation 'com.android.volley:volley:1.1.1'
  8. }
  9.  


activity_main.xml
  1.  
  2. <?xml version="1.0" encoding="utf-8"?>
  3. <androidx.constraintlayout.widget.ConstraintLayout
  4. xmlns:android="http://schemas.android.com/apk/res/android"
  5. xmlns:app="http://schemas.android.com/apk/res-auto"
  6. xmlns:tools="http://schemas.android.com/tools"
  7. android:layout_width="match_parent"
  8. android:layout_height="match_parent"
  9. tools:context=".MainActivity">
  10.  
  11. <TextView
  12. android:id="@+id/textView"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:text="Hello World!"
  16. app:layout_constraintBottom_toBottomOf="parent"
  17. app:layout_constraintLeft_toLeftOf="parent"
  18. app:layout_constraintRight_toRightOf="parent"
  19. app:layout_constraintTop_toTopOf="parent" />
  20.  
  21. <Button
  22. android:id="@+id/button"
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:layout_marginTop="96dp"
  26. android:text="Button"
  27. app:layout_constraintBottom_toTopOf="@+id/textView"
  28. app:layout_constraintEnd_toEndOf="parent"
  29. app:layout_constraintHorizontal_bias="0.482"
  30. app:layout_constraintStart_toStartOf="parent"
  31. app:layout_constraintTop_toTopOf="parent"
  32. app:layout_constraintVertical_bias="0.07"
  33. android:onClick="sendrequest"/>
  34.  
  35. </androidx.constraintlayout.widget.ConstraintLayout>
  36.  


MainActivity.kt(最陽春的範例)
  1.  
  2.  
  3. import android.app.Activity
  4. import android.os.Bundle
  5. import android.view.View
  6. import android.widget.TextView
  7. import com.android.volley.Request
  8. import com.android.volley.Response
  9. import com.android.volley.toolbox.StringRequest
  10. import com.android.volley.toolbox.Volley
  11.  
  12. class MainActivity : Activity()
  13. {
  14. val TAG = "MyTag"
  15.  
  16.  
  17. override fun onCreate(savedInstanceState: Bundle?)
  18. {
  19. super.onCreate(savedInstanceState)
  20. setContentView(R.layout.activity_main)
  21. }
  22.  
  23.  
  24. fun sendrequest(v: View)
  25. {
  26. val queue = Volley.newRequestQueue(this)
  27. val url = "https://您的網址/php程式.php"
  28. val textView = findViewById(R.id.textView)
  29. val stringRequest = StringRequest(Request.Method.GET,
  30. url,
  31. Response.Listener<String> { response -> textView.text = response.toString()},
  32. Response.ErrorListener { error ->
  33. Log.d(TAG, "volley error: %s".format(error.toString()))
  34. textView.text = "volley error"
  35. }
  36. )
  37.  
  38. // Add the request to the RequestQueue.
  39. queue.add(stringRequest)
  40. }
  41. }
  42.  


app 執行後,一按 button,就會看到 TextView 顯示回傳的字串,超簡單的!





Google 仍強烈建議不要在主執行緒(UI thread) 執行。


方法二


新增一個 VolleyService.kt
  1.  
  2. package 完整packagename
  3.  
  4. import android.content.Context
  5. import com.android.volley.RequestQueue
  6. import com.android.volley.toolbox.Volley
  7.  
  8.  
  9. object VolleyService
  10. {
  11. private lateinit var context: Context
  12. val requestQueue: RequestQueue by lazy { Volley.newRequestQueue(context) }
  13.  
  14. fun initialize(context: Context)
  15. {
  16. this.context = context.applicationContext
  17. }
  18. }
  19.  


再新增一個 Application 級的 class:App.kt
  1.  
  2. package 完整packagename
  3.  
  4. import android.app.Application
  5.  
  6.  
  7. class App : Application()
  8. {
  9. override fun onCreate()
  10. {
  11. super.onCreate()
  12. VolleyService.initialize(this)
  13. }
  14. }
  15.  


微調一下 AndroidManifest.xml
  1.  
  2. ...
  3. ...
  4.  
  5. <uses-permission android:name="android.permission.INTERNET" />
  6.  
  7. <application
  8. android:name=".App"
  9. ...
  10. ...
  11.  


再微調 MainActivity.kt
  1.  
  2. ...
  3. ...
  4.  
  5. fun sendrequest(v: View)
  6. {
  7. val url = "https://網址/php程式"
  8. val textView = findViewById(R.id.textView)
  9. // Request a string response from the provided URL.
  10. val stringRequest = StringRequest(Request.Method.GET, url,
  11. Response.Listener<string> { response -> textView.text = response.toString() },
  12. Response.ErrorListener { textView.text = "That didn't work!" }
  13. )
  14.  
  15. // 呼叫 VolleyService
  16. VolleyService.requestQueue.add(stringRequest)
  17. VolleyService.requestQueue.start()
  18. }
  19.  


Volley 也可以直接取得 json



在本例中,自網站取得的是一個 json 陣列,陣列元素組成為 exno, exname, exdate 三個字串,改用 ListView 顯示

activity_main.xml
  1.  
  2. <?xml version="1.0" encoding="utf-8"?>
  3. <RelativeLayout
  4. xmlns:android="http://schemas.android.com/apk/res/android"
  5. xmlns:app="http://schemas.android.com/apk/res-auto"
  6. xmlns:tools="http://schemas.android.com/tools"
  7. android:layout_width="match_parent"
  8. android:layout_height="match_parent"
  9. tools:context=".MainActivity">
  10.  
  11. <Button
  12. android:id="@+id/button"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:layout_alignParentStart="true"
  16. android:layout_alignParentLeft="true"
  17. android:layout_alignParentTop="true"
  18. android:layout_marginStart="32dp"
  19. android:layout_marginLeft="32dp"
  20. android:text="get json"
  21. android:onClick="getjson" />
  22.  
  23. <ListView
  24. android:id="@+id/lv"
  25. android:layout_width="match_parent"
  26. android:layout_height="match_parent"
  27. android:layout_below="@id/button"
  28. android:layout_marginTop="10dp"
  29. android:layout_marginLeft="10dp"
  30. android:layout_marginRight="10dp" />
  31.  
  32. </RelativeLayout>
  33.  


新增 list_item.xml
  1.  
  2. <?xml version="1.0" encoding="utf-8"?>
  3.  
  4. <RelativeLayout
  5. xmlns:android="http://schemas.android.com/apk/res/android"
  6. android:layout_width="fill_parent"
  7. android:layout_height="wrap_content"
  8. android:paddingBottom="6dp"
  9. android:paddingLeft="6dp"
  10. android:paddingRight="6dp"
  11. android:paddingTop="6dp" >
  12.  
  13. <TextView
  14. android:id="@+id/lblExno"
  15. android:layout_alignParentTop="true"
  16. android:layout_alignParentLeft="true"
  17. android:layout_alignParentStart="true"
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content"
  20. android:text="exno"
  21. android:textAppearance="?android:attr/textAppearanceSmall"
  22. android:visibility="gone"/>
  23. <TextView
  24. android:id="@+id/lblExname"
  25. android:layout_below="@+id/lblExno"
  26. android:layout_alignParentLeft="true"
  27. android:layout_alignParentStart="true"
  28. android:layout_width="wrap_content"
  29. android:layout_height="wrap_content"
  30. android:text="exam_name"
  31. android:textColor="@android:color/holo_blue_dark"
  32. android:textAppearance="?android:attr/textAppearanceMedium" />
  33.  
  34. <TextView
  35. android:id="@+id/lblExdate"
  36. android:layout_alignParentLeft="true"
  37. android:layout_alignParentStart="true"
  38. android:layout_below="@+id/lblExname"
  39. android:layout_width="wrap_content"
  40. android:layout_height="wrap_content"
  41. android:text="exam_date"
  42. android:textColor="@android:color/holo_blue_dark"
  43. android:textAppearance="?android:attr/textAppearanceSmall" />
  44. </RelativeLayout>
  45.  


新增 ListAdapter.kt
  1.  
  2. ...
  3. ...
  4.  
  5. class ListAdapter(private val activity: Activity, private val mExno: List<*>, private val mExname: List<*>, private val mExdate: List<*>) : BaseAdapter()
  6. {
  7.  
  8. init
  9. {
  10. inflater = activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
  11. }
  12.  
  13. override fun getCount(): Int
  14. {
  15. return mExno.size
  16. }
  17.  
  18. override fun getItem(position: Int): Any
  19. {
  20. return position
  21. }
  22.  
  23. override fun getItemId(position: Int): Long
  24. {
  25. return position.toLong()
  26. }
  27.  
  28. override fun getView(position: Int, convertView: View?, parent: ViewGroup): View
  29. {
  30. var vi = convertView
  31. if (convertView == null)
  32. {
  33. vi = inflater!!.inflate(R.layout.list_item, null)
  34. }
  35.  
  36. val lblExno = vi!!.findViewById<view>(R.id.lblExno) as TextView
  37. val lblExname = vi.findViewById<view>(R.id.lblExname) as TextView
  38. val lblExdate = vi.findViewById<view>(R.id.lblExdate) as TextView
  39.  
  40. lblExno.text = mExno[position].toString()
  41. lblExname.text = mExname[position].toString()
  42. lblExdate.text = mExdate[position].toString()
  43.  
  44. return vi
  45. }
  46.  
  47. companion object
  48. {
  49. private var inflater: LayoutInflater? = null
  50. }
  51. }
  52.  


MainActivity.kt
  1.  
  2. ...
  3. ...
  4.  
  5. class MainActivity : Activity()
  6. {
  7. val TAG = "MyTag"
  8.  
  9. override fun onCreate(savedInstanceState: Bundle?)
  10. {
  11. super.onCreate(savedInstanceState)
  12. setContentView(R.layout.activity_main)
  13. }
  14.  
  15. override fun onStop()
  16. {
  17. super.onStop()
  18. VolleyService.requestQueue?.cancelAll(TAG)
  19. }
  20.  
  21. fun getjson(v: View)
  22. {
  23. val lv = findViewById(R.id.lv) as ListView
  24. val url = "https://網址/php程式"
  25. val stringRequest = JsonArrayRequest(Request.Method.GET, url, null,
  26. Response.Listener<JSONArray>
  27. {
  28. response -> var listExno: MutableList<String> = ArrayList()
  29. var listExname: MutableList<String> = ArrayList()
  30. var listExdate: MutableList<String> = ArrayList()
  31. for(x in 0..(response.length()-1))
  32. {
  33. var exam = response.getJSONObject(x)
  34. listExno.add(exam.getString("exno"))
  35. listExname.add(exam.getString("exname"))
  36. listExdate.add(exam.getString("exdate"))
  37. }
  38. val adapterExam = ListAdapter(this@MainActivity, listExno, listExname, listExdate)
  39. lv.setAdapter(adapterExam)
  40. },
  41. Response.ErrorListener
  42. {
  43. Toast.makeText(this, "That didn't work!", Toast.LENGTH_SHORT).show()
  44. }
  45. )
  46.  
  47. // 呼叫 VolleyService
  48. VolleyService.requestQueue.add(stringRequest)
  49. VolleyService.requestQueue.start()
  50.  
  51. }
  52. }
  53.  
  54.