In need your help in modifying my code, I am trying to build an application that contains a flight schedule by searching on a flight number via data json . l am using edit text and AsyncTask and custom list adapter list view .My application works fine, but the problem is when the user enters the flight number in wrong way l got FATAL EXCEPTION . because data json url he has data array when user enters correct flight number , other ways if user enters wrong flight number the data json url he will back data json in jsonobject and l get FATAL EXCEPTION is
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.iraqairoirt.iraqairports, PID: 5380
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
Caused by: org.json.JSONException: Value null of type org.json.JSONObject$1 cannot be converted to JSONArray
at org.json.JSON.typeMismatch(JSON.java:111)
at org.json.JSONArray.<init>(JSONArray.java:96)
at org.json.JSONArray.<init>(JSONArray.java:108)
at com.iraqairoirt.iraqairports.BaghdadAirport.FlightSearch$Arr.handleJson(FlightSearch.kt:106)
at com.iraqairoirt.iraqairports.BaghdadAirport.FlightSearch$Arr.onPostExecute(FlightSearch.kt:90)
at com.iraqairoirt.iraqairports.BaghdadAirport.FlightSearch$Arr.onPostExecute(FlightSearch.kt:58)
at android.os.AsyncTask.finish(AsyncTask.java:660)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:677)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
data json if input is correct l get data array
{
"result": {
"request": {},
"response": {
"data": [
{
"identification": {
"id": null,
"row": 4849651452,
"callsign": null,
"codeshare": null
},
"status": {
"live": false,
"text": "Scheduled",
"icon": null,
"estimated": null,
"ambiguous": false
}
}
]
}
}
}
if input is wrong l get data json object and fatal EXCEPTION
{
"result": {
"request": {},
"response": {
"data": null
}
}
}
class activity including list adapter
class FlightSearch : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_flight_search)
flightlistlaout.bringToFront()
}
fun getflightsearchresult(view:View){
val FlightNumber=flightnumbertext.text.toString()
// val auto=autoCompleteTextView.text.toString()
if(FlightNumber.trim().length>0) {
val url = "flight/list.json?query="+FlightNumber+"&fetchBy=flight&page=1&limit=100&token="
Arr().execute(url)
Toast.makeText(applicationContext, "Message : ", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(applicationContext, "Please enter some message! ", Toast.LENGTH_SHORT).show()
}
}
inner class Arr : AsyncTask<String, String, String>() {
override fun onPreExecute() {
super.onPreExecute()
}
// for build connection
override fun doInBackground(vararg url: String?): String {
var text: String
val connection = URL(url[0]).openConnection() as HttpURLConnection
connection.connectTimeout = 700
try {
connection.connect()
text = connection.inputStream.use { it.reader().use { reader -> reader.readText() } }
} finally {
connection.disconnect()
}
return text
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
handleJson(result)
}
override fun onProgressUpdate(vararg text: String?) {
}
#SuppressLint("WrongViewCast")
private fun handleJson(jsonString: String?) {
val jsonObj = JSONObject(jsonString)
val result = jsonObj.getJSONObject("result")
val response = result.getJSONObject("response")
val jsonArray = JSONArray(response.get("data").toString())
val list = ArrayList<FlightShdu>()
var x = 0
while (x < jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(x)
list.add(
FlightShdu(
jsonObject.getJSONObject("identification").getJSONObject("number").getString("default"),
jsonObject.getJSONObject("airline").getString("name"),
jsonObject.getJSONObject("status").getJSONObject("generic").getJSONObject("status").getString(
"text"
),
jsonObject.getJSONObject("airline").getJSONObject("code").getString("icao"),
jsonObject.getJSONObject("time").getJSONObject("scheduled").getString("arrival"),
jsonObject.getJSONObject("airport").getJSONObject("origin").getJSONObject("code").getString(
"iata"
x++
}
list.forEach(::println)
var adapter = FlightSearchAdpater(this#FlightSearch, list)
flightsearchlists.adapter = adapter
}
}
}
class FlightSearchAdpater (val context: Context, val list: ArrayList<FlightShdu>): BaseAdapter() {
#SuppressLint("ViewHolder", "NewApi", "WrongViewCast")
override fun getView(p0: Int, convertView: View?, parent: ViewGroup?): View {
val view : View = LayoutInflater.from(context).inflate(R.layout.baghdad_arrivel_list,parent,false)
val list = list[p0]
val LogoAriline = view.findViewById(R.id.logo_image) as ImageView
val status = view.findViewById(R.id.ali_id) as AppCompatTextView
val Airport = view.findViewById(R.id.airportid) as AppCompatTextView
val code = view.findViewById(R.id.code_id) as AppCompatTextView
val TimeFlight = view.findViewById(R.id.time_id) as AppCompatTextView
val checkiflive = view.checkifliveTextId
view.callsign_id.text=list.Callsign
view.airline_id.text=list.Airline
code.text = list.code
view.ali_id.text=list.Stauts
status.text= list.Stauts
TimeFlight.text = getDateTime(list.TimeFlight)
Picasso.with(context).load(Uri.parse("/data/operators/"+status.text.toString()+"_logo0.png"))
.error(R.drawable.logo).into(LogoAriline)
Airport.text= list.Airport
view.model_id.text=list.Model
checkiflive.text=list.IfLive
private fun getDateTime(s: String): String? {
try {
val sdf = SimpleDateFormat("EE, MMM d KK:mm a")
val netDate = Date(s.toLong() * 1000)
return sdf.format(netDate)
} catch (e: Exception) {
return e.toString()
}
}
override fun getItem(p0: Int): Any {
return list [p0]
}
override fun getItemId(p0: Int): Long {
return p0.toLong()
}
override fun getCount(): Int {
return list.size
}
}
when l track FATAL EXCEPTION: main found the main problem in line 106 with this code val jsonArray = JSONArray(response.get("data").toString())
please l want answer with code guys , l want add text when the user enters wrong information he get respond example "no flights found please make sure about the flight number "
thank you
Caused by: org.json.JSONException: Value null of type
org.json.JSONObject$1 cannot be converted to JSONArray
You should check getJSONArray is null or not
Below code will work if Your Json "data":[]
val jsonData = response.getJSONArray("data")
if(jsonData.length()!=0)
{
// Do your work
}
FYI
You should check your Json data JSONArray or String.
Object dataVal= response.get("data");
if (dataValis is JSONArray)
{
// Your code
}
else
{
// null value
}
l found this way and its working fine
private fun handleJson(jsonString: String?) {
val jsonObj = JSONObject(jsonString)
val result = jsonObj.getJSONObject("result")
val response = result.getJSONObject("response")
if (jsonObj is JSONArray) {
val jsonArray= response.getJSONArray("data")
val list = ArrayList<FlightShdu>()
var x = 0
while (x < jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(x)
list.add(
FlightShdu(
jsonObject.getJSONObject("identification").getJSONObject("number").getString("default"),
jsonObject.getJSONObject("airline").getString("name"),
jsonObject.getJSONObject("status").getJSONObject("generic").getJSONObject("status").getString(
"text"
),
)
)
x++
}
list.forEach(::println)
var adapter = FlightSearchAdpater(this#FlightSearch, list)
flightsearchlists.adapter = adapter
}else if(jsonObj is JSONObject){
val response = result.getJSONObject("response")
if(response.isNull("data")){
Toast.makeText(applicationContext, "Please enter currect flight number", Toast.LENGTH_SHORT).show()
}
}
}
Related
hi guys I got an error like the one below when trying to upload an image from the galley:
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{efed650 15275:app.fadlyproject.com/u0a158} (pid=15275, uid=10158) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
the error comes from this line of code:
val parcelFileDescriptor =
contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?: return
I'm using 3rd party libraries namely DrJacky and Retrofit 2. I've added some necessary things to the manifest as below:
Dependencies :
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.github.Drjacky:ImagePicker:2.3.19'
Manifest :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
image_view = findViewById(R.id.image_view)
button_upload = findViewById(R.id.button_upload)
image_view!!.setOnClickListener {
openImageChooser()
}
button_upload!!.setOnClickListener {
uploadImage()
}
}
private val profileLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
val uri = it.data?.data!!
selectedImageUri = uri
image_view!!.setImageURI(selectedImageUri)
} else parseError(it)
}
private fun openImageChooser() {
ImagePicker.with(this)
.provider(ImageProvider.BOTH)
.setDismissListener {
Log.d("ImagePicker", "onDismiss");
}
.createIntentFromDialog { profileLauncher.launch(it) }
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
REQUEST_CODE_PICK_IMAGE -> {
selectedImageUri = data?.data
image_view!!.setImageURI(selectedImageUri)
}
}
}
}
private fun uploadImage() {
if (selectedImageUri == null) {
layout_root!!.snackbar("Select an Image First")
return
}
val parcelFileDescriptor =
contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?: return
val inputStream = FileInputStream(parcelFileDescriptor.fileDescriptor)
val file = File(cacheDir, contentResolver.getFileName(selectedImageUri!!))
val outputStream = FileOutputStream(file)
inputStream.copyTo(outputStream)
progress_bar!!.progress = 0
val body = UploadRequestBody(file, "image", this)
MyAPI().uploadImage(
MultipartBody.Part.createFormData(
"file",
file.name,
body
),
RequestBody.create(MediaType.parse("multipart/form-data"), "json")
).enqueue(object : Callback<UploadResponse> {
override fun onFailure(call: Call<UploadResponse>, t: Throwable) {
layout_root!!.snackbar(t.message!!)
progress_bar!!.progress = 0
}
override fun onResponse(
call: Call<UploadResponse>,
response: Response<UploadResponse>
) {
response.body()?.let {
layout_root!!.snackbar(it.message)
progress_bar!!.progress = 100
classes!!.text = it.data.classes
layout!!.visibility = View.VISIBLE
Glide.with(this#MainActivity).load("http://167.172.72.26:1337/"+ it.data.image_after_preprocessing).into(
image_view!!
)
}
}
})
}
override fun onProgressUpdate(percentage: Int) {
progress_bar!!.progress = percentage
}
companion object {
const val REQUEST_CODE_PICK_IMAGE = 101
}
This answer is late but it might help others.
I just added .crop() to it like this.
ImagePicker.with(this)
.crop()
.provider(ImageProvider.BOTH)
.setDismissListener {
Log.d("ImagePicker", "onDismiss");
}
.createIntentFromDialog { profileLauncher.launch(it) }
I noticed that the error only persist when using the gallery and adding the .crop() is the only solution to it.
In case you don't use Crop option, you just need to add:
mGalleryUri?.let { galleryUri ->
contentResolver.takePersistableUriPermission(
galleryUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
}
https://developer.android.com/training/data-storage/shared/photopicker#persist-media-file-access
I'll change ACTION_GET_CONTENT to ACTION_OPEN_DOCUMENT on the next update.
[And if I could find a way to have both worlds(having crop and let developer use or not use takePersistableUriPermission, I'll update again.]
I have tried two different ways to access my spinner. Without success thus far.
I want to load the data for each driver as chosen.
To give an idea of my app.
Code for adapter:
class TableViewAdapter(var tripsheetlist: Tripsheetlist) : RecyclerView.Adapter<TableViewAdapter.RowViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RowViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.table_list_item, parent, false)
return RowViewHolder(itemView) }
override fun getItemCount(): Int { return tripsheetlist.videos.size + 1 // one more to add header row
}
override fun onBindViewHolder(holder: RowViewHolder, position: Int) {
val rowPos = holder.adapterPosition
if (rowPos == 0) {
// Header Cells. Main Headings appear here
holder.itemView.apply {
setHeaderBg(txtWOrder)
setHeaderBg(txtDElNote)
setHeaderBg(txtCompany)
// setHeaderBg(txtAddress)
setHeaderBg(txtWeight)
setHeaderBg(txtbutton1)
setHeaderBg(txtbutton2)
setHeaderBg(txttvdone)
txtWOrder.text = "WOrder"
txtDElNote.text = "DElNote"
txtCompany.text = "Company"
// txtAddress.text = "Address"
txtWeight.text = "Weight"
txtbutton1.text = "Delivered"
txtbutton2.text = "Exception"
txttvdone.text = ""
}
} else {
val modal = tripsheetlist.videos[rowPos -1]
holder.itemView.apply {
setContentBg(txtWOrder)
setContentBg(txtDElNote)
setContentBg(txtCompany)
setContentBg(txtWeight)
setContentBg(txtbutton1)
setContentBg(txtbutton2)
setContentBg(txttvdone)
val list : MutableList<String> = ArrayList()
list.add("Deon")
list.add("Leon")
list.add("David")
list.add("Dick")
println(list)
val spinner : Spinner = findViewById(R.id.spnDriver)
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
val item :String = list[p2]
if (item == "David")
{
txtWOrder.text = modal.WOrder.toString()
txtDElNote.text = modal.DElNote.toString()
txtCompany.text = modal.name.toString()
txtWeight.text = modal.id.toString()
}
}
override fun onNothingSelected(p0: AdapterView<*>?) {
}
}
I did it like this as a test for now. As I will get the drivers from my JSON. I don't have access to it yet so that is why the static values.
The problem I am getting now is: findViewById(R.id.spnDriver) must not be null
I first had my spinner class in my main activity and passed it over like this:
val list : MutableList<String> = ArrayList()
list.add("Deon")
list.add("Leon")
list.add("David")
list.add("Dick")
list.add("Jim")
list.add("Harry")
val adapter = ArrayAdapter( this, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, list)
val spinner: Spinner = findViewById(R.id.spnDriver)
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
val item :String = list[p2]
Toast.makeText(this#MainActivity, "Driver $item selected", Toast.LENGTH_SHORT).show()
}
override fun onNothingSelected(p0: AdapterView<*>?) {
//empty
}
// insert code that activates data pull of tripsheet for driver= actifavte by method the class/object that activates the data pull. so datapuul(Driver)
}
limitDropDownHeight(spinner)
//drivers end
val btnLoadData: Button = findViewById(R.id.btnLoadData)
// weightsum(tvTotalweight, Tripsheetlist)
// totaldelNotes(tvTotaldelv,Tripsheetlist)
// setData(btnLoadData, Tripsheetlist )
fetchJson(spinner)
}
private fun fetchJson(spinner: Spinner) {
println("Attempting to Fetch JSON")
val url = "https://api.letsbuildthatapp.com/youtube/home_feed"
val request = Request.Builder().url(url).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object: Callback {
override fun onFailure(call: Call, e: IOException) {
println("Failed to execute request") }
override fun onResponse(call: Call, response: Response) {
val body = response.body?.string()
println(body)
val gson = GsonBuilder().create()
val tripsheetlist = gson.fromJson(body, Tripsheetlist::class.java)
runOnUiThread {
recyclerViewTripsheetlist.adapter = TableViewAdapter(tripsheetlist, spinner)
}
}
})
}
In my Adapter class I then called it with : val spinner = spnDriver
This led to a different error: AppCompatSpinner.setOnItemSelectedListener(android.widget.AdapterView$OnItemSelectedListener)' on a null object reference
But seems like it passed the val spinner =spnDriver without a problem.
Thank you for all input and help.
I found a solution. What I did was to keep the spinner inside my MainActivity and then just pass the result of the spinner to the adapter - where I wanted to use it.
I am trying to convert a string to JSONArray but I am having issues.
This is my test:
class MainActivityTest {
#Test
fun checkParse(){
val loader = ClassLoader.getSystemClassLoader()
val json: String = Files.lines(
get(
loader.getResource("data.json").toURI()
)
)
.parallel()
.collect(Collectors.joining())
val main = MainActivity()
val dataParse2 = Gson().fromJson(json, JSONArray::class.java)
val gson = GsonBuilder().create()
val parse2 = gson.fromJson(json, Array<QuoteModel>::class.java).toList()
val parse1 = main.parseResponse(dataParse2)
assertEquals(parse1,parse2)
}
}
This is the function I am testing in my MainActivity:
fun parseResponse(response: JSONArray): List<QuoteModel> {
val fileData = response.toString()
val gson = GsonBuilder().create()
return gson.fromJson(fileData, Array<QuoteModel>::class.java).toList()
}
And this is my data.json file:
[
{
"text": "Genius is one percent inspiration and ninety-nine percent perspiration.",
"author": "Thomas Edison"
},
{
"text": "You can observe a lot just by watching.",
"author": "Yogi Berra"
},
{
"text": "A house divided against itself cannot stand.",
"author": "Abraham Lincoln"
}
]
the issue comes in this line from my test:
val dataParse2 = Gson().fromJson(json, JSONArray::class.java)
Any ideas?
First Update
This is the function where I call the parseFunction in MainActivity:
private fun jsonArrayRequest(url: String): JsonArrayRequest {
return JsonArrayRequest(Request.Method.GET, url, null,
{ response ->
val quotesArray = parseResponse(response)
displayQuote(chooseQuote(quotesArray))
},
{ error ->
TODO("Handle error missing")
}
)
}
private fun jsonArrayRequest(url: String): JsonArrayRequest {
return JsonArrayRequest(Request.Method.GET, url, null,
{ response ->
val responseArray = JSONArray(response)
val quotesArray = parseResponse(responseArray)
displayQuote(chooseQuote(quotesArray))
},
{ error ->
TODO("Handle error missing")
}
)
fun parseResponse(response: JSONArray): List<QuoteModel> {
return Gson().fromJson(response.toString(), Array<QuoteModel>::class.java).toList()
My current project downloading data from a server time I want to display a progress bar so the user knows what is going on. I have a simple alert dialog , l am try to add alert dialog when data json loading for user . when l launching app the alert dialog stay stick on screen even if the data loaded already and doesn't hide .
AsyncTask code :
inner class Arr : AsyncTask<String, String, String>(){
val progressDialog = AlertDialog.Builder(this#MainActivity)
val dialogView = layoutInflater.inflate(R.layout.progress_dialog,null)
val message = dialogView.findViewById<TextView>(R.id.message_id)
val dialog = progressDialog.create()
override fun onPreExecute() {
super.onPreExecute()
progressDialog.setMessage("loading")
progressDialog.setCancelable(false)
progressDialog.show()
}
// for build connection
override fun doInBackground(vararg url: String?): String{
var text : String
val connection = URL(url[0]).openConnection() as HttpURLConnection
try {
connection.connect()
text = connection.inputStream.use { it.reader().use{reader -> reader.readText()} }
} finally{
connection.disconnect()
}
return text
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
handleJson(result)
dialog.dismiss()
}
override fun onProgressUpdate(vararg text: String?) {
dialog.dismiss()
}
private fun handleJson (jsonString: String?){
dialog.dismiss()
val jsonObj = JSONObject(jsonString)
val result = jsonObj.getJSONObject("result")
val response = result.getJSONObject("response")
val airport = response.getJSONObject("airport")
val pluginData = airport.getJSONObject("pluginData")
val schedule = pluginData.getJSONObject("schedule")
val arrivals = schedule.getJSONObject("arrivals")
// val data = arrivals.getJSONObject("data")
val jsonArray = JSONArray(arrivals.get("data").toString())
val list = ArrayList<FlightShdu>()
var x = 0
while (x < jsonArray.length()){
val jsonObject = jsonArray.getJSONObject(x)
list.add(FlightShdu(
jsonObject.getJSONObject("flight").getJSONObject("identification").getJSONObject("number").getString("default"),
jsonObject.getJSONObject("flight").getJSONObject("airline").getString("name"),
jsonObject.getJSONObject("flight").getJSONObject("status").getString("text"),
jsonObject.getJSONObject("flight").getJSONObject("airline").getJSONObject("code").getString("icao"),
jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("scheduled").getString("arrival")
))
x++
}
list.forEach(::println)
val adapter = ListAdapte(this#MainActivity,list)
flight_arrivel_list.adapter = adapter
}
} //
any solution please ?
Change to this:
override fun onPreExecute() {
super.onPreExecute()
dialog.setMessage("loading")
dialog.setCancelable(false)
dialog.show()
}
and hide it with:
dialog.dismiss();
you must refer to the AlertDialog object and not the AlertDialog.Builder.
In your onPreExecute()
override fun onPreExecute() {
...
progressDialog.show()
}
But in onPostExecute() you call different dialog to dismiss
override fun onPostExecute(result: String?) {
...
dialog.dismiss()
}
So you need to call progressDialog.dismiss() in onPostExecute().
progressDialog.dismiss() instead of dialog.dismiss()
I am trying to hit api using retrofit in kotlin
This is my DoinBackGround Method
private fun doinBackground() {
Utility.printMessage("in do in background.....")
try {
val hdr = HashMap<String, String>()
hdr.put("x-csrf-token", Utility.getToken(this.context!!))
val apiInterface = ApiCallRetrofit.getClient(this.mCrypt!!)!!.create(ApiInterface::class.java)
if (what.equals(0)) {
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), getQuery(para))
print("header...")
call = apiInterface.hitApi(url, hdr, body)
} else if (what.equals(1)) {
val imgPart = ArrayList<MultipartBody.Part>()
if (files != null) {
if (files.size > 0) {
for (i in files.indices) {
imgPart.add(preparePart("image/*", "document_file[" + files.get(i).key + "]", files.get(i).file))
}
}
call = apiInterface.hitApiImage(url, hdr, getMap(para), imgPart)
}
call?.enqueue(object : Callback<StandardReposnse> {
override fun onResponse(call: Call<StandardReposnse>, response: Response<StandardReposnse>) {
try {
Utility.printMessage("messege...." + response.body().message)
val resp = Gson().toJson(response.body())
Utility.printMessage("Response :$resp")
Utility.longLogPrint(response.body().data, "Full response : ")
Utility.printMessage("Error : " + Gson().toJson(response.errorBody()))
onPostExecute(Parseresponce(response.body()))
} catch (e: Exception) {
Parseresponce(null)
e.printStackTrace()
}
}
override fun onFailure(call: Call<StandardReposnse>, t: Throwable) {
t.printStackTrace()
if (progressDialog != null) {
progressDialog?.dismiss()
}
Parseresponce(null)
}
})
}
} catch (e: Exception) {
e.printStackTrace()
}
}
And this is my interface where I am defining all the POST methods
#POST
abstract fun hitApi(#Url api: String, #HeaderMap header: Map<String, Any>, #Body body: RequestBody): Call<StandardReposnse>
#POST
fun hitApiNoHeader(#Url api: String, #Body requestBody: RequestBody): Call<StandardReposnse>
#POST
fun test(#Url api: String, #HeaderMap headerMap: Map<String, String>, #Body requestBody: RequestBody): Call<JSONObject>
#Multipart
#POST
fun hitApiImage(#Url api: String, #HeaderMap headerMap: Map<String, String>, #PartMap bodyMap: Map<String, RequestBody>, #Part images: List<MultipartBody.Part>): Call<StandardReposnse>
Whenever I am trying to hit the Api I am getting the following exception :
java.lang.IllegalArgumentException: Parameter type must not include a type variable or wildcard: java.util.Map<java.lang.String, ?> (parameter #2)
for method ApiInterface.hitApi
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:720)
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:711)
at retrofit2.ServiceMethod$Builder.parameterError(ServiceMethod.java:729)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:193)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166)
This is the line where the exception occurs in doinbackground method
call = apiInterface.hitApi(url, hdr, body)
I tried #JvmSuppressWildcards before the RequestBody but it did not work, can anyone suggest whats the actual problem over here, plus nothing is printing in the log though I have used print() function should i use LOG.d?
Here i have fully example for it.
This dependancy add in gradle
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
annotationProcessor 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
Here now create ApiClient.kt file
object ApiClient {
val BASE_URL = "http://yourwebsite/services/"
private var retrofit: Retrofit? = null
val client: Retrofit
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit!!
}
}
Now create APIInterface.kt
#FormUrlEncoded
#POST("users/login")
fun POST_LOGIN(
#Field("imei_number") imei_number: String,
#Field("device_token") device_token: String,
#Field("mobile") mobile: String,
#Field("password") password: String
): Call<LoginResponse>
#GET("general/init-data")
fun GENERAL_MODULE(
#Header("Authorization") auth_key: String
): Call<InitResponse>
#GET("event-gallery/list")
fun GET_Event_GALLERY(
#Header("Authorization") auth_key: String
): Call<EventListResponse>
#GET("event-gallery/photo-list")
fun GET_Event_GALLERY_PHOTO(
#Header("Authorization") auth_key: String,
#Query("id") id: Int
): Call<EventGallerListResponse>
if Any Header for token the use #Header and also When call #GET that time params use #Query and #Post that time #Fields
Now Response file
data class EventListResponse(
#SerializedName("success")
var success: Boolean,
#SerializedName("data")
var data: EventgalleryModel?,
#SerializedName("server_error"),
#SerializedName("eventgallery")
var eventgallery: ArrayList<EventListData>
var server_error: Boolean,
#SerializedName("message")
var message: String
)
Then create Model class of Response
Now time to Activity code
private fun loadData() {
card_progress.visibility = View.VISIBLE
val apiService = ApiClient.client.create(ApiInterface::class.java)
val call =
apiService.GET_FEE_INSTALMENT_LIST(PreferenceManager.getAuthKey(this#FeesInstalmentActivity)!!)
call.enqueue(object : Callback<FeeInstalmentListResponse> {
override fun onResponse(
call: Call<FeeInstalmentListResponse>,
response: Response<FeeInstalmentListResponse>
) {
card_progress.visibility = View.GONE
val data = response.body()!!.data
if (response.code() == 200 && data != null) {
if (response.body()!!.server_error) {
txt_no_data_fee.visibility = View.VISIBLE
txt_no_data_fee.text = response.body()!!.message
} else {
Log.e("data", data.toString())
if (data != null && data.feesinstalment.isEmpty()) {
txt_no_data_fee.visibility = View.VISIBLE
} else {
txt_no_data_fee.visibility = View.GONE
adapter!!.setItem(data.feesinstalment)
}
}
} else if (response.code() == 401) {
PreferenceManager.removePref(this#FeesInstalmentActivity)
startActivity(
Intent(this#FeesInstalmentActivity, LoginActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
)
finish()
} else {
Toast.makeText(
this#FeesInstalmentActivity,
R.string.somethingWrong,
Toast.LENGTH_SHORT
).show()
}
}
override fun onFailure(call: Call<FeeInstalmentListResponse>, t: Throwable) {
card_progress.visibility = View.GONE
Log.e("onFailure", t.message)
txt_no_data_fee.visibility = View.VISIBLE
}
})
}
Adapter
class FeeInstalmentAdapter(
private val context: Context,
private var items: ArrayList<FeeInstalmentListData>
) : RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.row_fees_instalment_item, parent, false))
}
#SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.due_date.text = DateHelper.parseData(items[position].due_date!!, "yyyy-MM-dd", "dd MMM yyyy")
holder.instalment_title.text = items[position].instalment_title
if (items[position].paid_date == null) {
holder.paid_text.visibility = View.GONE
holder.paid_date.text = context.resources.getString(R.string.UnPaid)
holder.paid_date.setTextColor(Color.parseColor("#DC143C"))
} else {
holder.paid_date.text = DateHelper.parseData(items[position].due_date!!, "yyyy-MM-dd", "dd MMM yyyy")
holder.paid_date.setTextColor(Color.parseColor("#58A259"))
}
//holder.paid_date.text = items[position].paid_date
holder.amount.text = "Rs. " + items[position].amount
holder.amount.setTextColor(Color.parseColor("#ED7136"))
}
override fun getItemCount(): Int {
return items.size
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
fun setItem(holidays: ArrayList<FeeInstalmentListData>) {
items = holidays
notifyDataSetChanged()
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val due_date = view.due_date
val instalment_title = view.instalment_title
val paid_date = view.paid_date
val amount = view.amount
val paid_text = view.paidText
}
}
You have used:
#POST
abstract fun hitApi(#Url api: String, #HeaderMap header: Map<String, Any>, #Body body: RequestBody): Call<StandardReposnse>
And exception is:
Parameter type must not include a type variable or wildcard: java.util.Map<java.lang.String, ?> (parameter #2)
And your hitApi #2 param use wildcard actually:
#HeaderMap header: Map<String, ?>
Try to specify argument (just change Any to String). Anyway you are not probably going to put Any object than String in your request header.
Call it in the below mentioned way.
val callWeather = NetworkUtils.getApiInterface().getWeatherResponse("03a7949903004a0bb2590633181104", "1.909,45.909", 7)
callWeather.enqueue(object : Callback<APIXUResponse> {
override fun onResponse(call: Call<APIXUResponse>, response: Response<APIXUResponse>) {
var api :APIXUResponse? = response.body()
}
override fun onFailure(call: Call<APIXUResponse>, t: Throwable) {
}
})