I can not override getParam like shown below. I hope someone can explain how to override getParam in Kotlin.
build.gradle
implementation 'com.android.volley:volley:1.1.1'
fun testpost(button: Button)
{
val url = "http://192.168.178.23/insertcode.php"
val queue = Volley.newRequestQueue(this)
val stringRequest = StringRequest(Request.Method.POST, url,
{ response ->
button.text = "Response is: ${response}"
},
{ button.text = "That didn't work!" })
{
override fun getParam(){
}
}
queue.add(stringRequest)
}
Typing object before StringRequest and now the method getParams is available.
The code looks like this:
fun testpost(button: Button)
{
val url = "http://192.168.178.23/insertcode.php"
val queue = Volley.newRequestQueue(this)
val stringRequest = object :StringRequest(Request.Method.POST, url,
{ response ->
button.text = "Response is: ${response}"
},
{ button.text = "That didn't work!" })
{
//Press Ctr + O to find getParams
override fun getParams(): MutableMap<String, String> {
val hashMap = HashMap<String, String>()
hashMap.put("name", "peter")
return hashMap
}
}
queue.add(stringRequest)
}
You can't, it's not exposed in StringRequest or any other built in request for that matter. If that's indeed what you need to do, you have to unfortunately create your own custom request.
Below is an example for a Custom StringRequest which allows us to specify params in its constructor (Kotlin):
import androidx.annotation.GuardedBy
import com.android.volley.NetworkResponse
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.HttpHeaderParser
import java.io.UnsupportedEncodingException
import java.nio.charset.Charset
class CustomStringRequest(
method: Int,
url: String,
listener: Response.Listener<String>,
errorListener: Response.ErrorListener?,
private val params: MutableMap<String, String>
) : Request<String>(method, url, errorListener) {
private val lock = Any()
#GuardedBy("lock")
private var listener: Response.Listener<String>? = listener
override fun getParams(): MutableMap<String, String> {
return params
}
override fun cancel() {
super.cancel()
synchronized(lock) { listener = null }
}
override fun deliverResponse(response: String) {
var listener: Response.Listener<String>?
synchronized(lock) { listener = this.listener }
if (listener != null) {
listener!!.onResponse(response)
}
}
override fun parseNetworkResponse(response: NetworkResponse): Response<String> {
val parsed: String = try {
String(response.data, Charset.forName(HttpHeaderParser.parseCharset(response?.headers)))
} catch (e: UnsupportedEncodingException) {
// Since minSdkVersion = 8, we can't call
// new String(response.data, Charset.defaultCharset())
// So suppress the warning instead.
String(response.data)
}
return Response.success(
parsed,
HttpHeaderParser.parseCacheHeaders(response)
)
}
}
You would then use it like:
// Instantiate the RequestQueue.
val queue = Volley.newRequestQueue(activity)
val url = "YOUR_URL"
// Request a string response from the provided URL.
val stringRequest = CustomStringRequest(
Request.Method.POST, url,
Response.Listener { response ->
// TODO do something with response
},
Response.ErrorListener {
// TODO handle errors
},
hashMapOf("name" to "value") // TODO add your params here
)
// Add the request to the RequestQueue.
queue.add(stringRequest)
Related
I want to get the result from volley and then parse the result to create a model arraylist and the functional that calling the volley request should return the arraylist, the function is called from various other activities and code is written by someone else so I need to figure out a way to achieve the same within this class
Here's the full class code
class Mock #Inject constructor(private val context: Context) {
val url = Constant.prefix + "get_short_videos.php"
fun loadMockData(): ArrayList<StoriesDataModel>? {
// val mockData = context.resources.openRawResource(R.raw.stories_data)
// val dataString = mockData.bufferedReader().readText()
val scope = CoroutineScope(Dispatchers.Main).launch {
val data = getData()
}
Log.e("Rresponse",dataString+"-");
val gson = Gson()
val storiesType = object : TypeToken<ArrayList<StoriesDataModel>>() {}.type
val storiesDataModelList = gson.fromJson<ArrayList<StoriesDataModel>>(dataString, storiesType)
return storiesDataModelList
}
suspend fun getData() = suspendCoroutine<String> { cont ->
val requestQueue = Volley.newRequestQueue(context)
val postRequest: StringRequest = object : StringRequest(
Method.POST, url,
Response.Listener { response: String? ->
Log.e("response",response.toString());
cont.resume(response.toString())
},
Response.ErrorListener { error: VolleyError ->
error.printStackTrace()
Toast.makeText(context, "Check your internet connection", Toast.LENGTH_SHORT)
.show()
}
) {
override fun getParams(): Map<String, String>? {
val params: MutableMap<String, String> = HashMap()
params["mobile"] = context.getSharedPreferences(Constant.prefs, Context.MODE_PRIVATE).getString("mobile","").toString();
params["length"] = "0";
return params
}
}
postRequest.retryPolicy =
DefaultRetryPolicy(
0,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
)
requestQueue.add(postRequest)
}
}
I tried various different ways given on internet but not able to figure out a way, new to kotlin so don't have much idea about Coroutine, any help is appreciated, Thanks in advance
These suspendCoroutine and CoroutineScope added by me so these might not be something that should be here
Able to figure out a way to solve the issue, here's answer if anyone needs this
class Mock #Inject constructor(private val context: Context) {
val url = Constant.prefix + "get_short_videos.php"
private var parentJob = Job()
private val coroutineContext: CoroutineContext get() = parentJob + Dispatchers.Main
private val scope = CoroutineScope(coroutineContext)
suspend fun loadMockData(): ArrayList<StoriesDataModel>? {
// val mockData = context.resources.openRawResource(R.raw.stories_data)
// val dataString = mockData.bufferedReader().readText()
var dataString = "";
// val scope = CoroutineScope(Dispatchers.Main).launch {
// dataString = getData()
// }
scope.async(Dispatchers.IO) {
val success = async { getData() }
dataString = success.await()
Log.e("Rresponse2",dataString+"-");
}.await();
Log.e("Rresponse",dataString+"-");
val gson = Gson()
val storiesType = object : TypeToken<ArrayList<StoriesDataModel>>() {}.type
val storiesDataModelList = gson.fromJson<ArrayList<StoriesDataModel>>(dataString, storiesType)
return storiesDataModelList
}
suspend fun getData() = suspendCoroutine<String> { cont ->
val requestQueue = Volley.newRequestQueue(context)
val postRequest: StringRequest = object : StringRequest(
Method.POST, url,
Response.Listener { response: String? ->
Log.e("response",response.toString());
cont.resume(response.toString())
},
Response.ErrorListener { error: VolleyError ->
error.printStackTrace()
Toast.makeText(context, "Check your internet connection", Toast.LENGTH_SHORT)
.show()
}
) {
override fun getParams(): Map<String, String>? {
val params: MutableMap<String, String> = HashMap()
params["mobile"] = context.getSharedPreferences(Constant.prefs, Context.MODE_PRIVATE).getString("mobile","").toString();
params["length"] = "0";
return params
}
}
postRequest.retryPolicy =
DefaultRetryPolicy(
0,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
)
requestQueue.add(postRequest)
}
}
Also requires to make function suspended from the main function called
I have a method which should return String value. The return value is correct and shows needed value string but in fragment I received Kotlin.Unit instead of that value.
Here what I see when debug:
here is my function:
fun getName() {
var name: String? = null
uploadPerson({ res ->
name = res.getJSONObject("person").getString("name")
},
{ err ->
Log.d("TAG", "error: $err")
})
val id = "5586"
val url =
"https://$id/api/person/get?&$name"
val resRequest = JsonObjectRequest(
Request.Method.GET, requestUrl, null,
{ response ->
},
{ error ->
}
)
queue.add(resRequest)
}
uploadPerson function:
fun uploadPerson(
result: (res: JSONObject) -> Unit,
error: ((err: String) -> Unit)? = null
) {
val params = HashMap<String, Any>()
params["id"] = person.id
params["name"] = person.name
val jsonObject = JSONObject(params as Map<*, *>)
val id = "5545"
val requestUrl = "https://id/api/person/UploadPerson";
val jsonObjectRequest =
object : JsonObjectRequest(Request.Method.POST, requestUrl, jsonObject,
{ response ->
try {
if (response.getBoolean("success")) {
val resultObj = response.getJSONObject("person")
} else {
}
} catch (e: JSONException) {
e.printStackTrace()
}
uploadResult(response);
},
{ error ->
// TODO: Handle error
uploadError?.invoke(error.toString());
}
) {
override fun getHeaders(): MutableMap<String, String> {
return getAuthHeaders()
}
}
queue.add(jsonObjectRequest);
}
I think that it is because of result uoloadPerson function is Unit and I need return String type in getName function. But I can't understand how to fix this problem
I am integrating a Login System for that I want the Response.Listener and Response.ErrorListener function to return a Boolean.
I searched on the google and found that it can be done using a callback interface ( This Question ). But I don't know how to do that in Kotlin
[ALSO UPDATED] This is my Kotlin file containing my function which are used by many activities:
package com.pratham.example
// My required imports
import ...
fun function1(){
...
}
fun function2(){
...
}
// This Auth function will return True if login success
fun auth(activity:Activity):Boolean{
val queue = Volley.newRequestQueue(activity)
val req = JsonObjectRequest(Request.Method.POST, url, jsonObj,
Response.Listener { response ->
val JSONObj = response.getString("Status")
if(JSONObj=="200"){
// return true
}
else{
// return false
}
}, Response.ErrorListener {
// return false
}
)
queue.add(req)
}
fun function4(){
...
}
This function will return true or false according to the Volley Response.
How can i return value from a Response.Listener and Response.ErrorListener in Kotlin
Edit:: I tried to use Interface like this
package com.pratham.sitapuriya
import ...
fun function1(){
...
}
fun function2(){
...
}
interface MyInterface {
fun onCallback(response: Boolean,context:Context)
}
class Login : MyInterface {
private val myInterface = this
override fun onCallback(response: Boolean,context:Context) {
Toast.makeText(context,"Working",Toast.LENGTH_SHORT).show()
}
fun auth(activity: Activity): Boolean {
val sp1 = activity.getSharedPreferences("Login", AppCompatActivity.MODE_PRIVATE)
if (sp1.contains("token") && sp1.contains("deviceId")) {
val token = sp1.getString("token", null)
val deviceId = sp1.getString("deviceId", null)
if (!token.isNullOrEmpty() && !deviceId.isNullOrEmpty()) {
// val url = "http://10.0.2.2:80/Projects/Sitapuriya/login.php"
val url = activity.getString(R.string.server) + "/tokenAuth.php"
val params = HashMap<String, String>()
params["token"] = token
params["deviceId"] = deviceId
val jsonObj = JSONObject(params)
val queue = Volley.newRequestQueue(activity)
val req = JsonObjectRequest(Request.Method.POST, url, jsonObj,
Response.Listener { response ->
val JSONObj = response.getString("Status")
if (JSONObj == "200") {
// return true
myInterface.onCallback(true,activity)
} else {
// return false
myInterface.onCallback(false,activity)
}
}, Response.ErrorListener {
// return false
myInterface.onCallback(false,activity)
}
)
queue.add(req)
} else {
return false
}
} else {
return false
}
return false
}
}
fun function4(){
...
}
But now i have no idea that how the callback will return value in auth() function and also how I'll be calling this auth() fucntion in my other activities .
Please help I have never used a callback before..
You can't, the code you have executes asynchronously so you can't have the return statement there.
But it doesn't mean you can not get the value. The easiest option is create a LiveData<Boolean> and observe it in your activity. When the value changes you will get notified.
The next thing you can do is you can create an interface.
interface MyCallback{
fun onValueChanged()
}
Then implement this interface in your activity and override the method. Then you can use it to get a callback when your asynchronous call finishes. See the below code.
interface MyInterface{
fun onCallback(response:Boolean)
}
class LoginActivity : AppCompatActivity(), AuthListener, MyInterface {
val myInterface = this
override fun onCallback(response: Boolean) {
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val queue = Volley.newRequestQueue(activity)
val req = JsonObjectRequest(Request.Method.POST, url, jsonObj,
Response.Listener { response ->
val JSONObj = response.getString("Status")
if(JSONObj=="200"){
//return true
myInterface.onCallback(true)
}
else{
myInterface.onCallback(false)
}
}, Response.ErrorListener {
// return false
}
)
queue.add(req)
}
}
Hope this helps. Thank You :)
I have to call an API asynchronously. To do it i'm using a coroutine, but i have to wait until the API is called to load the data. The problem is the next:
The await is not working as I want, it's not waiting until the API gives all the data.
Is the await what I need? Here is the code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_see)
launch { loaddata() }
/* some other code here*/
}
suspend fun loadData(){
val readData = async { read() }
readData.join()
readData.await()
val showScreen = async { refreshList() }
showScreen.join()
showScreen.await()
}
fun read(){
val stringRequest = object : StringRequest(Request.Method.POST, URL, Response.Listener<String>{ s ->
try {
val array = JSONArray(s)
for (i in 0..array.length() - 1) {
val objectAccount = array.getJSONObject(i)
val account = Account(
objectAccount.getString(value),
objectAccount.getString(value),
objectAccount.getString(value))
listAccount.add(account)
}
}catch (e: JSONException){
e.printStackTrace()
}
}, Response.ErrorListener { error: VolleyError? -> Log.e("error", "error") }){
override fun getParams(): Map<String, String> {
val params = HashMap<String, String>()
params.put("password", value)
params.put("idaccount", value)
return params
}
}
val requesQueue = Volley.newRequestQueue(this)
requesQueue.add<String>(stringRequest)
}
Usually you shouldn't call a async function
requesQueue.add<String>(stringRequest)
in the async coroutine builder
async {}
Sulution #1
you can change your read() method to a synchronous request.
Can I do a synchronous request with volley?
and run it with CommonPool
async(CommonPool) {
read()
}
Solution #2
wrap your async http call into a suspend function
I am NOT familiar with Volley, so maybe the code needs tweak
suspend fun read() {
return suspendCancellableCoroutine { continuation ->
val stringRequest = object : StringRequest(Request.Method.POST, URL, Response.Listener<String> { s ->
try {
val array = JSONArray(s)
for (i in 0..array.length() - 1) {
val objectAccount = array.getJSONObject(i)
val account = Account(
objectAccount.getString(value),
objectAccount.getString(value),
objectAccount.getString(value))
listAccount.add(account)
}
} catch (e: JSONException) {
e.printStackTrace()
// notice this
continuation.resumeWithException(e)
}
// notice this
continuation.resume()
}, Response.ErrorListener { error: VolleyError? ->
Log.e("error", "error")
// notice this
if (!continuation.isCancelled)
continuation.resumeWithException()
}) {
override fun getParams(): Map<String, String> {
val params = HashMap<String, String>()
params.put("password", value)
params.put("idaccount", value)
return params
}
}
val requesQueue = Volley.newRequestQueue(this)
requesQueue.add<String>(stringRequest)
continuation.invokeOnCompletion {
if (continuation.isCancelled)
try {
cancel()
} catch (ex: Throwable) {
//Ignore cancel exception
}
}
}
}
and call it like this
suspend fun loadData(){
read()
val showScreen = async { refreshList() }
showScreen.join()
showScreen.await()
}
**How to create interface get only Response and set Adapter **
I have lots of json create single method pass url get response handle Error network Check
public void getJsonRequest(String url){//interface
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET,url, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
list =parseJSONRequest(response);// create interface
adapter.setAllLinks(list); // create interface
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
errorJson.setVisibility(View.VISIBLE);
String map = VolleyErrorException.getErrror(error, getContext());
errorJson.setText(map);
}
});
requestQueue.add(jsonObjectRequest);
}
you can make an interface like this :
public interface resultInterface {
void Success(JSONObject response);
void Error(VolleyError error);
}
In the mainActivity , implement resultInterface . In the getJson() method, add another parameter like this:
public void getJsonRequest(String url, final resultInterface listener){
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET,url, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
listener.Success(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
listener.Error(error);
}
});}
From your mainActivity, when call the getJsonRequest as follows:
getJsonRequest(url,this);
This will enable callbacks to your main activity.You should receive the Success and Error callbacks now.
Hope this helps!
Here is an example done in Kotlin
You can also create one like this
interface IVolley {
fun onResponse(response: String)
}
Creating requests and adding it to queue, then just call the methods and handle in MainActivity
class MyVolleyRequest
private var mRequestQueue: RequestQueue?=null
private var context: Context?=null
private var iVolley: IVolley?=null
var imageLoader: ImageLoader?=null
private set
val requestQueue: RequestQueue
get(){
if(mRequestQueue == null)
mRequestQueue = Volley.newRequestQueue(context!!.applicationContext)
return mRequestQueue!!
}
private constructor(context: Context, iVolley: IVolley)
{
this.context = context
this.iVolley = iVolley
mRequestQueue = requestQueue
this.imageLoader = ImageLoader(mRequestQueue,object: ImageLoader.ImageCache{
private val mCache = LruCache<String, Bitmap>(10)
override fun getBitmap(url: String?): Bitmap? {
return mCache.get(url!!)
}
override fun putBitmap(url: String?, bitmap: Bitmap?) {
mCache.put(url!!,bitmap!!)
}
})
}
internal constructor(context: Context)
{
this.context = context
mRequestQueue = requestQueue
this.imageLoader = ImageLoader(mRequestQueue,object: ImageLoader.ImageCache{
private val mCache = LruCache<String, Bitmap>(10)
override fun getBitmap(url: String?): Bitmap? {
return mCache.get(url!!)
}
override fun putBitmap(url: String?, bitmap: Bitmap?) {
mCache.put(url!!,bitmap!!)
}
})
}
fun <T> addToRequestQueue(req: Request<T>){
requestQueue.add(req)
}
// GET METHOD
fun getRequest(url:String)
{
val getRequest = JsonObjectRequest(Request.Method.GET,url, null, Response.Listener { response ->
iVolley!!.onResponse(response.toString())
},Response.ErrorListener { error ->
iVolley!!.onResponse(error.message!!)
})
addToRequestQueue(getRequest)
}
// POST method with params
fun postRequest(url:String)
{
val postRequest = object:StringRequest(Request.Method.POST,url,
Response.Listener { response ->
iVolley!!.onResponse(response.toString ())
},Response.ErrorListener {error -> iVolley!!.onResponse((error.message!!)) })
{
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
params["name"] = "Assad Ginem"
params["value"] = "This value is Put from Android App"
return params
}
}
addToRequestQueue(postRequest)
}
// PUT method with params
fun putRequest(url:String)
{
val postRequest = object:StringRequest(Request.Method.PUT,url,
Response.Listener { response ->
iVolley!!.onResponse(response.toString ())
},Response.ErrorListener {error -> iVolley!!.onResponse((error.message!!)) })
{
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
params["name"] = "Assad Ginem"
params["value"] = "This is value posted from Android App"
return params
}
}
addToRequestQueue(postRequest)
}
// PATCH method with params
fun patchRequest(url:String)
{
val postRequest = object:StringRequest(Request.Method.PATCH,url,
Response.Listener { response ->
iVolley!!.onResponse(response.toString ())
},Response.ErrorListener {error -> iVolley!!.onResponse((error.message!!))})
{
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
params["name"] = "Assad Ginem"
params["value"] = "This is value patch from Android App"
return params
}
}
addToRequestQueue(postRequest)
}
// DELETE method with params
fun deleteRequest(url:String)
{
val deleteRequest = StringRequest(Request.Method.DELETE, url, Response.Listener { response ->
iVolley!!.onResponse(response)
},Response.ErrorListener { error -> iVolley!!.onResponse(error.message!!)
})
addToRequestQueue(deleteRequest)
}
companion object{
private var mInstance: MyVolleyRequest? = null
#Synchronized
fun getInstance(context: Context, iVolley: IVolley): MyVolleyRequest{
if(mInstance == null)
{
mInstance = MyVolleyRequest(context,iVolley)
}
return mInstance!!
}
}
MainActivity.kt
class MainActivity : AppCompatActivity(), IVolley {
override fun onResponse(response: String) {
//Show
Toast.makeText(this#MainActivity,""+response,Toast.LENGTH_SHORT).show()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_get.setOnClickListener {
MyVolleyRequest.getInstance(this#MainActivity, this#MainActivity)
.getRequest("https://jsonplaceholder.typicode.com/todos/1")
}
btn_post.setOnClickListener {
MyVolleyRequest.getInstance(this#MainActivity, this#MainActivity)
.postRequest("https://jsonplaceholder.typicode.com/posts")
}
btn_put.setOnClickListener {
MyVolleyRequest.getInstance(this#MainActivity, this#MainActivity)
.putRequest("https://jsonplaceholder.typicode.com/posts/1")
}
btn_patch.setOnClickListener {
MyVolleyRequest.getInstance(this#MainActivity, this#MainActivity)
.patchRequest("https://jsonplaceholder.typicode.com/posts/1")
}
btn_delete.setOnClickListener {
MyVolleyRequest.getInstance(this#MainActivity, this#MainActivity)
.deleteRequest("https://jsonplaceholder.typicode.com/posts/1")
}
btn_image_loader.setOnClickListener {
image_view.setImageUrl("http://www.inspiredluv.com/wp-content/uploads/2016/10/24-cool-wallpapers.jpg"
,MyVolleyRequest(this#MainActivity).imageLoader)
}
}
}