I want to make api calls using json object request in android studio using kotlin.
This is the api.
How to access the 'name' in the array articles ?. I can access all the other things except 'id' and 'name'.
This is my code
val url = "https://news-api-don.herokuapp.com/api/v1?apiKey=20d14506791144cc8b424549c42068c0"
val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET, url, null,
{
val newsJsonArray = it.getJSONArray("articles")
val newsArray = ArrayList<News>()
for(i in 0 until newsJsonArray.length()) {
val newsJsonObject = newsJsonArray.getJSONObject(i)
val news = News(
newsJsonObject.getString("title"),
newsJsonObject.getString("author"),
newsJsonObject.getString("url"),
newsJsonObject.getString("urlToImage")
)
newsArray.add(news)
}
mAdapter.updateNews(newsArray)
swipeRefreshLayout.isRefreshing = false
progressBar.visibility = View.GONE
},
{
Toast.makeText(this,"Something went wrong", Toast.LENGTH_LONG).show()
swipeRefreshLayout.isRefreshing = false
progressBar.visibility = View.GONE
}
)
MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest)
}
I tried convert to data class to map. (Under the code is just example code)
data class User (
val name : String = "",
val age : Int = 0,
val deviceGroup: MutableSet<DeviceGroup> = mutableSetOf()
)
data class DeviceGroup (
val name : String = "",
val deviceLink : MutableSet<DeviceLink> = mutableSetOf()
)
data class DeviceLink (
val id : Int = 0,
val device : Device
)
data class Device (
val devId : Int = 0,
val name : String = ""
)
fun main (request : HttpServletRequest) {
val currentUser = request.session.getAttribute("user") as User
val data = userRepository.findByName(currentUser.name)
// return currentUser
// result is {name="test", age=17, deviceGroup = [{name="group1"}, {name="group2"}]}
// I want deserialization data class to Map
val response = data.deviceGroup.toMap()
response.deivceGroup.forEach {
// And add new key, pair
it.add(Map<String, MutableSet<Device>>("devices", mutableSetOf()))
// Lastly, I want put in the value
deviceGroupRepository.findByName(it.name).deviceLink.forEach {
it.devices.add(this)
}
}
return response
}
if just return the data value, that's result is "{name="test", age=17, deviceGroup = [{name="group1"}, {name="group2"}]}"
How to convert to data class to Map object and add new key pair?
Use associate to turn a collection into a Map
The Kotlin standard library provides a function called associate which will take a collection of objects and transform them into a map. It takes one argument, which is a function specifying what the keys and values of the map should be.
For example, in your case, you would call it like this:
val response = data.deviceGroup.associate { it.name to it.deviceLink }
It will return a Map<String, MutableSet<DeviceLink>> where the key is the name of the device group and the value is the deviceLink set.
The easiest way to add new values is simply to append them with the + operator.
val response = data.deviceGroup.associate {
it.name to it.deviceLink
} + mapOf("device" to emptySet())
If you need more control than that, you could use .toMutableMap() so new entries can be added using put.
val response = data.deviceGroup.associate {
it.name to it.deviceLink
}.toMutableMap()
response.put("device", emptySet())
I'm having some issues building out a section of my code which edits server sent thumbnails and renders them as a Google GroundOverlay.
The issue seems to stem from Kotlin Coroutines. First, the documentation from Google says that the ground overlays must be created on the Main Thread. Running their creation out of the main thread causes a fatal error. So I have been sure to make these GroundOverlays on the main thread. When trying to create the bitmap on a thread out of Main, however, I seem to get no overlay at all.
class BarreMapFragment : Fragment(),
GoogleMap.OnCameraIdleListener,
GoogleMap.OnCameraMoveCanceledListener,
GoogleMap.OnCameraMoveListener,
GoogleMap.OnCameraMoveStartedListener,
OnMapReadyCallback {
//Main handler for google map/item styling
googleMapHandler = GoogleMapHandler(gMap!!, activity!!.applicationContext, DefaultTheme, lifecycle.coroutineScope)
. . .
open class GoogleMapHandler(val gMap: GoogleMap,
val context: Context,
val mapThemeInstructions: MapThemeInstructions,
val coroutineScope: CoroutineScope
) {
fun updateActiveUserAvatarPosition(position: LatLng) {
if (mActiveUserAvatar == null) {
coroutineScope.launch {
mActiveUserAvatar = mapObjectFactory.factory(
MapObject(
latitude = position.latitude,
longitude = position.longitude,
objectId = "SELF_AVATAR",
objectType = MapObjectType.USER_AVATAR,
timestamp = System.currentTimeMillis(),
weight = 20.toFloat()
), getOverlayWidthByZoom(dpScreenWidth, gMap.cameraPosition.target, gMap.cameraPosition.zoom)) as RenderedUserAvatarItem
}
}
mActiveUserAvatar?.updatePosition(position)
}
suspend fun factory(mapObject: MapObject, diameter: Float) : RenderedMapItem {
overlayDiameter = diameter
val item = RenderedUserAvatarItem(
mapObject,
buildOverlay(mapObject)
)
return item
}
#MainThread
private suspend fun buildOverlay(mapObject: MapObject) : GroundOverlay {
Log.d("UserOverlay", "I was called.")
//Get the bitmap from the resources
//TODO: We can do more with this later... Like custom avatars
//val bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.ic_user_avatar)
val bitmap = withContext(Dispatchers.Default) {
async {
val d: Drawable = context.getDrawable(R.drawable.ic_user_avatar)!!
val bitmap : Bitmap = drawableToBitmap(d)!!
bitmap
}
}.await()
//val d: Drawable = context.getDrawable(R.drawable.ic_user_avatar)!!
//val bitmap : Bitmap = drawableToBitmap(d)!!
Log.d(TAG, "bitmap = " + bitmap.toString())
//Make bitmap descriptor
val descriptor = BitmapDescriptorFactory.fromBitmap(bitmap)
val overlayOptions = GroundOverlayOptions().image(descriptor)
//Position and size of groundoverlay
overlayOptions.position(LatLng(mapObject.latitude, mapObject.latitude) , overlayDiameter)
//Add the overlay to the map, get a handle and save it to public Overlay list
val mOverlay = gMap.addGroundOverlay(overlayOptions)
//Store the moment information in the overlay tag
mOverlay.tag = mapObject.objectId
return mOverlay
}
The suspend function is called from the main thread. Now,
val bitmap = withContext(Dispatchers.Unconfined) {
async {
val d: Drawable = context.getDrawable(R.drawable.ic_user_avatar)!!
val bitmap : Bitmap = drawableToBitmap(d)!!
bitmap
}
}.await()
and the commented out section above (without using async)
val d: Drawable = context.getDrawable(R.drawable.ic_user_avatar)!!
val bitmap : Bitmap = drawableToBitmap(d)!!
Will both yield a GroundOverlay with no problems. The problem happens when I change Dispatchers.Unconfined to anything else. Even Dispatchers.Main causes the GroundOverlay to not show up on the map. The GroundOverlays are made, I have checked them with log statements. Their transparency is expected as is their visibility. The issue seems to be with the Bitmap. I suspect I am not understanding the way the await() works. I figured that it would pause the suspend function until the bitmap is returned and ready to go.
This is simplified code to isolate the error. I do need this to be done on Dispatchers.Default because each thumbnail is adjusted in style depending on the location and time of day. This bit of processing would be hard on the UI if done on the main thread.
JSON Data Parsing Using Retofit2 and Rxjava2. This Data get In ArrayList successfully. its ArrayList Size is Nine but its display only two Record in Table. After Two Record its Kotlin.NullPointerException.
JSON Data:
{"success":1,"salesGst":[{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"1","ChallanDate":"2019-03-15 00:00:00","ChallanAmount":"2778.75","TaxTotal":"2778.75","InvoiceType":"Retail Invoice","CGSTTotal":"0.0","PartyGST":"CDE","SGSTTotal":"0.0","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"1","ChallanDate":"2019-03-13 00:00:00","ChallanAmount":"2203.0","TaxTotal":"2118.5","InvoiceType":"Tax Invoice","CGSTTotal":"52.96","PartyGST":"CDE","SGSTTotal":"52.96","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"VIKAS","ChallanNo":"2","ChallanDate":"2019-03-16 00:00:00","ChallanAmount":"6975.0","TaxTotal":"6975.0","InvoiceType":"Retail Invoice","CGSTTotal":"0.0","PartyGST":null,"SGSTTotal":"0.0","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES MH","ChallanNo":"2","ChallanDate":"2019-03-13 00:00:00","ChallanAmount":"420.0","TaxTotal":"403.75","InvoiceType":"Tax Invoice","CGSTTotal":"0.0","PartyGST":"ABC","SGSTTotal":"0.0","IGSTTotal":"20.19"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"3","ChallanDate":"2019-03-14 00:00:00","ChallanAmount":"4788.0","TaxTotal":"4560.0","InvoiceType":"Tax Invoice","CGSTTotal":"114.0","PartyGST":"CDE","SGSTTotal":"114.0","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"4","ChallanDate":"2019-03-15 00:00:00","ChallanAmount":"241.9","TaxTotal":"230.38","InvoiceType":"Tax Invoice","CGSTTotal":"5.76","PartyGST":"CDE","SGSTTotal":"5.76","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"5","ChallanDate":"2019-03-15 00:00:00","ChallanAmount":"5563.68","TaxTotal":"5101.5","InvoiceType":"Tax Invoice","CGSTTotal":"231.28","PartyGST":"CDE","SGSTTotal":"231.28","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"6","ChallanDate":"2019-03-16 00:00:00","ChallanAmount":"13238.0","TaxTotal":"12459.25","InvoiceType":"Tax Invoice","CGSTTotal":"389.29","PartyGST":"CDE","SGSTTotal":"389.29","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES MH","ChallanNo":"7","ChallanDate":"2019-03-16 00:00:00","ChallanAmount":"2074.0","TaxTotal":"1975.0","InvoiceType":"Tax Invoice","CGSTTotal":"0.0","PartyGST":"ABC","SGSTTotal":"0.0","IGSTTotal":"98.75"}]}
Please Guide Me,After Getting How to Show in TableLayout.
In ArrayList Nine Record but in Table show only Two Record another seven record is not display. in third record taxtotal give kotlin.nullpointerException. what missing?
private fun displaySalesGSTData(salesGSt : List<SalesGST>) {
salesGST = SalesGST()
tvSalesCompanyName.setText(salesGSt.get(1).Cmp_Name)
tvGSTIN.setText(salesGSt.get(1).GSTIN)
val rowHeader = TableRow(this#Sales)
rowHeader.setBackgroundColor(Color.parseColor("#c0c0c0"))
rowHeader.setLayoutParams(TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT,
TableLayout.LayoutParams.WRAP_CONTENT))
val headerText = arrayOf<String>("Sr.No.", "Invoice Type", "Bill No.", "Bill Date", "Firm Name", "GST NO","TAX Total","CGST","SGST","IGST","Net Amount")
for (c in headerText)
{
val tv = TextView(this#Sales)
tv.setLayoutParams(TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
TableRow.LayoutParams.WRAP_CONTENT))
tv.setGravity(Gravity.CENTER)
// tv.setBackgroundResource(R.drawable.table_header)
tv.setTextColor(Color.parseColor("#3F51B5"))
tv.setTextSize(18F)
tv.setPadding(5, 5, 5, 5)
tv.setText(c)
rowHeader.addView(tv)
}
tableMarks.addView(rowHeader)
for (j in 0 until salesGSt.size)
{
/*val jsonObject1 = jsonArray.getJSONObject(j)
val date = jsonObject1.getString("ExamDate")
val inputFormatter1 = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val date1 = inputFormatter1.parse(date)
val outputFormatter1 = SimpleDateFormat("dd-MMM-yyyy")
ExamDate = outputFormatter1.format(date1)*/
/* String replaceDate = date.replace("/Date(", "").replace(")/", "");
Long getDate = Long.valueOf(replaceDate);
ExamDate = dateFormat.format(getDate);*/
/*Subject = jsonObject1.getString("subject")
ExamName = jsonObject1.getString("ExamName")
TotalMark = jsonObject1.getLong("TotalMarks")
PassingMark = jsonObject1.getLong("PassingMarks")
Mark = jsonObject1.getLong("Marks")*/
var fName : String = salesGSt.get(j).FirmName!!
var invoice : String = salesGSt.get(j).InvoiceType!!
var bill_no : String = salesGSt.get(j).ChallanNo!!
var bill_date : String = salesGSt.get(j).ChallanDate!!
var gst_no : String = salesGSt.get(j).PartyGST!!
var tax_total : Double = salesGSt.get(j).TaxTotal!!.toDouble()
var cgst : String = salesGSt.get(j).CGSTTotal!!
var igst : String = salesGSt.get(j).IGSTTotal!!
var sgst : String = salesGSt.get(j).SGSTTotal!!
var net_amount : String = salesGSt.get(j).ChallanAmount!!
var sr : Int = j + 1
// dara rows
val row = TableRow(this#Sales)
row.setLayoutParams(TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT,
TableLayout.LayoutParams.WRAP_CONTENT))
val colText = arrayOf<String>(sr.toString(),(invoice), bill_no, bill_date, fName, gst_no, tax_total.toString(),cgst,sgst,igst,net_amount)
for (text in colText)
{
val tv = TextView(this#Sales)
tv.setLayoutParams(TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
TableRow.LayoutParams.WRAP_CONTENT))
tv.setGravity(Gravity.CENTER)
// tv.setBackgroundResource(R.drawable.table_shape)
tv.setTextSize(18F)
tv.setTextColor(Color.parseColor("#3F51B5"))
tv.setPadding(5, 5, 5, 5)
tv.setText(text)
row.addView(tv)
}
tableMarks.addView(row)
}
}
The 3rd item, salesGst[2], is "PartyGST": null. Your json deserializer library won't handle non-null fields as it's written in Java. I assume you have a data class where PartGST is defined as non-null, yet the deserializer will still parse it as null. Therefore, when you access PartyGST then you will receive a NullPointerException because Kotlin is expecting it to be non-null. This is a good article, which explains in more detail:
I've trusted you! You promised no null pointer exceptions!
A solution to this would be to have two models. The DTO (for JSON response) where all fields are optional and your internal model (used by your app), where you define which fields you want to be optional. Then you can have a mapper to handle the case where a field is null in the DTO, but non-null in your internal model:
// Models for your API response
data class SalesGstsDTO(val gsts: List<GstDTO>)
data class GstDTO(val name: String?, val surname: String?)
// Internal models used by your app
data class SalesGsts(val gsts: List<Gst>)
data class Gst(val name: String, val surname: String?)
class SalesGstDTOMapper {
fun mapToSalesGsts(salesGstsDTO: SalesGstsDTO): SalesGsts {
val gsts = mutableListOf<Gst>()
salesGstsDTO.gsts.map {
val name = it.name ?: return#map // Skips this item. You could handle this how you wish
val surname = it.surname
val gst = Gst(name, surname)
gsts.add(gst)
}
return SalesGsts(gsts)
}
}
This also allows you to decouple your app from the JSON response.