參考資料 ----
Volley overview
github/google/volley
Volley 是 Jetpack 的一員,能讓開發者以簡單的方式寫出與 httpclient 相同功能的程式,並且速度更快。不過 Volley 只適合輕量的網路傳輸,所以諸如檔案的下載或串流的操作,仍建議以原有的方式執行,如:DownloadManager。
在 AndroidManifest.xml 加入網路權限
<uses-permission android:name="android.permission.INTERNET" /> <application ... ...
在 app 層級的 build.gradle 加入相關宣告
... ... dependencies { ... implementation 'com.android.volley:volley:1.1.1' }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="96dp" android:text="Button" app:layout_constraintBottom_toTopOf="@+id/textView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.482" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.07" android:onClick="sendrequest"/> </androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt(最陽春的範例)
import android.app.Activity import android.os.Bundle import android.view.View import android.widget.TextView import com.android.volley.Request import com.android.volley.Response import com.android.volley.toolbox.StringRequest import com.android.volley.toolbox.Volley class MainActivity : Activity() { val TAG = "MyTag" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun sendrequest(v: View) { val queue = Volley.newRequestQueue(this) val url = "https://您的網址/php程式.php" val textView = findViewById(R.id.textView) val stringRequest = StringRequest(Request.Method.GET, url, Response.Listener<String> { response -> textView.text = response.toString()}, Response.ErrorListener { error -> Log.d(TAG, "volley error: %s".format(error.toString())) textView.text = "volley error" } ) // Add the request to the RequestQueue. queue.add(stringRequest) } }
app 執行後,一按 button,就會看到 TextView 顯示回傳的字串,超簡單的!
但 Google 仍強烈建議不要在主執行緒(UI thread) 執行。
方法二
新增一個 VolleyService.kt
package 完整packagename import android.content.Context import com.android.volley.RequestQueue import com.android.volley.toolbox.Volley object VolleyService { private lateinit var context: Context val requestQueue: RequestQueue by lazy { Volley.newRequestQueue(context) } fun initialize(context: Context) { this.context = context.applicationContext } }
再新增一個 Application 級的 class:App.kt
package 完整packagename import android.app.Application class App : Application() { override fun onCreate() { super.onCreate() VolleyService.initialize(this) } }
微調一下 AndroidManifest.xml
... ... <uses-permission android:name="android.permission.INTERNET" /> <application android:name=".App" ... ...
再微調 MainActivity.kt
... ... fun sendrequest(v: View) { val url = "https://網址/php程式" val textView = findViewById(R.id.textView) // Request a string response from the provided URL. val stringRequest = StringRequest(Request.Method.GET, url, Response.Listener<string> { response -> textView.text = response.toString() }, Response.ErrorListener { textView.text = "That didn't work!" } ) // 呼叫 VolleyService VolleyService.requestQueue.add(stringRequest) VolleyService.requestQueue.start() }
Volley 也可以直接取得 json
在本例中,自網站取得的是一個 json 陣列,陣列元素組成為 exno, exname, exdate 三個字串,改用 ListView 顯示
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginStart="32dp" android:layout_marginLeft="32dp" android:text="get json" android:onClick="getjson" /> <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/button" android:layout_marginTop="10dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" /> </RelativeLayout>
新增 list_item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingBottom="6dp" android:paddingLeft="6dp" android:paddingRight="6dp" android:paddingTop="6dp" > <TextView android:id="@+id/lblExno" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="exno" android:textAppearance="?android:attr/textAppearanceSmall" android:visibility="gone"/> <TextView android:id="@+id/lblExname" android:layout_below="@+id/lblExno" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="exam_name" android:textColor="@android:color/holo_blue_dark" android:textAppearance="?android:attr/textAppearanceMedium" /> <TextView android:id="@+id/lblExdate" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_below="@+id/lblExname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="exam_date" android:textColor="@android:color/holo_blue_dark" android:textAppearance="?android:attr/textAppearanceSmall" /> </RelativeLayout>
新增 ListAdapter.kt
... ... class ListAdapter(private val activity: Activity, private val mExno: List<*>, private val mExname: List<*>, private val mExdate: List<*>) : BaseAdapter() { init { inflater = activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater } override fun getCount(): Int { return mExno.size } override fun getItem(position: Int): Any { return position } override fun getItemId(position: Int): Long { return position.toLong() } override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { var vi = convertView if (convertView == null) { vi = inflater!!.inflate(R.layout.list_item, null) } val lblExno = vi!!.findViewById<view>(R.id.lblExno) as TextView val lblExname = vi.findViewById<view>(R.id.lblExname) as TextView val lblExdate = vi.findViewById<view>(R.id.lblExdate) as TextView lblExno.text = mExno[position].toString() lblExname.text = mExname[position].toString() lblExdate.text = mExdate[position].toString() return vi } companion object { private var inflater: LayoutInflater? = null } }
MainActivity.kt
... ... class MainActivity : Activity() { val TAG = "MyTag" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun onStop() { super.onStop() VolleyService.requestQueue?.cancelAll(TAG) } fun getjson(v: View) { val lv = findViewById(R.id.lv) as ListView val url = "https://網址/php程式" val stringRequest = JsonArrayRequest(Request.Method.GET, url, null, Response.Listener<JSONArray> { response -> var listExno: MutableList<String> = ArrayList() var listExname: MutableList<String> = ArrayList() var listExdate: MutableList<String> = ArrayList() for(x in 0..(response.length()-1)) { var exam = response.getJSONObject(x) listExno.add(exam.getString("exno")) listExname.add(exam.getString("exname")) listExdate.add(exam.getString("exdate")) } val adapterExam = ListAdapter(this@MainActivity, listExno, listExname, listExdate) lv.setAdapter(adapterExam) }, Response.ErrorListener { Toast.makeText(this, "That didn't work!", Toast.LENGTH_SHORT).show() } ) // 呼叫 VolleyService VolleyService.requestQueue.add(stringRequest) VolleyService.requestQueue.start() } }