How to add Body in Url in Volley request in Kotlin? - json

Here is my Code that for Volley Request:-
val searchRequest = object : JsonArrayRequest(Request.Method.GET,url,
Response.Listener { response ->
val result = response.toString()
},
Response.ErrorListener { error ->
Toast.makeText(activity, "Error!",Toast.LENGTH_LONG)
.show()
Log.d("ERROR",error.toString())
})
{
override fun getBody(): ByteArray {
// TODO add Body, Header section works //////////
return super.getBody()
}
override fun getBodyContentType(): String {
return "application/json"
}
override fun getHeaders() : Map<String,String> {
val params: MutableMap<String, String> = HashMap()
params["Search-String"] = songName
params["Authorization"] = "Bearer ${accessTx.text}"
return params
}
}
AppController.instance!!.addToRequestQueue(searchRequest)
I want to add this information in the body section
video_id = "BDJIAH" ,
audio_quality = "256"
here is the sample to add above information in the below segment.
{
"video_id":"ABCDE",
"audio_quality":"256"
}
Basically, I am facing problem in ByteArray section. That doesn't work for me.

This function i created to send a call to server and this is how you will add body in your call.
fun sendcall() {
//RequestQueue initialized
mRequestQueue = Volley.newRequestQueue(this)
//String Request initialized
mStringRequest = object : StringRequest(Request.Method.POST, url, Response.Listener { response ->
Toast.makeText(applicationContext, "Logged In Successfully", Toast.LENGTH_SHORT).show()
}, Response.ErrorListener { error ->
Log.i("This is the error", "Error :" + error.toString())
Toast.makeText(applicationContext, "Please make sure you enter correct password and username", Toast.LENGTH_SHORT).show()
}) {
override fun getBodyContentType(): String {
return "application/json"
}
#Throws(AuthFailureError::class)
override fun getBody(): ByteArray {
val params2 = HashMap<String, String>()
params2.put("Login","your credentials" )
params2.put("Password", "your credentials")
return JSONObject(params2).toString().toByteArray()
}
}
mRequestQueue!!.add(mStringRequest!!)
}

Volley post request in kotlin with params
private fun loginUser() {
val username: String = etName.getText().toString().trim()
val password: String = etPass.getText().toString().trim()
val stringRequest: StringRequest = object : StringRequest( Method.POST, LOGINURL,
Response.Listener { response ->
Toast.makeText(this, response, Toast.LENGTH_LONG).show()
try {
val jsonObject = JSONObject(response)
//Parse your api responce here
/*val intent = Intent(this, MainActivity::class.java)
startActivity(intent)*/
} catch (e: JSONException) {
e.printStackTrace()
}
},
Response.ErrorListener { error ->
Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show()
}) {
override fun getParams(): Map<String, String> {
val params: MutableMap<String, String> = HashMap()
//Change with your post params
params["username"] = username
params["password"] = password
return params
}
}
val requestQueue = Volley.newRequestQueue(this)
requestQueue.add(stringRequest)
}

Related

I tried to parse a JSON file on my app but even if there is no error, my app doesn't run on the emulator

The problem might be that the app can't reach the json file I tried to parse it to.No error pops up in the run or build but it stops at"11/23 23:14:38: Launching 'app' on Device 4.Install successfully finished in 325 ms."Below is my code:
MainActivity
class MainActivity : AppCompatActivity() {
#SuppressLint("SuspiciousIndentation", "NotifyDataSetChanged")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val usersList: ArrayList<UserModelClass> = ArrayList()
try {
val obj = JSONObject(getJSONFromAssets()!!)
val usersArray = obj.getJSONArray("owner")
for (i in 0 until usersArray.length()) {
val user = usersArray.getJSONObject(i)
val login = user.getInt("id")
val name = user.getString("name")
val url = user.getString("url")
val followers_url = user.getString("followers")
val starred_url = user.getString("stars")
val userDetails =
UserModelClass(login, name, url, followers_url , starred_url)
// add the details in the list
usersList.add(userDetails)
}
} catch (e: JSONException) {
//exception
e.printStackTrace()
}
val recyclerView = findViewById<RecyclerView>(R.id.rvUsersList)
val adapter = UserAdapter(this, usersList)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
recyclerView.adapter = adapter
adapter.notifyDataSetChanged()
}
private fun getJSONFromAssets(): String? {
var json: String? = null
val charset: Charset = Charsets.UTF_8
try {
val myUsersJSONFile = assets.open("JSON.json")
val size = myUsersJSONFile.available()
val buffer = ByteArray(size)
myUsersJSONFile.read(buffer)
myUsersJSONFile.close()
json = String(buffer, charset)
} catch (ex: IOException) {
ex.printStackTrace()
return null
}
return json
}
}
UserAdapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
class UserAdapter( val context: Context, val items: ArrayList<UserModelClass>) :
RecyclerView.Adapter<UserViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
return UserViewHolder(
LayoutInflater.from(context).inflate(
R.layout.item_user,
parent,
false
)
)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount(): Int {
return items.size
}
}
UserViewHolder
class UserViewHolder(view: View) : RecyclerView.ViewHolder(view) {
// Holds the TextView that will add each item to
var tvId : TextView
var tvName : TextView
var tvURL : TextView
var tvFollowers : TextView
var tvStars : TextView
init {
tvId = view.findViewById(R.id.tvId)
tvName = view.findViewById(R.id.tvName)
tvURL = view.findViewById(R.id.tvURL)
tvFollowers = view.findViewById(R.id.tvFollowers)
tvStars = view.findViewById(R.id.tvStars)
}
fun bind(item: UserModelClass) {
tvId.text = item.login.toString()
tvName.text = item.node_id
tvURL.text = item.avatar_url
tvFollowers.text = item.followers_url.toString()
tvStars.text = item.starred_url.toString()
}
}
UserModelClass
class UserModelClass(
val login: Int,
val node_id: String,
val avatar_url: String,
val followers_url: String,
val starred_url: String
)
Json.json
I don't need all the information from the json, I selected some of them
{
"total_count": 357602,
"incomplete_results": false,
"items": [
{
"id": 23096959,
"node_id": "...",
"name": "...",
"full_name": "...",
"private": false,
"owner": {
"login": "...",
"id": 4314092,
"node_id": "...",
"avatar_url": "https://...",
"url": "https://api.github.com/users/golang",
"followers_url": "https://api.github.com/users/golang/followers",
"following_url": "https://api.github.com/users/golang/following{/other_user}",
"starred_url": "https://api.github.com/users/golang/starred{/owner}{/repo}",
},
Actually it seems you are parsing it wrong. In your json, items is the array and owner is an object inside items array item.
You cannot access owner directly. Also you should give exact keys.
Like "followers_url" not just "followers"
Try the below code.
try {
val obj = JSONObject(getJSONFromAssets()!!)
val itemsArray = obj.getJSONArray("items")
for (i in 0 until itemsArray.length()) {
val user = itemsArray.getJSONObject(i)
val name = user.getString("name") // Getting name from item object
val owner = user.getJSONObject("owner") //Getting owner object from item object
//And below you need to get items from owner object not the user object.
val login = owner.getInt("id")
val url = owner.getString("url")
val followers_url = owner.getString("followers_url")
val starred_url = owner.getString("starred_url")
val userDetails =
UserModelClass(login, name, url, followers_url , starred_url)
// add the details in the list
usersList.add(userDetails)
}
} catch (e: JSONException) {
//exception
e.printStackTrace()
}

Post Request in Kotlin

I'm trying to do a post request in Android Studio written in Kotlin
I'm posting a JSON object to our server and then the server is returning a JSON object back. But what I'm doing here is decoding the response body as a string and then converting it into the data structure we need. I'm sure there is a better and simpler way to do what I need done.
My current code works but the major issue I'm having is formatting the string if our objects have nested objects which is why I want to figure out a better way to turn the response body into a json object.
I'm not too familiar with many request libraries for kotlin but I have looked into okhttp3 but I'm not sure how to post a json object, attach headers and decode the response body into a json object.
I know for okhttp3 I need to convert the json object to a string to post other than that I'm lost.
Breakdown of what's needed:
Post JSON Object To Server
Send Headers With Post Request
Decode Response Body into JSON Object/ Kotlin Equivalent
Simplify What I'm Trying to Do if Possible
This is the current code I have
private fun postRequestToGetDashboardData() {
val r = JSONObject()
r.put("uid", muid)
r.put("token", mtoken)
SendJsonDataToServer().execute(r.toString());
}
inner class SendJsonDataToServer :
AsyncTask<String?, String?, String?>() {
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
if (result.equals(null)) {
val t = Toast.makeText(this#Home, "No devices to display", Toast.LENGTH_LONG)
t.setGravity(Gravity.CENTER, 0, 0)
t.show()
} else {
intentForUnique.putExtra("FirstEndpointData", result)
var list = handleJson(result)
adapter.submitList(list)
dashboardItem_list.adapter = adapter
adapter.notifyDataSetChanged();
dashboardItem_list.smoothScrollToPosition(0);
}
}
override fun doInBackground(vararg params: String?): String? {
val JsonDATA = params[0]!!
var urlConnection: HttpURLConnection? = null
var reader: BufferedReader? = null
try {
val url = URL("URL");
urlConnection = url.openConnection() as HttpURLConnection;
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Authorization", mtoken);
urlConnection.setRequestProperty("Accept", "application/json");
val writer: Writer =
BufferedWriter(OutputStreamWriter(urlConnection.getOutputStream(), "UTF-8"));
writer.write(JsonDATA);
writer.close();
val inputStream: InputStream = urlConnection.getInputStream();
if (inputStream == null) {
return null;
}
reader = BufferedReader(InputStreamReader(inputStream))
var inputLine: String? = reader.readLine()
if (inputLine.equals("null")) {
return null
} else {
return inputLine
}
} catch (ex: Exception) {
Log.e(TAG, "Connection Failed", ex);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (ex: Exception) {
Log.e(TAG, "Error closing stream", ex);
}
}
}
return null
}
}
private fun handleJson(jsonString: String?): ArrayList<SensorData> {
val jsonArray = JSONArray(jsonString)
val list = ArrayList<SensorData>()
var x = 0
while (x < jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(x)
list.add(
SensorData(
jsonObject.getInt("deviceId"),
// jsonObject.getString("deviceName"),
jsonObject.getInt("battery"),
jsonObject.getString("dateTime"),
jsonObject.getInt("airValue"),
jsonObject.getInt("waterValue"),
jsonObject.getInt("soilMoistureValue"),
jsonObject.getInt("soilMoisturePercent")
)
)
x++
}
return list
}
So the json data being returned back is an array of this structure (our backend is written in Go)
type Device struct {
DeviceID int `bson:"deviceId" json:"deviceId"`
Battery int `bson:"battery" json:"battery"`
DateTime time.Time `bson:"dateTime" json:"dateTime"`
AirValue int `bson:"airValue" json:"airValue"`
WaterValue int `bson:"waterValue" json:"waterValue"`
SoilMoistureValue int `bson:"soilMoistureValue" json:"soilMoistureValue"`
SoilMoisturePercent int `bson:"soilMoisturePercent" json:"soilMoisturePercent"`
}

How to add Body request in url in Kotlin?

Here is my Code that for Volley Request:-
val searchRequest = object : JsonArrayRequest(Request.Method.GET,url,
Response.Listener { response ->
val result = response.toString()
},
Response.ErrorListener { error ->
Toast.makeText(activity, "Error!",Toast.LENGTH_LONG)
.show()
Log.d("ERROR",error.toString())
})
{
override fun getBody(): ByteArray {
// TODO add Body, Header section works //////////
return super.getBody()
}
override fun getBodyContentType(): String {
return "application/json"
}
override fun getHeaders() : Map<String,String> {
val params: MutableMap<String, String> = HashMap()
params["Search-String"] = songName
params["Authorization"] = "Bearer ${accessTx.text}"
return params
}
}
AppController.instance!!.addToRequestQueue(searchRequest)
I want to add this information in the body section
video_id = "BDJIAH" , audio_quality = "256"
here is the sample to add above information in the below segment.
{ "video_id":"ABCDE", "audio_quality":"256" }
Basically, I am facing problem in ByteArray section. That doesn't work for me.
You can use toByteArray() method of String class in Kotlin.
For example:
val charset = Charsets.UTF_8
val byteArray = "SomeValue".toByteArray(charset)
Also try to pass multiple values in the request body in this way:
val requestBody = "video_id = "+"ABCDE"+ "& audio_quality ="+ "256"
val charset = Charsets.UTF_8
val byteArray = requestBody.toByteArray(charset)

Swift 3 - Declaring a simulated JSON as a response from a server

I'm making an application with swift 3.0. But I have a problem, because in the API REST still have not implemented the service, I'm creating a simulated JSON to continue working. But the problem as you will see at the end of all the explanation in the image is that I do not know how to declare a JSON "-.- .... Basically the program will make a call to the server and it will respond with a JSON (now I pass it "the simulated" you will see it in the code). And with that JSON maps it with ObjectMapper to some models (that I pass the code) so that in the end the application has an object.
Error declaring Simulated JSON
These are the three models I have to map the JSON when it will come from the server or in this case, the simulated JSON.
The first is "LegendEntriesModel":
import Foundation
import ObjectMapper
import AlamofireDomain
class LegendEntriesModel: Mappable {
fileprivate var _id_snapshot: String?
fileprivate var _date: String?
fileprivate var _deliverables: [DeliverablesModel]?
init(){}
required init?(map: Map) { }
func mapping(map: Map) {
self.id_snapshot <- map["id_snapshot"]
self.date <- map["date"]
self.deliverables <- map["deliverables"]
}
var id_snapshot: String {
get {
if _id_snapshot == "" {
_id_snapshot = ""
}
return _id_snapshot!
}
set {
_id_snapshot = newValue
}
}
var date: String {
get {
if _date == "" {
_date = ""
}
return _date!
}
set {
_date = newValue
}
}
var deliverables: [DeliverablesModel] {
get {
if _deliverables == nil {
_deliverables = []
}
return _deliverables!
}
set {
_deliverables = newValue
}
}
//MARK: RELEASE MEMORY BETWEEN OBJECT AND API REST (BROKE DEPENDENCIS)
func copy()->LegendEntriesModel {
let legendEntriesModel = LegendEntriesModel()
legendEntriesModel.id_snapshot = self.id_snapshot
legendEntriesModel.date = self.date
legendEntriesModel.deliverables = copyDeliverables()
return legendEntriesModel
}
func copyDeliverables() -> [DeliverablesModel]{
var newArray: [DeliverablesModel] = []
for item in deliverables {
newArray.append(item.copy())
}
return newArray
}
}
The second on is "DeliverablesModel"
import Foundation
import ObjectMapper
import AlamofireDomain
class DeliverablesModel: Mappable {
fileprivate var _id: String?
fileprivate var _type: String?
fileprivate var _url_layer: String?
fileprivate var _options: OptionsDeliverablesModel?
init(){}
required init?(map: Map) { }
func mapping(map: Map) {
self.id <- map["id"]
self.type <- map["type"]
self.url_layer <- map["url_layer"]
self.options <- map["options"]
}
var id: String {
get {
if _id == "" {
_id = ""
}
return _id!
}
set {
_id = newValue
}
}
var type: String {
get {
if _type == "" {
_type = ""
}
return _type!
}
set {
_type = newValue
}
}
var url_layer: String {
get {
if _url_layer == "" {
_url_layer = ""
}
return _url_layer!
}
set {
_url_layer = newValue
}
}
var options: OptionsDeliverablesModel {
get {
if _options == nil {
_options = OptionsDeliverablesModel()
}
return _options!
}
set {
_options = newValue
}
}
//MARK: RELEASE MEMORY BETWEEN OBJECT AND API REST (BROKE DEPENDENCIS)
func copy()->DeliverablesModel {
let deliverablesModel = DeliverablesModel()
deliverablesModel.id = self.id
deliverablesModel.type = self.type
deliverablesModel.url_layer = self.url_layer
deliverablesModel.options = self.options
return deliverablesModel
}
}
And the last one is "OptionsDeliverablesModel":
import Foundation
import ObjectMapper
import AlamofireDomain
class OptionsDeliverablesModel: Mappable {
fileprivate var _type: String?
fileprivate var _max_range: Float?
fileprivate var _min_range: Float?
fileprivate var _title: String?
fileprivate var _initial_max_value: Float?
fileprivate var _initial_min_value: Float?
fileprivate var _id: String?
init(){}
required init?(map: Map) { }
func mapping(map: Map) {
self.type <- map["type"]
self.max_range <- map["max_range"]
self.min_range <- map["min_range"]
self.title <- map["title"]
self.initial_max_value <- map["initial_max_value"]
self.initial_min_value <- map["initial_min_value"]
self.id <- map["id"]
}
var type: String {
get {
if _type == "" {
_type = ""
}
return _type!
}
set {
_type = newValue
}
}
var max_range: Float {
get {
if _max_range == 0 {
_max_range = 0
}
return _max_range!
}
set {
_max_range = newValue
}
}
var min_range: Float {
get {
if _min_range == 0 {
_min_range = 0
}
return _min_range!
}
set {
_min_range = newValue
}
}
var title: String {
get {
if _title == "" {
_title = ""
}
return _title!
}
set {
_title = newValue
}
}
var initial_max_value: Float {
get {
if _initial_max_value == 0 {
_initial_max_value = 0
}
return _initial_max_value!
}
set {
_initial_max_value = newValue
}
}
var initial_min_value: Float {
get {
if _initial_min_value == 0 {
_initial_min_value = 0
}
return _initial_min_value!
}
set {
_initial_min_value = newValue
}
}
var id: String {
get {
if _id == "" {
_id = ""
}
return _id!
}
set {
_id = newValue
}
}
//MARK: RELEASE MEMORY BETWEEN OBJECT AND API REST (BROKE DEPENDENCIS)
func copy()->OptionsDeliverablesModel {
let optionsDeliverablesModel = OptionsDeliverablesModel()
optionsDeliverablesModel.type = self.type
optionsDeliverablesModel.max_range = self.max_range
optionsDeliverablesModel.min_range = self.min_range
optionsDeliverablesModel.title = self.title
optionsDeliverablesModel.initial_max_value = self.initial_max_value
optionsDeliverablesModel.initial_min_value = self.initial_min_value
optionsDeliverablesModel.id = self.id
return optionsDeliverablesModel
}
}
With these three "Models" are what I can map the JSON inside the class DAO, but here is the problem, because I do not know how to pass my JSON that I have simulated.
The code is as follows:
import AlamofireDomain
import Alamofire
import ObjectMapper
class DeliverablesLegendDAO : SimpleDAO {
var deliverables = Dictionary<String, Any>()
deliverables = [{"legendEntries": [{"id_snapshot": "123","date": "2016-10-20","deliveries": [{"id": "12","type": "RGB","url_layer":"topp:states","options": [{"type": "range","max_range": 100,"min_range": 0,"title": "Option RGB","initial_max_value": 100,"initial_min_value": 0,"id": "depth"}]}]}]}]
func snapshots(_ parameters: String,
callbackFuncionOK: #escaping (LegendEntriesModel)->(),
callbackFunctionERROR: #escaping (Int,NSError)->()) {
Alamofire.request(parameters,
method: .post,
encoding: JSONEncoding.default)
.responseJSON { response in
if response.result.isSuccess{
if let status = response.response?.statusCode {
switch(status){
case 200:
let value = response
let legendEntries = Mapper<LegendEntriesModel>().map(JSONObject: value)
callbackFuncionOK(legendEntries!)
default:
break
}
}
}
else {
var statusCode = -1
if let _response = response.response {
statusCode = _response.statusCode
}
var nsError: NSError = NSError(domain: Constants.UNKNOWN_HTTP_ERROR_MSG,
code: Constants.UNKNOWN_HTTP_ERROR_ID,
userInfo: nil)
if let _error = response.result.error {
nsError = _error as NSError
}
callbackFunctionERROR(statusCode,nsError)
}
}
}
}
As you can see in the image, I am declaring my simulated JSON wrong and then map it with "LegendDeliveriesModel" to an object. How can I do it?
Error declaring simulated JSON
If you need anything else, tell me. I repeat, the problem is in the JSON simulated statement that I do not know how to pass it to DAO and that it maps it.
Hi not sure if you will be open to this, but it will be better to try creating a JSON in file and load it in using Bundle like this :
func loadJsonFrom(fileName: String) -> NSDictionary {
let path = Bundle.main.path(forResource: filename, ofType: "json")
let jsonData = try! Data(contentsOf: URL(fileURLWithPath: path!))
let jsonResult: NSDictionary = try! JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as! NSDictionary
return jsonResult
}
I think your syntax is wrong for declaring your JSON. Pretty sure declaring Dictionaries inline in swift you only use ["key":"value"]
So just remove all of the { and }
Edit: Sorry, didn't realise it was outside of a method. If you want to do that you have to declare it directly like so
var deliverables = ["legendEntries": ["id_snapshot": "123","date": "2016-10-20","deliveries": ["id": "12","type": "RGB","url_layer":"topp:states","options": ["type": "range","max_range": 100,"min_range": 0,"title": "Option RGB","initial_max_value": 100,"initial_min_value": 0,"id": "depth"]]]]
If you're just using it as mock Data I would also consider making it a let constant rather than a variable

Swift use ObjectMapper with singleton

I want use ObjectMapper to parsing Json string within a singleton situation. Example code :
class User: Mappable {
var username: String?
var signature: String?
//Singleton
static let shared = User()
private init() {}
//Mappable functions
required init?(map: Map) {}
func mapping(map: Map) {
username <- map["username"]
signature <- map["signature"]
}
//Update userInfo after network request
func getUserInfo() {
//Network things
...
//Example data
let data = [
"username": "Eason",
"signature": "I love U"
]
//Some thing like this to update userInfo
Mapper<User>().map(data)
}
}
So, what is the right way to use ObjectMapper in singleton situation?
I prefer the following option.
1) UserManager (singleton):
class UserManager: NSObject {
static let shared = UserManager()
var profile: UserProfile?
private override init() {}
func loadUserProfile(completion: #escaping () -> ()) {
RestClient.shared.getUserProfile() { [weak self] (profile, error) in
guard let `self` = self else { return }
self.profile = profile as? UserProfile
completion()
}
}
}
2) User model:
class UserProfile: Mappable {
var username: String?
var signature: String?
required init?() {}
required init?(map: Map) {}
func mapping(map: Map) {
username <- map ["username"]
signature <- map ["signature"]
}
}
3) RestClient
typealias IdResponseBlock = (_ swiftObj: Any?, _ error: Error?) -> Void
class RestClient: NSObject {
static let shared = RestClient()
// Additional class where sending and receiving information from the server occurs
private var http = HttpService()
let baseUrl = ApiSettings.shared.kServerBaseURL
override init() {
super.init()
}
func parseData<P: BaseMappable>(object: Any, modelCls: P.Type, response: (IdResponseBlock)) {
if object is NSArray {
let result = Mapper<P>().mapArray(JSONObject: object)
return response(result, nil)
}
if object is NSDictionary {
let model: P = Mapper<P>().map(JSONObject: object)!
return response(model, nil)
}
}
//MARK: - API
//MARK: - User
func getUserProfile(resp: #escaping IdResponseBlock) {
let url = baseUrl + Requests.profile
http.queryBy(url, method: .get, queue: .background, resp: { (response, error) in
if let err = error {
return resp(nil, err)
}
guard let data = response else {
return resp(nil, error)
}
let jsonData = JSON(data)["data"]
self.parseData(object: jsonData.rawValue,
modelCls: UserProfile.self,
response: resp)
})
}
}