Eu tenho um JSONObject
que estou usando para criar uma tabela. Porém, quando uso as teclas uma segunda vez para criar cada uma das células, nada acontece. Incluí instruções de log para testar isso. Nenhum key
s singular é impresso. Me chame de perplexo.
class MovieFragment : Fragment(), FinraDataInterface {
private lateinit var binding: MovieFragmentBinding
val finraDataInterface: FinraDataInterface = this
override fun drawTable(jsonArrayData: JSONArray) {
// ------ Draw the table -----
// Draw the keys first
val headerRow = TableRow(requireActivity())
Log.d("jsonArray", jsonArrayData[0].toString())
val firstRecord = jsonArrayData[0] as JSONObject
val keys = firstRecord.keys()
for (key in keys) {
val textView = TextView(requireActivity())
textView.text = key
headerRow.addView(textView)
}
binding.table.addView(headerRow)
// Draw the data second
for (i in 0 until jsonArrayData.length()) {
val record = jsonArrayData[i] as JSONObject
Log.d("Record", record.toString())
val tableRow = TableRow(requireActivity())
Log.d("Table Row", "Table Row created")
Log.d("Keys", listOf(keys).toString())
// Error is right here.
for (key in keys) {
Log.d("key", key)
val textView = TextView(requireActivity())
val cellText = record[key] as String
textView.text = cellText
tableRow.addView(textView)
}
binding.table.addView(tableRow)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = MovieFragmentBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
finraGetBondInfo("AMC")
}
private fun finraGetBondInfo(companyName: String) {
val url = "https://www.finra.org/finra-data/fixed-income/corp-and-agency"
val queue = Volley.newRequestQueue(requireActivity())
var cfruid = ""
val stringRequest = object: StringRequest(Request.Method.GET, url,
{ response ->
Log.d("A", "Response is: " + response.substring(0,500))
},
{ error ->
Log.e("Error", error.toString())
})
{
override fun parseNetworkResponse(response : NetworkResponse) : Response<String> {
// since we don't know which of the two underlying network vehicles
// will Volley use, we have to handle and store session cookies manually
Log.i("response", response.headers.toString());
val cookies = HttpCookie.parse(response.headers?.get("Set-Cookie"))
Log.d("Cookies:", cookies[0].toString())
val indexOfEqualSign = cookies[0].toString().indexOf('=')
cfruid = cookies[0].toString().substring(indexOfEqualSign + 1)
Log.d("Cfruid:", cfruid)
return super.parseNetworkResponse(response)
}
}
queue.add(stringRequest)
// Create our JSON Object for the finra call
val json = JSONObject()
val fieldsArray = JSONArray()
fieldsArray.put("issueSymbolIdentifier")
fieldsArray.put("issuerName")
fieldsArray.put("isCallable")
fieldsArray.put("productSubTypeCode")
fieldsArray.put("couponRate")
fieldsArray.put("maturityDate")
fieldsArray.put("industryGroup")
fieldsArray.put("moodysRating")
fieldsArray.put("standardAndPoorsRating")
fieldsArray.put("lastSalePrice")
fieldsArray.put("lastSaleYield")
json.put("fields", fieldsArray)
json.put("dateRangeFilters", JSONArray())
json.put("domainFilters", JSONArray())
json.put("compareFilters", JSONArray())
val multiJson = JSONObject()
multiJson.put("fuzzy", false)
multiJson.put("searchValue", companyName)
multiJson.put("synonym", true)
val subfieldsJson = JSONObject()
subfieldsJson.put("name", "issuerName")
subfieldsJson.put("boost", 1)
val fieldsArray2 = JSONArray()
fieldsArray2.put(subfieldsJson)
multiJson.put("fields", fieldsArray2)
val multiArray = JSONArray()
multiArray.put(multiJson)
json.put("multiFieldMatchFilters", multiArray)
json.put("orFilters", JSONArray())
json.put("aggregationFilter", JSONObject.NULL)
val sortFieldsArray = JSONArray()
sortFieldsArray.put("+issuerName")
json.put("sortFields", sortFieldsArray)
json.put("limit", 50)
json.put("offset", 0)
json.put("delimiter", JSONObject.NULL)
json.put("quoteValues", false)
Log.d("JSON", json.toString())
val url2 = "https://services-dynarep.ddwa.finra.org/public/reporting/v2/data/group/FixedIncomeMarket/name/CorporateAndAgencySecurities"
val request2 = object: JsonObjectRequest(Request.Method.POST, url2, json,
{ response ->
// TODO replace this with our calls to make tab2 display bond data
val returnBody = response["returnBody"] as JSONObject
var stringData = returnBody["data"] as String
stringData = stringData.replace("\\n", "").replace("\\", "")
val jsonArrayData = JSONArray(stringData)
finraDataInterface.drawTable(jsonArrayData)
},
{ error ->
Log.e("Error", error.toString())
})
{
override fun getHeaders(): MutableMap<String, String> {
val headers = HashMap<String, String>()
headers["Authority"] = "services-dynarep.ddwa.finra.org"
headers["Accept"] = "application/json, text/plain, */*"
headers["Cookie"] = "XSRF-TOKEN=$cfruid;"
headers["Origin"] = "https://www.finra.org"
headers["Referer"] = "https://www.finra.org/"
headers["X-XSRF-token"] = cfruid
headers["user-agent"] = "python-requests/2.31.0"
Log.d("headers:", headers.toString())
return headers
}
override fun getBodyContentType(): String {
return "application/json"
}
}
queue.add(request2)
}
}
O que me deixou particularmente confuso é que o primeiro loop for de uso das teclas para criar a linha do cabeçalho funciona bem. Tentei transmitir coisas para tipos diferentes para ver se era algum erro de tipo. No entanto, é apenas o segundo loop for que não está em execução. Não recebo nenhuma mensagem de erro. o que estou perdendo? Obrigado.
Supondo que você use a biblioteca
JSON-java
(org.json
) aqui, observe queJSONObject.keys()
o método retorna umaIterator
chave over. Iterador é diferente deIterable
coleções ou - é uma iteração "ao vivo" sobre alguns dados e pode ser consumido apenas uma vez. Depois de consumirmos todos os itens, o iterador fica constantemente no final dos dados e não fornece nenhum item adicional.É fácil ignorar isso, pois a maioria das bibliotecas não fornece iteradores, mas sim iteráveis que podem ser consumidos várias vezes.
Para corrigir o problema, precisamos criar outro iterador usando
keys()
ou podemos usarkeySet()
, que retorna um conjunto, para que possa ser iterado várias vezes. SekeySet()
não estiver disponível, podemos converter um iterador em uma lista com:asSequence().toList()
.