I'm attempting to make an API call then use it's response as a string. Thus far I am able to successfully get and log the response... however the string I'm attempting to create using the response is empty and I'm unsure why this might be happening.
Any suggestions are appreciated:
api.getUser().enqueue(new API.SimpleCallback<ResponseBody>() {
#Override
public void onResponse(ResponseBody data) {
try {
Log.d("RAW BODY", data.string());
final SharedPreferences.Editor editor = App.sharedPrefs.edit();
String responseString = data.string().toString();
editor.putString(NOTIFICATION_PREFERENCES_ENABLED_STATUS,responseString);
editor.apply();
} catch (IOException e) {
e.printStackTrace();
}
}
});
The response body can be consumed only once. https://square.github.io/okhttp/3.x/okhttp/okhttp3/ResponseBody.html
In your code, you are attempting to consume the body multiple times. (once when you log it, and another time when you try to put it in the shared preferences).
Instead do something like:
#Override
public void onResponse(ResponseBody responseBody) {
String data = responseBody.string();
Log.d("RAW_DATA", data);
sharedPreferences.edit().putString(myKey, data);
}
Related
I am working on a project right now where I use jsoup in a class with the function retrieveMedia in order to return an ArrayList filled with data from the webpage. I run it in a thread since you shouldn't be connecting to URLs from the main thread. I run it and join it. However, it doesn't work (I tested the same code in Eclipse separate from Android Studio and it worked fine). It seems that no matter what I do I can't get jsoup to connect to the webpage. Below is my class MediaRetriever.
public class MediaRetreiever {
public ArrayList<Media> retrieveMedia() {
ArrayList<Media> mediaOutput = new ArrayList<Media>(); //Store each scraped post
Thread downloadThread = new Thread(new Runnable() {
public void run() {
Document doc = null;
try {
doc = Jsoup.connect(<Website Im connecting to>).timeout(20000).get();
} catch (IOException e) {
System.out.println("Failed to connect to webpage.");
mediaOutput.add(new Media("Failed to connect", "oops", "", "oh well"));
return;
}
Elements mediaFeed = doc.getElementById("main").getElementsByClass("node");
for (Element e : mediaFeed) {
String title, author, imageUrl, content;
title=e.getElementsByClass("title").text().trim();
author=e.getElementsByClass("content").tagName("p").select("em").text().trim();
content=e.getElementsByClass("content").text().replace(author,"").trim();
Media media = new Media(title, author, "", content);
mediaOutput.add(media);
}
}
});
downloadThread.start();
try {
downloadThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return mediaOutput;
}
}
Running this class's method from another class and it doesn't ever connect. Any ideas?
Since you say that the problem persists only in Android, it looks like that you should add the user agent string to your request - first get the user agent string of a browser that displays correctly the site, and then add it to the request:
doc = Jsoup.connect(<Website Im connecting to>)
.userAgent("your-user-agent-string")
.timeout(20000).get();
And as a sidenote - if you are catching exception, don't print your own error message - print the original message, it may be very useful.
There is an implemented method of the AbstractRegueestLoggingFilter class called afterRegueest. It has two parameters: HttpServletRequest request, String message. For some reason, the message parameter comes incomplete, that is, cut off (there is a feeling that this message has a dimension, as is often the case with the size of varhar in the database). I don't understand how this can happen.
P.S. the message should display the information on the request that the client asks for. For example Put: /api/url and further the request body. I use it for logging.
So the body itself is cut off, and already at the input in the parameter.
How can I fix this problem?
#Override
#SuppressWarnings("NullableProblems")
protected void afterRequest(HttpServletRequest request, String message) { // Here it is already incomplete !!!!!
if (!FORBIDDEN_URLS.contains(request.getRequestURI())) {
ApiRequestLog log = new ApiRequestLog();
log.setMethod(RequestMethod.valueOf(request.getMethod()).name());
log.setUrl(request.getRequestURL().toString());
log.setParams(request.getQueryString());
String body = StringUtils.substringAfter(message, "payload=");
if (StringUtils.isNotBlank(body)) {
log.setBody(body);
}
try {
log.setCreatedBy(UserHelper.getUser());
} catch (RuntimeException ignored) {
}
try {
queueService.sendToQueue(log, REQUESTS_FOR_SAVE);
} catch (JMSException ignored) {
}
}
}
The problem was that we manually wrote into the code the maximum length of the request body that we could accept. In this regard, I just changed the maximum number of characters to a larger value.
#Autowired
public CustomLoggingFilter(QueueService queueService) {
setIncludePayload(true);
setMaxPayloadLength(2048);
setBeforeMessagePrefix("");
setBeforeMessageSuffix("");
setAfterMessagePrefix("");
setAfterMessageSuffix("");
this.queueService = queueService;
}
I change setMaxPayloadLength(2048) on 1million length value.
I have a code in my android app:
homes=Get_HomeList(this, progressBar, view, mMap,MapsActivity.this);
Log.v(TAG, "onMapReady: "+homes.size());
Get_HomeList is a function that fetches data from back end using asynchronous okhhttp call.
Inside this function I have onsuccessful method that is the place I have access to list of homes that has just been fetched.
However I need homes list outside of this function. but this line
Log.v(TAG, "onMapReady: "+homes.size());
gives me null for homes; I guess it is because it is running in parallel thread that has not seen home results yet.
Now my question is that how can handle this and be able to see fetched data outside Get_HomList function? Inside this function it looks like this:
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try {
String responsedata = response.body().string();
homes= extractHomesUpdateMap(responsedata,mMap,mapsActivity);
} catch (IOException e) {
e.printStackTrace();
}
} else {
}
Is there a way that when loading is successful and finished I can pass the results outside of Get_HomeList?Or in General how we can deal with this cases?
I have an Android application and right now I am managing error and success messages in strings.xml resource file. Now in case if I want to change these messages I need to make changes in strings.xml file and give an app update in play-store, which is a bit overhead. Instead, I want these messages to be managed from server side (back-end) so that they can be changed without any update. Can anyone please suggest me the best way to achieve this.
If you are use Volley then this is helpfil for you
VolleyError is really just an extended Exception, so Exception.getMessage() likely wouldn't return what you are looking for unless you override the parsing methods for parsing your VolleyError in your extended Request class. A really basic way to handle this would be to do something like:
//In your extended request class
#Override
protected VolleyError parseNetworkError(VolleyError volleyError){
if(volleyError.networkResponse != null && volleyError.networkResponse.data != null){
VolleyError error = new VolleyError(new String(volleyError.networkResponse.data));
volleyError = error;
}
return volleyError;
}
}
If you add this to your extended Request classes, your getMessage() should at least not return null. I normally don't really bother with this, though, since it's easy enough to do it all from within your onErrorResponse(VolleyError e) method.
You should use a JSON library to simplify things -- I use Gson for example or you could use Apache's JSONObjects which shouldn't require an additional external library. The first step is to get the response JSON sent from your server as a String (in a similar fashion to what I just demonstrated), next you can optionally convert it to a JSONObject (using either apache's JSONObjects and JsonArrays, or another library of your choice) or just parse the String yourself. After that, you just have to display the Toast.
Here's some example code to get you started:
public void onErrorResponse(VolleyError error) {
String json = null;
NetworkResponse response = error.networkResponse;
if(response != null && response.data != null){
switch(response.statusCode){
case 400:
json = new String(response.data);
json = trimMessage(json, "message");
if(json != null) displayMessage(json);
break;
}
//Additional cases
}
}
public String trimMessage(String json, String key){
String trimmedString = null;
try{
JSONObject obj = new JSONObject(json);
trimmedString = obj.getString(key);
} catch(JSONException e){
e.printStackTrace();
return null;
}
return trimmedString;
}
//Somewhere that has access to a context
public void displayMessage(String toastString){
Toast.makeText(context, toastString, Toast.LENGTH_LONG).show();
}
I am using OkHttp 3.1.2.
I've created file upload similar to the original recipe which is found here: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PostMultipart.java
I can't find example how to abort an upload of large file upon user request. I mean not how to get the user request but how to tell the OkHttp to stop sending data.
So far the only solution that I can imagine is to use custom RequestBody, add an abort() method and override the writeTo() method like this:
public void abort() {
aborted = true;
}
#Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(mFile);
long transferred = 0;
long read;
while (!aborted && (read = source.read(sink.buffer(), SEGMENT_SIZE)) != -1) {
transferred += read;
sink.flush();
mListener.transferredSoFar(transferred);
}
} finally {
Util.closeQuietly(source);
}
}
Is there any other way?
It turns out it is quite easy:
Just hold reference to the Call object and cancel it when needed like this:
private Call mCall;
private void executeRequest (Request request) {
mCall = mOkHttpClient.newCall(request);
try {
Response response = mCall.execute();
...
} catch (IOException e) {
if (!mCall.isCanceled()) {
mLogger.error("Error uploading file: {}", e);
uploadFailed(); // notify whoever is needed
}
}
}
public void abortUpload() {
if (mCall != null) {
mCall.cancel();
}
}
Please note that when you cancel the Call while uploading an IOException will be thrown so you have to check in the catch if it is cancelled (as shown above) otherwise you will have false positive for error.
I think the same approach can be used for aborting download of large files.