OkHttp Async call returning JsonArray Null - java

I declared a global JSONArray variable to return in okHttpCallback function but it returns null. I am getting data,But while returning it is null
JSONArray jsonArray; //Global in class
public JSONArray getJsonString(String link){
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
if(response.isSuccessful()){
try {
jsonArray = new JSONArray(response.body().string());
}catch (JSONException e){
e.printStackTrace();
}
}else{
Log.d("ERROR", "onResponse: ERROR" + response.body().string());
}
}
});
return jsonArray; // Null Here
}

Actually the network call is taking place in another thread and you are returning jsonArray in main thread. You should return jsonArray only when you get response through okhttp.
You should do as follows :-
public void getJsonResponse(String link){
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
if(response.isSuccessful()){
try {
jsonArray = new JSONArray(response.body().string());
getJsonString(jsonArray);
}catch (JSONException e){
e.printStackTrace();
}
}else{
Log.d("ERROR", "onResponse: ERROR" + response.body().string());
}
}
});
}
// somewhere in class
public JSONArray getJsonString(JSONArray jsonArr)
{
return jsonArr;
}

Related

Variable set value in runnable()

Im having a problem where I cant set the value for a variable inside a runnable(). I declare the variable idPeople, and then set the value in the following code
public void searchPeople(){
final String help = etCast.getText().toString();
request = new Request.Builder()
.url("https://api.themoviedb.org/3/search/person?query=" + help + "&api_key=66183feb7d9585664541910fce65bde5")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
final String myResponse = response.body().string(); //string da resposta do site
DiscoverActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
try {
JSONObject json = new JSONObject(myResponse);
JSONArray results = json.getJSONArray("results"); //procura parametro results
idPeople = results.getJSONObject(0).getString("id");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
}
but the value sticks with null. Any suggestions?

Android, Volley Request, the response is blocking main thread

Something bad is happening when using Volley to treat a large response:
String url = AppHelper.DOMAIN + "/service/pages/profile_update.json";
this.infoTextView.setText(getString(R.string.profile_info_updating));
final StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject json = new JSONObject(response);
if (json.getBoolean("success")) {
// manage JSON object here
} else {
Toast.makeText(ProfileActivity.this,
getString(R.string.connection_problem_server),
Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
ProfileActivity.this.infoTextView.setText(
getString(R.string.profile_info_updating_error));
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
ProfileActivity.this.infoTextView.setText(
getString(R.string.profile_info_updating_error));
if (error.networkResponse != null && error.networkResponse.statusCode == 401) {
Toast.makeText(ProfileActivity.this,
getString(R.string.connection_problem_permission),
Toast.LENGTH_LONG).show();
}
new android.os.Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (ProfileActivity.this.swipeRefreshLayout != null) {
ProfileActivity.this.swipeRefreshLayout.setRefreshing(false);
}
}
}, 1000);
error.printStackTrace();
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("auth_token", ProfileActivity.this.defaultUser.getAuthenticationToken());
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.putAll(super.getHeaders());
params.put("Accept-Encoding", "gzip,deflate");
return params;
}
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
StringBuilder output = new StringBuilder();
try {
GZIPInputStream gStream = new GZIPInputStream(new ByteArrayInputStream(response.data));
InputStreamReader reader = new InputStreamReader(gStream);
BufferedReader in = new BufferedReader(reader, 16384);
String read;
while ((read = in.readLine()) != null) {
output.append(read).append("\n");
}
reader.close();
in.close();
gStream.close();
} catch (IOException error) {
error.printStackTrace();
return Response.error(new ParseError());
}
return Response.success(output.toString(), HttpHeaderParser.parseCacheHeaders(response));
}
};
stringRequest.setRetryPolicy(new RetryPolicy() {
#Override
public int getCurrentTimeout() {
// 40 seconds
return 40000;
}
#Override
public int getCurrentRetryCount() {
return DefaultRetryPolicy.DEFAULT_MAX_RETRIES;
}
#Override
public void retry(VolleyError error) throws VolleyError {
throw error;
}
});
Volley.newRequestQueue(this).add(stringRequest);
this code block the main thread, freezing the application.
Additionally, I set some header values to allow gzip response and a code to handle the data. But it is not the piece that make the undesired behavior. The application freeze only when onResponse(String response) starts.
What can I do to avoid this?
onResponse and onErrorResponse is called on UI thread hence any heavy operation done inside these methods will make you application less responsive. I guess you are trying to parse the response in onResponse() which is incorrect.
You have to move to parsing logic to parseNetworkResponse since this
is the method which is called in background thread. Refer the below link for more details :
https://developer.android.com/training/volley/request-custom.html
If it help someone , try to create a new thread in a method inside onResponse , inside that thread execute your parsing data. I hope the answer works for you

Sending POST Request and Receive Json Responds using Retrofit Unable to use Responds data I need to pass it to another activity

I am using Retrofit for sending POST request.Server return's a JSON Response and i am able to parse the response in the callback method. I need to pass the data from server to another activity. But i can't use the response data outside.
api.LoginUser(
Email.getText().toString(), // passing value to interface of retrofit
Password.getText().toString(),
new Callback<Response>() {
#Override
public void success(Response result, Response response) {
BufferedReader reader = null;
String output = "";
try {
reader = new BufferedReader(new InputStreamReader(result.getBody().in()));
output = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
//Json PArsing
try {
JSONObject mainObject = new JSONObject(output);
JSONObject dataObj = mainObject.getJSONObject("data");
String id = dataObj.getString("id");
String name = dataObj.getString("name");
n=name;
Log.d("jsontext", n); //This works
}
catch(JSONException e)
{
e.printStackTrace();
}
Toast.makeText(MainActivity.this, output, Toast.LENGTH_LONG).show();
}
#Override
public void failure(RetrofitError error) {
//If any error occured displaying the error as toast
Toast.makeText(MainActivity.this, error.toString(), Toast.LENGTH_LONG).show();
}
}
);
I can't use this when it executes App crashes.its ok now there is no value in the variable.how to get values out of the callback Responds OnSuccess method???
Log.d("outer",n);
Intent dash = new Intent(this,Dashboard.class);
dash.putExtra("Value",fi);
startActivity(dash);
}
You can create an object and implement Serializable:
class User implements Serializable {
...
}
Then put object User to bundle, add to intent:
Bundle bundle = new Bundle();
bundle.putSerializable("data", user);
Intent intent = new Intent(this, YourClass.class);
intent.putExtras(bundle);
startActivity(intent);
Hope it help you.
Hold all data in a string and using intent app another activity and parse it;
You can do it as follows
public void onSuccess(int statusCode, Header[] headers,
byte[] response) {
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(new ByteArrayInputStream(
response)));
String st = "";
String st1 = "";
while ((st = br.readLine()) != null) {
st1 = st1 + st;
}
showStoreData(st1);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onFailure(int statusCode, Header[] headers,
byte[] errorResponse, Throwable e) {
// called when response HTTP status is "4XX" (eg. 401, 403, 404)
Log.e("FAIL", "FAIl" + statusCode);
}
#Override
public void onRetry(int retryNo) {
// called when request is retried
}
});
after that
public void showStoreData(String st) {
Intent intent = new Intent(this, YourClass.class);
intent.putExtras(st);
startActivity(intent);
}
You should use an interface that you initialize from the calling method and pass as a parameter into you request class, that way you can call the requests from anywhere and get the callback response back to where you called it from, an example would be:
A general interface, separated in another file:
public interface SomeCustomListener<T>
{
public void getResult(T object);
}
In the class holding your call (complete the stuff you need):
public void someRequestReturningString(Object param1, final SomeCustomListener<String> listener)
{
//here you initialize what you need... it's your stuff
response.enqueue(new Callback<ResponseBody>()
{
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
{
try
{
String response = rawResponse.body().string();
// do what you want with it and based on that...
//return it to who called this method
listener.getResult("someResultString");
}
catch (Exception e)
{
e.printStackTrace();
listener.getResult("Error1...");
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable throwable)
{
try
{
// do something else in case of an error
listener.getResult("Error2...");
}
catch (Exception e)
{
throwable.printStackTrace();
listener.getResult("Error3...");
}
}
});
}
Then from where you're calling the request (could be anywhere, Fragments, onClicks, etc):
public class BlaBla
{
//.....
public void someMethod()
{
NetworkManager.getInstance().someRequestReturningString(someObject, new SomeCustomListener<String>()
{
#Override
public void getResult(String result)
{
if (!result.isEmpty())
{
//do what you need with the result...
}
}
});
}
}
If you need more context, you can refer to this SO thread.
Hope this helps!

trying to call join on a worker thread

I have an onClickListener that uses Okhttp to asynchronously get some stuff in the background. Here's the OnClickListener:
mGetChartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String companyName = mSymbolValue.getText().toString();
getRequest(companyName, "chart");
Log.i(TAG, mChartProfile.getSizeDates()+""); // Null exception happens here
}
});
And here is the Okhttp snippet:
OkHttpClient client = new OkHttpClient();
Request request = new Request
.Builder()
.url(completeUrl)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
String jsonData = response.body().string();
Log.v(TAG, jsonData);
if (response.isSuccessful()) {
if (requestType.equals("quote")) {
isValidSearch = getQuote(jsonData);
runOnUiThread(new Runnable() {
#Override
public void run() {
if (isValidSearch) {
updateDisplay();
}
toggleFacts(isValidSearch);
}
});
}
else{
getChartInfo(jsonData);
}
} else {
alertUserAboutError();
}
} catch (IOException e) {
Log.e(TAG, "Exception caught: ", e);
} catch (JSONException e) {
Log.e(TAG, "JSONException caught: ", e);
Toast.makeText(BuyActivity.this, "oops!", Toast.LENGTH_LONG).show();
}catch (ParseException e){
Log.e(TAG, "Unable to parse", e);
}
}
});
// How do I do a thread.join() here?
private void getChartInfo(String jsonData) throws JSONException, ParseException{
JSONObject wholeChartData = new JSONObject(jsonData);
JSONArray dates = wholeChartData.getJSONArray("Dates");
mChartProfile = new ChartProfile();
// ChartProfile contains ArrayList of ChartDate and ArrayList of ChartValue
for (int i = 0; i < dates.length(); i++){
ChartDate chartDate = new ChartDate(dates.getString(i));
mChartProfile.addToDates(chartDate);
}
JSONArray values = close.getJSONArray("values");
for (int i = 0; i < values.length(); i++){
ChartValue chartValue = new ChartValue(values.getDouble(i));
mChartProfile.addToValues(chartValue);
}
}
Right now, I'm getting an error of thread exiting with uncaught exception. And this is caused by a null exception because when calling mChartProfile.getSizeDates(), the values haven't been written in yet. My intuition is that the call to getChartInfo(jsonData) doesn't finish and the main UI thread is already returning from the getRequest() function. Hence, it will continue next line, and try to access an empty array that has not been initialized. Hence, I get a null exception. My solution is to have the main thread wait on the worker thread by calling thread.join() but I am not sure of how to do this through this Okhttp interface. Any help is deeply appreciated.

Retrieve data from method in java

How can I retrieve a file from the following method:
public void getJson(String pathToFile) {
String userUrl = DOMAIN_URL+pathToFile;
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(userUrl));
JSONArray outerJsonArray;
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
try {
JSONValue jsonValue = JSONParser.parse(response.getText());
JSONArray jsonArray = jsonValue.isArray();
if (jsonArray != null) {
} else {
throw new JSONException();
}
} catch (JSONException e) {
}
} else {
}
}
});
} catch (RequestException e) {
}
}
Now it is just void. I should retriwe the jsonArray variable
You simply can't.
The request is asynchronous, so your method has to be asynchronous (non-blocking) too. You can pass something like an AsyncCallback (to reuse an existing interface) to your getJson method, and have your RequestCallback call it... back, with the JSONArray.
Technically speaking, that would be possible, but that's a design choice in GWT to not allowing blocking AJAX requests.
Embrace asynchrony!
Just change the declaration to
public JSONArray getJson(String pathToFile) {
After the line
JSONArray jsonArray = jsonValue.isArray();
you can add
return jsonArray;
Now you have to be careful. Obviously, you have some error checking conditions in case the array is null or an error occurs during reading. It is up to you to design how to handle them: if the array is null, should you throw an exception or return the null value? If there is an error reading, should you throw an exception, print an error, or return a null value? These are considerations that your external interface will dictate.

Categories

Resources