How to send POST with json using Retrofit? - android

I'm Struggling how to send POST with json using Retrofit2.
like this:
{
"user_available_id": 702,
"teacher_id" : 3207,
"schedule" : [{
"event_id" : 47533,
"schedule_time" : "2020-11-30 07:00:00",
"status" :1
},
{
"event_id" : 47532,
"schedule_time" : "2020-11-30 06:30:00",
"status" :1
}]
}
I'm suppose send post like that. And I wonder is it possible to send like that or there is another way. can you kindly tell me if there is another way. btw here's how I try to send it
CreateSchduleAPI.kt
#POST("schedule/student-create")
#Headers("Accept: application/json")
#SerializedName("data")
suspend fun createScheduleSesi2(
#Header("Authorization") token: String?,
#Body createSchedule: String
): Response<ScheduleModel>
And the Model
ScheduleModel.kt
#Parcelize
data class ScheduleModel(
#field:SerializedName("user_available_id")
var userAvailableId: String? = null,
#field:SerializedName("schedule")
var schedule: ArrayList<schedule?>? = null,
#field:SerializedName("teacher_id")
var teacherId: String? = null
) : Parcelable
#Parcelize
data class schedule(
#field:SerializedName("event_id")
var eventId: String? = null,
#field:SerializedName("schedule_time")
var scheduleTime: String? = null,
#field:SerializedName("status")
var status: String? = null
) : Parcelable
First
private suspend fun getMultiSlotJadwal(id: String, date: String) {
jamList.clear()
val networkConfig =
NetworkConfig().getTeacher().getTeacherScheduleAvailability(token, id, date)
if (networkConfig.isSuccessful) {
if (networkConfig.body()!!.availability!!.isEmpty()) {
binding.rvSlot.visibility = View.GONE
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Jam tidak tersedia",
Toast.LENGTH_SHORT
).show()
}
} else {
for (slot in networkConfig.body()!!.availability!!) {
//convert tanggal start ke millis
val tanggalSlot = slot!!.start!!.toDate().formatTo("yyyy-MM-dd HH:mm")
val tanggalInMillis = convertToMillis(tanggalSlot)
//ambil tanggal sekarang
val myFormat = "yyyy-MM-dd HH:mm" // format tanggal
val calendar = Calendar.getInstance()
val time = calendar.time
val sdf = SimpleDateFormat(myFormat, Locale.getDefault())
val curdate = sdf.format(time) //diconvert ke tanggal local
val curDateinMillis = convertToMillis(curdate) // convert ke millis
val hasilDate = tanggalInMillis - curDateinMillis
val tanggalJam = hasilDate / 3600000 //diubah dari millis ke jam
if (tanggalJam >= 6) {
jamList.add(slot)
val sortJamList = jamList.sortedBy { jamList -> jamList.start }
binding.rvSlot.visibility = View.VISIBLE
binding.rvSlot.adapter = SlotJamAdapter(sortJamList) {
teacher_id = it.teacherId.toString()
scheduleModel.teacherId = teacher_id
scheduleModel.userAvailableId = user_avalaible_id
scheduleItem.scheduleTime = it.start.toString()
scheduleItem.status = "1"
scheduleItem.eventId = it.id.toString()
scheduleList.add(scheduleItem)
scheduleModel.schedule = scheduleList
itemClicked = true
changeBackgroundButtonSesi2()
}
}
}
}
} else {
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Jam tidak tersedia",
Toast.LENGTH_SHORT
).show()
}
}
}
Second
private suspend fun createSchedule2Sesi() {
val jsonSchedule = Gson().toJson(scheduleModel)
val networkConfig = NetworkConfig().createSchedule().createScheduleSesi2(
token,
jsonSchedule
)
try {
if (networkConfig.isSuccessful) {
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Pembuatan Jadwal Berhasil",
Toast.LENGTH_LONG
).show()
startActivity(Intent(this, MainActivity::class.java))
finish()
}
} else {
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Pembuatan Jadwal Gagal, Cek Koneksi",
Toast.LENGTH_LONG
).show()
}
}
}catch (e:Exception){
Log.e(TAG, "createSchedule2Sesi: ${e.message}", )
}
}
Thank you in advance

Retrofit allows you to use your Kotlin object as a parameter of a call. It will take care of the json serialisation itself if you use GsonConverterFactory when building your Retrofit instance.
That will allow you to change the definition of your endpoint as below
#POST("schedule/student-create")
suspend fun createScheduleSesi2(
#Header("Authorization") token: String?,
#Body createSchedule: ScheduleModel
): Response<ScheduleModel>

Related

How to get my retrofit2 model to parse this?

This is unusuall response where the name of object is the same as the object's ID and at this point I don't really know how to parse this response
"addresses": {
"163492": {
"address_id": "163492",
//more of String variables
},
"166127": {
"address_id": "166127",
//more of String variables
},
"166202": {
"address_id": "166202",
//more of String variables
}
}
this is how my Event model looks like, I'm using room database to save this response later
#Entity
data class Event(
#PrimaryKey(autoGenerate = false)
#SerializedName("id") val id: Int,
#SerializedName("title") val title: String,
#SerializedName("description") val desc: String,
#SerializedName("note") val note: String? = null,
#SerializedName("date") val dateTs: Long,
#SerializedName("begintime") val beginTime: String,
#SerializedName("enddate") val endDate: String,
#SerializedName("endtime") val endTime: String,
#SerializedName("customerid") val customerId: String? = null,
#SerializedName("address_id") val addressId: String? = null,
#SerializedName("pin") val pin: String? = null,
#SerializedName("location") val location: String? = null,
#SerializedName("customerlocation") val customerLocation: String? = null,
#field:TypeConverters(beskidmedia.pl.scanner.room.TypeConverters::class)
#SerializedName("nodes") val nodes: List<Node>? = null,
#SerializedName("closed") val closed: Int,
#SerializedName("type") val type: Int,
#SerializedName("ticketid") val ticketId: String? = null,
#SerializedName("customername") val customerName: String? = null,
#field:TypeConverters(beskidmedia.pl.scanner.room.TypeConverters::class)
#SerializedName("contacts") val contacts: List<Contacts>? = null,
#field:TypeConverters(beskidmedia.pl.scanner.room.TypeConverters::class)
#SerializedName("addresses") val addresses: List<Address>? = null,
#Embedded
#SerializedName("assignments") val assignments: Assignments? = null,
#SerializedName("lastUpdate") val lastUpdate: Long = System.currentTimeMillis()
)
everything beside the addresses part is fine cos I tested it using response with null for addresses, I tried to do deserializer for this but it appears like it don't recognise it, this is how it looks like
class EventDeserializer : JsonDeserializer<Event> {
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): Event {
json?.asJsonObject!!.let { event ->
val nodes = mutableListOf<Node>()
val contacts = mutableListOf<Contacts>()
val addresses = mutableListOf<Address>()
val net = mutableListOf<Assignment>()
val tv = mutableListOf<Assignment>()
val assignments = Assignments(net, tv)
val netTemp = event.get("assignments").asJsonObject.get("assignments_net").asJsonArray
val tvTemp = event.get("assignments").asJsonObject.get("assignments_tv").asJsonArray
netTemp.forEach { assignment ->
assignment.asJsonObject.let {
net.add(
Assignment(
name = it.get("name").asString,
id = it.get("id").asInt
)
)
}
}
tvTemp.forEach { assignment ->
assignment.asJsonObject.let {
tv.add(
Assignment(
name = it.get("name").asString,
id = it.get("id").asInt
)
)
}
}
val nodesTemp = event.get("nodes").asJsonArray
nodesTemp.forEach { node ->
node.asJsonObject.let {
nodes.add(
Node(
id = it.get("id").asInt,
name = it.get("name").asString,
mac = it.get("mac").asString,
ip = it.get("ip").asString,
location = it.get("location").asString,
netName = it.get("netname").asString
)
)
}
}
val contactsTemp = event.get("contacts").asJsonArray
contactsTemp.forEach { contact ->
contact.asJsonObject.let {
contacts.add(
Contacts(
phone = it.get("phone").asString,
contact = it.get("contact").asString,
name = it.get("name").asString,
type = it.get("type").asString,
typeStr = it.get("typestr").asString
)
)
}
}
val addressesTemp = event.get("addresses").asJsonObject
addressesTemp?.keySet()?.let { names ->
names.forEach { name ->
addressesTemp.get(name).asJsonObject.let {
addresses.add(
Address(
id = it.get("address_id").asString,
name = it.get("location").asString
)
)
}
}
}
return Event(
id = event.get("id").asInt,
title = event.get("title").asString,
desc = event.get("description").asString,
note = event.get("note")?.asString,
dateTs = event.get("date").asLong,
beginTime = event.get("begintime").asString,
endDate = event.get("enddate").asString,
endTime = event.get("endtime").asString,
customerId = event.get("customerid")?.asString,
addressId = event.get("address_id")?.asString,
pin = event.get("pin")?.asString,
location = event.get("location")?.asString,
customerLocation = event.get("customerlocation")?.asString,
nodes = nodes,
closed = event.get("closed").asInt,
type = event.get("type").asInt,
ticketId = event.get("ticketid")?.asString,
customerName = event.get("customername")?.asString,
contacts = contacts,
addresses = addresses,
assignments = assignments
)
}
}
}
and this is how I'm creating gson factory
val gson = GsonBuilder().registerTypeAdapter(Event::class.java, EventDeserializer())
Retrofit
.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(
GsonConverterFactory.create(gson.create())
)
.callbackExecutor(Executors.newSingleThreadExecutor())
and the structure of response looks like this
Call<List<Event>>
but the list always have 1 element and this is artifact of old api that i can't change
Ok, so I figured this out, apparently your deserializer needs to be the exactly the same type as your response, so I added the interceptor that removed excess array that wrapped every response and now deserializer is being ussed as intended.

Decode Token JWT android kotlin?

I have a token like this:
hereeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyYWRvciI6eyJpZCI6NzAsIm5vbWUiOiJERUlWSVRJIiwidXN1YXJpbyI6IkRFSVZJVEkifSwiaWF0IjoxNjI5ODEyNDA1fQ.JqzQnFSbG6gFsnlJu3-bezxZ_N5e5FEzc9QvpRGu0u4
hide it:
alg: "HS256",
typ: "JWT"
}.
operador: {
id: 20,
nome: "JOAO",
usuario: "JOAO"
},
iat: 1629812405
}
Question is how do I get on android kotlin only user id to use in certain tasks?
You could use this,
https://github.com/auth0/JWTDecode.Android
Assuming the iat value is the user id,
var jwt: JWT = JWT(YOUR_TOKEN_STRING)
var claim: Claim = jwt.getClaim("iat")
//or as a string
var claim: String = jwt.getClaim("iat").asString()
I just fix the issue thanks to this:
private fun decodeToken(jwt: String): String {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return "Requires SDK 26"
val parts = jwt.split(".")
return try {
val charset = charset("UTF-8")
val header = String(Base64.getUrlDecoder().decode(parts[0].toByteArray(charset)), charset)
val payload = String(Base64.getUrlDecoder().decode(parts[1].toByteArray(charset)), charset)
"$header"
"$payload"
} catch (e: Exception) {
"Error parsing JWT: $e"
}
}
Then :
val mDecode = decodeToken(mToken)
val test = JSONObject(mDecode).getString("operador")
val mDecodeTokenOk = JSONObject(test).getString("id")
/** SALVANDO ID_OPERADOR */
mSharedPreferences.saveString(WmsConstantes.ID_OPERADOR,mDecodeTokenOk)
Log.e("------------------>", mDecodeTokenOk.toString());
You don't have to install any libraries. You can try something like this.
Class(s) reflecting your JWT payload
data class JwtPayload(
#SerializedName("iat")
val iat: Int,
#SerializedName("operador")
val operador: Operador
)
data class Operador(
#SerializedName("id")
val id: Int,
#SerializedName("nome")
val nome: String,
#SerializedName("usuario")
val usuario: String
)
You can use this class as a wrapper for your token
class Jwt(private val token: String) {
private val userData: JsonObject by lazy {
val userData = String(Base64.decode(token.split(".")[1], Base64.DEFAULT), StandardCharsets.UTF_8)
JsonParser.parseString(userData).asJsonObject
}
fun getUserData(): JwtPayload{
gson.toJson(userData, Jwt::class.java)
return gson.fromJson(userData, JwtPayload::class.java)
}
fun isExpired(): Boolean {
return userData.asJsonObject.get("exp").asLong < (System.currentTimeMillis() / 1000)
}
companion object {
#JvmStatic
private val gson = Gson()
}
}
Usage
val token = Jwt("YOUR_TOKEN")
val operatorID = token.operator.id

Successful API call returning null value when using Single.zip()

I am using Single.zip() and Function 5 to consolidate 5 API calls into one Single:
private fun loadProfileAndBalances() {
registerSubscription(
Single.zip<AvailableFundsResult, IncomingFundsResult, TotalEarnedResult, TotalDonatedResult, ProfileResult, Unit>(
Interactors.api.paymentsApiClient.getAvailableFunds()
.map<AvailableFundsResult> {
Timber.d("Available Result [${it.amount}]") <------ DollarAmount object with null amount
AvailableFundsResult.Amount(it) }
.onErrorReturn { AvailableFundsResult.Error(it) }
.scheduleIOUI(),
Interactors.api.paymentsApiClient.getIncomingFunds()
.map<IncomingFundsResult> { IncomingFundsResult.Amount(it) }
.onErrorReturn { IncomingFundsResult.Error(it) }
.scheduleIOUI(),
Interactors.api.paymentsApiClient.getTotalEarned()
.map<TotalEarnedResult> { TotalEarnedResult.Amount(it) }
.onErrorReturn { TotalEarnedResult.Error(it) }
.scheduleIOUI(),
Interactors.api.paymentsApiClient.getTotalDonated()
.map<TotalDonatedResult> { TotalDonatedResult.Amount(it) }
.onErrorReturn { TotalDonatedResult.Error(it) }
.scheduleIOUI(),
Interactors.profileManager.getNotCachedProfile()
.map<ProfileResult> { ProfileResult.Profile(it) }
.onErrorReturn { ProfileResult.Error(it) }
.scheduleIOUI(),
Function5 { availableFunds: AvailableFundsResult, incomingFunds: IncomingFundsResult, totalEarned: TotalEarnedResult, totalDonated: TotalDonatedResult, profileResult: ProfileResult ->
availableTotal = when (availableFunds) {
is AvailableFundsResult.Amount ->
availableFunds.result.amount
is AvailableFundsResult.Error -> {
Timber.w(availableFunds.throwable, "Error while fetching sponsorships")
"0.00"
}
}
incomingTotal = when (incomingFunds) {
is IncomingFundsResult.Amount -> incomingFunds.result.amount
is IncomingFundsResult.Error -> {
Toast.makeText(activity, getString(R.string.payout_main_error_loading_totals), Toast.LENGTH_SHORT).show()
"0.00"
}
}
earnedTotal = when (totalEarned) {
is TotalEarnedResult.Amount -> totalEarned.result.amount
is TotalEarnedResult.Error -> {
Toast.makeText(activity, getString(R.string.payout_main_error_loading_totals), Toast.LENGTH_SHORT).show()
"0.00"
}
}
donatedTotal = when (totalDonated) {
is TotalDonatedResult.Amount -> totalDonated.result.amount
is TotalDonatedResult.Error -> {
Toast.makeText(activity, getString(R.string.payout_main_error_loading_totals), Toast.LENGTH_SHORT).show()
"0.00"
}
}
onboardingComplete = when (profileResult) {
is ProfileResult.Profile ->
profileResult.result.isOnboardingCompleted
is ProfileResult.Error -> {
Timber.e(profileResult.throwable, "Error fetching profile")
true
}
}
}
).ignoreElement()
.subscribe(::updateViews) {
it.printStackTrace()
availableTotal = ""
incomingTotal = ""
earnedTotal = ""
donatedTotal = ""
onboardingComplete= false
vWalletRefresher.isRefreshing = false
internetConnectionError(it)
})
}
Each of these API calls is succeeding with code 200. The call made with Interactors.api.paymentsApiClient.getAvailableFunds() is returning {"amount":264.69}, which is parsed into an object of this class:
internal data class DollarAmount(#SerializedName("amount") val amount: String)
The paymentsApiClient repeatedly referenced is built like this:
private fun createNewPaymentsClient(authRefreshClient: AuthRefreshClient,
preferencesInteractor: PreferencesInteractor): PaymentsApiClient {
val loggingInterceptor = run {
val httpLoggingInterceptor = HttpLoggingInterceptor()
httpLoggingInterceptor.apply {
httpLoggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
}
}
val okHttpClient = createHttpClientBuilder()
.addInterceptor(createSessionRequestInterceptor())
.addInterceptor(createUserAgentInterceptor(context))
.addInterceptor(loggingInterceptor)
.authenticator(RefreshUserAuthenticator(authRefreshClient, preferencesInteractor,
UnauthorizedNavigator(SDKInternal.appContext, Interactors.preferences)))
.build()
val gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().setLenient().create()
return Retrofit.Builder()
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(Interactors.apiEndpoint)
.build()
.create(PaymentsApiClient::class.java)
}
Despite the API call being successful, the log statement that is printed in Single.zip for a successful retrieval of a DollarAmount via Interactors.api.paymentsApiClient.getAvailableFunds() the is showing its amount as being null, rather than 264.69. What is wrong with my parsing that is making this null?
Edit: As someone noticed, I am wrapping the results in another set of classes:
private sealed class AvailableFundsResult {
data class Error(val throwable: Throwable) : AvailableFundsResult()
data class Amount(val result: DollarAmount) : AvailableFundsResult()
}
private sealed class IncomingFundsResult {
data class Error(val throwable: Throwable) : IncomingFundsResult()
data class Amount(val result: DollarAmount) : IncomingFundsResult()
}
private sealed class TotalEarnedResult {
data class Error(val throwable: Throwable) : TotalEarnedResult()
data class Amount(val result: DollarAmount) : TotalEarnedResult()
}
private sealed class TotalDonatedResult {
data class Error(val throwable: Throwable) : TotalDonatedResult()
data class Amount(val result: DollarAmount) : TotalDonatedResult()
}
private sealed class ProfileResult {
data class Error(val throwable: Throwable) : ProfileResult()
data class Profile(val result: InfluencerProfileDto) : ProfileResult()
}
I don't think this is relevant though because it the amount is coming back null before I even spit out an instance of these wrapper classes.
Edit 2: Class that gets returned from 5th API call:
#JsonClass(generateAdapter = true)
internal data class InfluencerProfileDto(
#Json(name = "id") val id: String,
#Json(name = "emailAddress") val email: String?,
#Json(name = "phoneNumber") val phoneNumber: PhoneNumberDto?,
#Json(name = "isPhoneNumberVerified") val isPhoneNumberVerified: Boolean,
#Json(name = "isEmailVerified") val isEmailVerified: Boolean,
#Json(name = "notificationTimePreference") val notificationTimePreference: String,
#Json(name = "isInstagramConnected") val isInstagramConnected: Boolean,
#Json(name = "isFacebookConnected") val isFacebookConnected: Boolean,
#Json(name = "isTwitterConnected") val isTwitterConnected: Boolean,
#Json(name = "currencyIsoSymbol") val currencyIsoSymbol: String,
#Json(name = "currencySymbol") val currency: String,
#Json(name = "birthDate") val birthDate: Date?,
#Json(name = "name") val name: String?,
#Json(name = "profilePictureUri") val avatarUrl: String?,
#Json(name = "gender") val gender: Gender?)
{
val isOnboardingCompleted: Boolean
get() = gender!= Gender.UNKNOWN && birthDate!= null && !!notificationTimePreference.isNullOrEmpty() && isPhoneNumberVerified && !email.isNullOrEmpty()
}
my approach is in java
first of all we need two libraries that you might not be using in your project ie.
gson => for pasing objects from string and vice versa
volley => for string http requests
please google their official github pages and install the latest versions
then we ll be creating a common result object to bear results
class Result {
boolean error; // this field can be used by the api to tell if there was some error while processing the request
String message; // here api can give you some extra message if there was some error
String result; // here you get the result. you can make it a map as well if you want to receive an object and later parse to a unique object class
}
this is a function you can use for HTTP requets
public static Single<Result> getHttpResult(String api, Map<Stirng, String> params){
return Single.create(emitter -> {
StringRequest stringRequest = new StringRequest(Request.Method.POST, api, response -> {
Log.i("RESPONSE :", response);
try {
Result result = new Gson().fromJson(response, Result.java);
emitter.onSuccess(result);
} catch (JSONException e) {
emitter.onError(e);
}
}, emitter::onError) {
#Override
protected Map<String, String> getParams() {
return params;
}
};
stringRequest.setRetryPolicy(new DefaultRetryPolicy(0, 0, 0));
RequestQueue requestQueue = Volley.newRequestQueue(context);
requestQueue.add(stringRequest);
});
}
this is how you can get multiple results at once and i recommend you also check the internet connectivity if user has enough internet then only make parallel requests else it wont produce good UX
...
List<Single<Result>> tasks = new ArrayList();
tasks.add(getHttpResult("https://..."), /**here you can add a map with params that your api might require for auth and other purposes**/);
tasks.add(...);
tasks.add(...);
tasks.add(...);
Single.zip(tasks, objects -> {
List<Result> results = new ArrayList();
for(Object object : objects){
results.add((Result)object)
}
return results;
}).subscribe(results -> {
// this result object have all the results of http requests
// for distinguising results from each other you can create a field on the result object
});
...
hope my approach is helpful to you ;)

Android: JSON object getString

I use this JSON https://api.github.com/users
I need to get string name, followers, following, and more. But on the program says "No value for name". I think I need to go to a specific user example: https://api.github.com/users/mojombo to getting that info, but I don't know-how.
And I using loopj library.
Here's My Code
private fun getDataGitDetail() {
progressBar.visibility = View.VISIBLE
val client = AsyncHttpClient()
client.addHeader("Authorization", "token 6fe9dff2e5e43d25eb3abe9ff508a750b972f725")
client.addHeader("User-Agent", "request")
val url = "https://api.github.com/users"
client.get(url, object : AsyncHttpResponseHandler() {
override fun onSuccess(
statusCode: Int,
headers: Array<Header>,
responseBody: ByteArray
) {
progressBar.visibility = View.INVISIBLE
val result = String(responseBody)
Log.d(TAG, result)
try {
val jsonArray = JSONArray(result)
for (i in 0 until jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(i)
val username: String? = jsonObject.getString("login")
val name: String? = jsonObject.getString("name")
val avatar: String? = jsonObject.getString("avatar_url")
val company: String? = jsonObject.getString("url")
val location: String? = jsonObject.getString("url")
val repository: Int = 0
val followers: Int = 0
val following: Int = 0
listData.add(
Data(
username,
name,
avatar,
company,
location,
repository,
followers,
following
)
)
}
showRecyclerList()
} catch (e: Exception) {
Toast.makeText(this#MainActivity, e.message, Toast.LENGTH_SHORT)
.show()
e.printStackTrace()
}
}
override fun onFailure(
statusCode: Int,
headers: Array<Header>,
responseBody: ByteArray,
error: Throwable
) {
progressBar.visibility = View.INVISIBLE
val errorMessage = when (statusCode) {
401 -> "$statusCode : Bad Request"
403 -> "$statusCode : Forbidden"
404 -> "$statusCode : Not Found"
else -> "$statusCode : ${error.message}"
}
Toast.makeText(this#MainActivity, errorMessage, Toast.LENGTH_LONG)
.show()
}
})
}
The current response you are getting does not contain a key name in the JSONObject.
If you want the Name of all the users you will have to go to each users endpoint in the api. You'll need to make another request inside your for loop that gets datafrom an endpoint like https://api.github.com/users/mojombo
val jsonArray = JSONArray(result)
for (i in 0 until jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(i)
val username: String? = jsonObject.getString("login")
//Make the request here using "https://api.github.com/users/" + login
You can then choose to get the rest of the data from either the first response or the 2nd one as both contain that information.
I hope this helps.
No need for a JSON array, cz API https://api.github.com/users/mojombo is JSON Object.
Example:
client.get(url, object : AsyncHttpResponseHandler() {
override fun onSuccess(statusCode: Int, headers: Array<Header>, responseBody: ByteArray) {
try {
//parsing json
val result = String(responseBody)
val responseObject = JSONObject(result)
textView2.text = responseObject.getString("login")
textView3.text = responseObject.getString("name")
textView9.text = responseObject.getString("location")
desc.text = responseObject.getString("company")
view?.let { Glide.with(it).load(responseObject.getString("avatar_url")).into(imageView2) }
} catch (e: Exception) {
Log.d("Exception", e.message.toString())
}
}
}

How to read child of child data from firebase in android / kotlin

I am trying to read data from my firebase realtime database to a TextView. But every time it shows null in TextView. I want to read single user data. I want to read data when user give input.
My Data Structure look like this..
{
"Date": {
"04-10-2019": {
"-LqR-e2UJLJCccqfgGi1":{
address: Dhaka
date: 04-10-2019
name: Mark
phoneNo: 017#######
serialNo: -LqR-e2UJLJCccqfgGi1
type: New
},
},
"05-10-2019": {
"-LqU-e2UJLJCDcqfgGi9":{
address: Dhaka
date: 04-10-2019
name: Tony
phoneNo: 017#######
serialNo: -LqU-e2UJLJCDcqfgGi9
type: OLd
},
}
}
The code that I am trying.
class Info(
val serialNo: String? = "",
val name: String = "",
val address: String = "",
val phoneNo: String = "",
val date: String = "",
var type: String = ""
)
private fun saveInfo() {
// Edit Text Field
val name = editTextName.text.toString().trim()
if (name.isEmpty()) {
editTextName.error = "Please Enter Your Name"
return
}
val address = editTextAddress.text.toString().trim()
if (address.isEmpty()) {
editTextAddress.error = "Please Enter Your Address"
return
}
val phoneNo = editTextPhoneNo.text.toString().trim()
if (phoneNo.isEmpty()) {
editTextPhoneNo.error = "Please Enter Your Phone Number"
return
}
val date = dateText.text.toString().trim()
//Radio Button
var type = ""
when {
checkboxNew.isChecked -> type += "New"
checkboxOld.isChecked -> type += "Old"
radioGroup.checkedRadioButtonId <= 0 -> {
Toast.makeText(applicationContext, "Please Check New or Old", Toast.LENGTH_LONG)
.show()
return
}
}
val current = LocalDateTime.now()
val formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
val formatted = current.format(formatter)
val myRef = FirebaseDatabase.getInstance().getReference("Date").child(formatted)
myRef.orderByChild(formatted).startAt("28-09-2019").endAt("31-12-2070")
val patientId = myRef.push().key
val patient = Info(patientId, name, address, phoneNo, date, type)
myRef.child((patientId).toString()).setValue(patient).addOnCompleteListener {
Toast.makeText(applicationContext, "Info saved Successfully", Toast.LENGTH_LONG).show()
myRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (data in dataSnapshot.children) {
val user = data.child(formatted).value.toString()
dataText.text = user
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
}
I want to show the data into a textview when the user give input and hit a button.
If you are trying to read the date attribute from the database then change this :
val user = data.child(formatted).value.toString()
Into this:
val user = data.child("date").value.toString()
Inside the child() you need to pass the name of the attribute.

Categories

Resources