I am new to kotlin / android development, I have been following the google / android docs with using Volley to send requests....Still have not go to handling JSON yet.
When I put the example GET in a function in kotlin using android development studio, I am getting the error message from ErrorListener
val textView = findViewById<TextView>(R.id.textReturn)
val url = "http://wwww.google.com"
val queue = Volley.newRequestQueue(this)
val stringRequest =
StringRequest(Request.Method.GET, url, Response.Listener<String> { response ->
var strRes = response.toString()
textView.text = strRes
}, Response.ErrorListener {textView.text = "That didn't work!"})
queue.add(stringRequest)
}
I am unsure on how to debug and come from a very javascript / php background where console.log() or print() will post to the console, kotlin does not seem to have such a simple function for this.
Not exactly certain about Volley, but eg. with Retrofit, the error listener will only be triggered on hard errors - but common HTTP status codes, besides 200 OK, end up in the response listener. Retrofit with GsonConverter and ORM is the most common combo for converting JSON to POJO (one can define a whole API as a web-service and it converts the JSON automatically). However, when still learning Java/Kotlin, it might not hurt to use Volley and not use ORM auto-mapping (because all the nuts & bolts are being abstracted away). PHP background is useful for whatever API interaction.
And concerning the actual question, in Kotlin one can log with: println and Android Studio can be used for the actual debugging (it provides similar functionality alike F12 tools and xdebug provide). Using logging to debug is only partially applicable, eg. when wanting to let the console tell the story of what happened - otherwise, just use break-points, watches or evaluate expressions.
Related
I call a Rest API of salesforce by post method:
url = "https://test-dev-ed.my.salesforce.com/services/apexrest/AccountUsers/"
client = OkHttpClient()
val jsonIn = FormBody.Builder()
.add("email",URLEncoder.encode("dt1#gmail.com", "UTF-8"))
.add("password", URLEncoder.encode("1","UTF-8"))
.build()
request = Request.Builder()
.post(jsonIn)
.header("Authorization", "Bearer "+accesstoken)
.addHeader("Content-Type","application/x-www-form-urlencoded")
.url(url)
.build()
response = client.newCall(request).execute()
This is rest api:
#HttpPost
global static ID createUser(String email, String password) {
AccountUser__c us=new AccountUser__c();
us.Email__c=email;
us.Password__c=password;
us.Status__c=0;
insert us;
return us.Id;
}
But result return is error:
[{"errorCode":"UNSUPPORTED_MEDIA_TYPE","message":"Content-Type header specified in HTTP request is not supported: application/x-www-form-urlencoded"}]
I had try change application/json to application/x-www-form-urlencoded , but still can't resolve.
I try call a Get method, it is ok.
Why Post method occur error [Content-Type header specified in HTTP request is not supported]?
I would like to suggest a better resolution. Retrofit Library
Even though it is not mandatory to use Retrofit, these are few eye catchy aspects which makes it reliable and handy in similar use case of yours.
Why to use Retrofit?
Type-safe REST Adapter that makes common networking tasks easy
For POST operations, retrofit helps in assembling what needed to be submitted. Eg:- Generating URL encoded form.
Takes care of URL manipulation, requesting, loading, caching, threading, synchronization, sync/async calls
Helps to generate URL using type-aware generated code tied to specific REST API
Parsing JSON using GSON
Retrofit is an API adapter wrapped over OkHttp
The problem that you are facing can be resolved using retrofit like this.
public interface APIConfiguration{
#Headers({"Accept:application/json",
"Content-Type:application/x-www-form-urlencoded"})
#FormUrlEncoded
#POST("user/registration")
Observable<DataPojo> registrationAPI(#FieldMap(encoded = true) Map<String, String> params);
}
That's it, with few annotation the library takes care of Form URL
Encoding and related dependencies.
As it is inappropriate to start from corresponding Retrofit dependencies and sample code, you can go through Reference One and Reference Two for more details.
As per my understanding just checkout the difference the content type header "application/x-www-form-urlencoded" is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type "multipart/form-data" should be used for submitting forms that contain files, non-ASCII data, and binary data.
The content "multipart/form-data" follows the rules of all multipart MIME data streams.
https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
Also try your http request by setting your content type header as multipart/formdata.
I am not able to view detailed URL Patterns in Firebase Performance Monitoring even after the API having >30k samples in the past few months.
It just shows the root API domain like this:
api.myAppName.in/**
instead of something like
api.myAppName.in/app/v3/user/*/profile/
The console just shows a label "uncategorized" on the API with this message if you hover it
Detailed URL patterns from api.myAppName.in will appear as we collect
a larger number of samples. Allow for up to 24 hours after collection.
But as mentioned earlier, it's been a few months and more than 30k samples.
I'm using retrofit, if that helps.
I have contacted Firebase support and their answer was:
...
As mentioned here, while Performance Monitoring reports most network requests for your app, some might not be reported. Hence, it is recommended to add monitoring for specific requests in your app.
In order for a request to be reported to the Performance Monitoring console, any trace that is start using the trace.start() must also be
stopped by calling the trace.stop() method. Traces that are never
stopped, are never reported.
Wildcarding is only based on path segment and not query strings. Query strings are ignored for purpose of aggregation in the dashboard.
For a domain a.b.c, it's path a.b.c/d/ should have been requested from several dozen unique devices in order for the path a.b.c/d/ to
appear separately in the dashboard, in the time frame of your selected
filter.
Known Issues with Performance Monitoring.
For the 4th point that I mentioned above, there is also one thing to
keep in mind. Let's say N is the definite numerical value representing
the "several dozen" threshold that I mentioned earlier. And, we are
monitoring the following 3 different path segments:
1. www.something.com/a/
2. www.something.com/b/
3. www.something.com/c/
Within a given time-frame, if all 3 of the paths above received N-1
hits. That is, not meeting the threshold requirement. While the number
of hits might appear to be almost 3 times of N when seen against
www.something.com collectively(as that is what the dashboard will
show), the individual hits for each path did not meet the threshold in
the given time frame and hence, only the aggregated number statistics
are shown.
...
The code that I used to intercept the retrofit request and monitor the request time is: (I removed the query params data for security)
val builder = OkHttpClient.Builder()
.addInterceptor(FirebasePerformanceInterceptor(FirebasePerformance.getInstance()))
.build()
// Adapted from: http://qaru.site/questions/15007824/how-can-i-get-the-url-and-method-of-retrofit-request-on-onsubscribe-of-rxjava-2-custom-operator
class FirebasePerformanceInterceptor(private val performanceInstance: FirebasePerformance) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
//Get request values
val url = request.url().url()
val urlPath = getUrlWithoutQuery(url)
val requestPayloadSize = request.body()?.contentLength() ?: 0L
val httpMethod = request.method()
//Initialize http trace
val trace = performanceInstance.newHttpMetric(urlPath, httpMethod)
trace.setRequestPayloadSize(requestPayloadSize)
trace.start()
//Proceed
val response = chain.proceed(chain.request())
//Get response values
val responseCode = response.code()
//Add response values to trace and close it
trace.setHttpResponseCode(responseCode)
trace.stop()
return response
}
}
private fun getUrlWithoutQuery(url: URL): URL {
val uri = URI(url.protocol, url.host, url.path, null)
return uri.toURL()
}
To test if it's logging correctedly: Follow this Debugging tutorial:
You will see something like:
10-24 19:48:21.162 23037 24411 I FirebasePerformance: Logging NetworkRequestMetric - https://your-api-domain.com/cart 0b 147809ms,
Firebase Performance Monitoring now supports creating custom URL patterns that allow you to target more specific URLs. From the docs:
You can create custom URL patterns to monitor specific URL patterns that Firebase isn't capturing with its derived automatic URL pattern matching. For example, you can use a custom URL pattern to troubleshoot a specific URL or to monitor a specific set of URLs over time.
So if you did want to capture something like api.myAppName.in/app/v3/user/*/profile/**, you would now be able to 😃
See the docs for more details.
I have searched extensively on SO and issues list here but could not find an optimal solution to the issue (This came close however: RETROFIT how to parse this response.).
Can someone help me out? Here is the gist:
https://gist.github.com/Sheshlok/f8ee09a6760f6aa3b05ad9c03d6b247b
Issue: The second API returns a malformed JSON response, specifically, one that is wrapped in finance_charts_json_callback(.....). I tried implementing a custom GSON converter as you can see in the gist above but keep getting the same error
([#Observable#getStockHistory -> onError() -> 'Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $'])
Note:
Have checked JsonpParser with the actual API response and it works fine.
I can solve this problem by using OkHttp class 'onResponse'
callback, and trimming the response string appropriately before
parsing JSON. However, I needed to use Observables.
I have a node.js application with an Angular Webfrontend and an Android App connecting to the backend via rest. Now I'm not sure how to return objects from node to the clients:
Way 1:
res.send(req.user);
If I'll do it like this I can load the user object from angular like:
return $http.post('/api/login', user)
.success(function (data) {
$rootScope.currentUser = data;
and in my Android app (simplyfied call, I use Spring and Gson):
user = SpringRestTemplate.getRestTemplate().postForObject(Routes.getLogin(), user, User.class);
This works fine, but what I actually would like to return from node would be my
Way 2:
res.send({user: req.user });
for angular everything pretty much stays the same:
$rootScope.currentUser = data.user;
but for android I didn't found any other way than to write the json conversion myself:
ResponseEntity<Map> map = SpringRestTemplate.getRestTemplate().postForEntity(Routes.getLogin(), dUser, Map.class);
LinkedTreeMap<String, User> map2 = (LinkedTreeMap<String, User>) map.getBody();
Map ltm = (Map) map.get("user");
String id = (String) ltm.get("_id");
String userName = (String) ltm.get("userName");
// ... and so on
I get, why this is the case (except why I had to use a second map), but I wonder if there's any simplier way to achieve my second way.
I left the Models and the SpringRestTemplate Code out, since this is more a general question on how to handle JSON with the following structure:
{ user : { _id: "1", userName: "foo", ...}}
Any guidance on how to deal with this problem would be much appreciated!
This is simplified, but this will solve your issue.
Create a POJO that matches the JSON Schema using Json Schema to POJO
If you can, use Retrofit or something more easily suited for Android to consume the API.
Create a retrofit service (look at the retrofit link above) and then connect to the API and you'll have a User object.
Option B:
Use GSON to deserialize your object into a POJO from your spring stuff. But I recommend using Retrofit or something similar as its easier and cleaner.
I am making an API call to a web service from the android application the problem is that it returns around 22000 records, I am loading this into an array after i convert each record into an object then assign that Array to a ListView. What is the fastest/best way to fetch this data from the web service? (buffer) ? and what are the best practices for this type of issues.
I would recommend using a library to handle your data call...
Please try using Android Query; specifically, see the section entitled Asynchronous Network.
This AQuery library (AndroidQuery) is lightweight, and requires only 1 jar SMALL jar file. It can be used with Maven or Gradle Android projects as well. It allows you to EASILY fetch XML or JSON data from a remote server in either asynchronous or synchronous fashion. I have used it many times with a JSON back-end, and it is a real timesaver.
This library also allows you to specify a ProgressBar that will automatically appear and disappear during the network download process.
Here is an example of an HTTP call to a JSON back-end, asynchronously:
public void asyncJson(){
//perform a Google search in just a few lines of code
String url = "http://www.google.com/uds/GnewsSearch?q=Obama&v=1.0";
aq.ajax(url, JSONObject.class, this, "jsonCallback");
}
public void jsonCallback(String url, JSONObject json, AjaxStatus status) {
if(json != null) {
//successful ajax call
} else {
//ajax error
}
}
AQuery can also simplify other aspects of Android programming (such as eliminating the findViewById() calls for many scenarios).