the app crashes when using OkHttpClient in doInBackground [closed] - java

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
My application on Android LOLLIPOP runs well, but in the lower version, program crashe and displays this error:
Exception caught
java.lang.RuntimeException: An error occured while executing doInBackground()
And points to this line of code:
OkHttpClient client = new OkHttpClient();
this is my code:
private void getMoviesFromDBz(int id) {
AsyncTask<Integer, Void, Void> asyncTask = new AsyncTask<Integer, Void, Void>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Integer... movieIds) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(linkkk + movieIds[0])
.build();
try {
Response response = client.newCall(request).execute();
JSONArray array = new JSONArray(response.body().string());
for (int i = 0; i < array.length(); i++) {
JSONObject object = array.getJSONObject(i);
Movie movie = new Movie(object.getInt("id") , object.getString("per") , object.getString("movie_name"),
object.getString("movie_image"), object.getString("movie_genre") , object.getString("movie_discription") , object.getString("movie_lat"), object.getString("movie_lon") , object.getString("movie_marker") , object.getString("sort") , object.getString("price") , object.getString("email") , object.getString("tell") , object.getString("location") , object.getString("count"));
ItemOneFragment.this.movies2.add(movie);
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
adapter2.notifyDataSetChanged();
getMoviesFromDB(0);
}
};
asyncTask.execute(id);
scroll2 = 1;
}

You're trying to access the Main/UI Thread in a background Thread:
ItemOneFragment.this.movies2.add(movie);
just return the movie object and execute the above line on the onPostExecute() method, also I wouldn't recommend instantiating an OkHttpClient for each request.

You're trying to performing action the on UI Thread from background Thread. So you can userunonuithread
runOnUiThread(new Runnable() {
#Override
public void run() {
ItemOneFragment.this.movies2.add(movie);
}
});
see the changes below in your code.
#Override
protected Void doInBackground(Integer... movieIds) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(linkkk + movieIds[0])
.build();
try {
Response response = client.newCall(request).execute();
JSONArray array = new JSONArray(response.body().string());
for (int i = 0; i < array.length(); i++) {
JSONObject object = array.getJSONObject(i);
Movie movie = new Movie(object.getInt("id") , object.getString("per") , object.getString("movie_name"),
object.getString("movie_image"), object.getString("movie_genre") , object.getString("movie_discription") , object.getString("movie_lat"), object.getString("movie_lon") , object.getString("movie_marker") , object.getString("sort") , object.getString("price") , object.getString("email") , object.getString("tell") , object.getString("location") , object.getString("count"));
runOnUiThread(new Runnable() {
#Override
public void run() {
ItemOneFragment.this.movies2.add(movie);
}
});
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
I think this may solve your problem.

You don't need any Asynctask with Okhttp
Look up examples that use the enqueue method
// Build the client and request in the main thread
// Start an asynchronous method
client.newCall(request).enqueue(new Callback() {
#Override public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
JSONObject json = new JSONObject(responseBody.string());
}
}
});
If you want to use JSON objects with Okhttp, Retrofit would be a better library

Related

keep data obtained in onResponse method available throughout the class

Basically in my android app I want user to search cities around the world, thus I am using an api to get all the cities of the world and storing in an ArrayList, this has been done in the onResponse method of okhttp library and after that the list becomes empty. This array list holds values only in onResponse but I want to use it in my entire class after the execution. Can anyone give me any ideas on that? Here is the code.
onCreate(){
OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder()
.url("https://raw.githubusercontent.com/David-Haim/CountriesToCitiesJSON/master/countriesToCities.json")
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
}
#Override
public void onResponse(Response response) throws IOException {
try {
fullObject = new JSONObject(response.body().string());
JSONArray s = fullObject.names();
for(int i=0; i<s.length(); i++) {
JSONArray citiesOfOneCoutry = null;
citiesOfOneCoutry = fullObject.getJSONArray(s.getString(i));
for(int j=0; j<citiesOfOneCoutry.length();j++) {
allCities.add(citiesOfOneCoutry.getString(j));
}
Log.d(TAG, "onResponse: in for "+allCities.size());
}
Log.d(TAG, "onResponse: outside for "+allCities.size()); //gives full size.
} catch (JSONException e) {
e.printStackTrace();
}
Log.d(TAG, "onResponse: outside try "+allCities.size()); //gives full size
}
});
Log.d(TAG, "outside response inside oncreate"+allCities.size()); //gives 0
}
I see in the logs that message from outside onResponse one is first and then the callback is getting executed. that is quite understandable but I want trick to get this ArrayList after response execution.
That is the nature of asynchronous operations, they don't complete in the order you wrote them. allCities data will not be available in your onCreate method because it hasn't had a chance to execute yet. The trick to using it outside of onResponse is to move the code that relies on the response to its own method.
private void updateUI() {
// Your code that relies on 'allCities'
}
and then in onResponse, call updateUI (or whatever you call it) after you populate allCities --
#Override
public void onResponse(Response response) throws IOException {
try {
fullObject = new JSONObject(response.body().string());
JSONArray s = fullObject.names();
for(int i=0; i<s.length(); i++) {
JSONArray citiesOfOneCoutry = null;
citiesOfOneCoutry = fullObject.getJSONArray(s.getString(i));
for(int j=0; j<citiesOfOneCoutry.length();j++) {
allCities.add(citiesOfOneCoutry.getString(j));
}
Log.d(TAG, "onResponse: in for "+allCities.size());
}
Log.d(TAG, "onResponse: outside for "+allCities.size()); //gives full size.
} catch (JSONException e) {
e.printStackTrace();
}
Log.d(TAG, "onResponse: outside try "+allCities.size()); //gives full size
updateUI();
}

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

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.

HttpClient.execute error =( [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
And Error's are:
error opening trace file:No Such file or directory(2);
java.lang.IllegalStateException: Manager is shut down. at
org.apache.http.impl.conn.SingleClientConnManager.assertStillUp(SingleClientConnManager.java:174)
org.apache.http.impl.conn.SingleClientConnManager.getConnection(bla
bla bla .java:212)
org.apache.http.impl.conn.SingleClientConnManager$1.getConnection(---.java:190)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:326)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
org.apache.http.impl.client.AbstractHttpClient.xecute(AbstractHttpClient.java:487)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
and more...
public class ReqClass {
public static final String TAG = ReqClass.class.getSimpleName();
//creating new ResClass object
ResClass resp = new ResClass();
//sending request
HttpResponse response;
//making the request - containst (url,header,entity);
HttpPost request;
//New HTTP Client
HttpClient httpClient = new DefaultHttpClient();
//our code in JSON or XML to Send Request
private String s;
//This variable contains the total number of keys
private int size;
// Map
Map<String,String> code = new HashMap<String, String>();
// Adding only Key Value parameters
public void addparametr (String key, String value){
code.put(key,value);
}
public String getS(){
return s;
}
//Adding Key Value and size of new map.
public void addparametr (String key, String value, int nOfValues){
}
public void Build(String lang){
//List Of keys
List<String> keys=new ArrayList<String>(code.keySet());
//k = keys; v = values;
String k="",v="";
// size = size of Map;
size=code.size();
// if we want to make our JSON Code to send Request
if (lang=="json"){
s="";
s+="{";
for (int i=0; i<size; i++){
k=keys.get(i);
v=code.get(k);
if (i==size-1) s=s+'"'+k+'"'+": "+'"'+v+'"';
else s=s+'"'+k+'"'+": "+'"'+v+'"'+',';
}
s=s+"}";
}
if (lang =="xml"){
s="";
s+="<code>";
for (int i=0; i<size; i++){
k=keys.get(i);
v=code.get(k);
s=s+'<'+k+'>'+v+"</"+k+'>';
}
s=s+"</code>";
}
}
// The Send Request Method - need link parameter and our JSON or XML code
public ResClass SendR (String url, String lang){
String valueOfSize = String.valueOf(size);
request= new HttpPost(url);
//adding a Header
request.addHeader("Header - Request Size", valueOfSize);
//adding request's body (Entity)
HttpEntity entity;
try {
entity = new StringEntity(s, "UTF-8");
request.setEntity(entity);
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
BackGroundTask doItInBackGround = new BackGroundTask();
doItInBackGround.execute();
//closing our connection
httpClient.getConnectionManager().shutdown();
return resp;
}
private class BackGroundTask extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
try {
//execute - means sending
response = httpClient.execute(request);
//adding new response to our Response Class
resp.addNewResponse(response);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
Log.e(TAG, "Exception caught: ", e);
}
return null;
}
}
}
You are calling getConnectionManager().shutdown() just after starting AsyncTask so before executing doInBackground method connection is shutdown . so use onPostExecute for close connection as:
protected void onPostExecute(Long result) {
// call shutdown() here
httpClient.getConnectionManager().shutdown();
}

AsyncTaks HTTP-request timeouts and exception handling

I'm making HTTP-get requests to the Facebook graph API.
In about 1/5 times my code never gets to Log.i("debug", "resp");. No exception thrown. Shouldn't it? Or is it just a very long timeout by default?
If I add a custom timeout (see below), I get to throw an exception. But even though my code is wrapped in a try+catch statement, my app crashes (just like on any unhandled exceptions), instead of letting me handle the error in onPostExecute(). Why dont I end up in the method?
protected Map<String, Integer> doInBackground(Void... params) {
Map<String, Integer> result = new HashMap<String, Integer>();
try {
HttpGet get = new HttpGet("https://graph.facebook.com/....etc");
//final HttpParams httpParams = httpclient.getParams();
//HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
//HttpConnectionParams.setSoTimeout(httpParams, 5000);
HttpResponse response = httpclient.execute(get);
Log.i("debug", "resp");
HttpEntity resEntityGet = response.getEntity();
//do stuff with resEntityGet
return result;
} catch (Exception e) {
Toast.makeText(mainActivity, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
return null;
}
}
protected void onPostExecute(Map<String, Integer> result) {
if(result != null){
//use the result data
} else {
//exception occured
}
}
You can show a Toast from the doInBackground method if you post it to the UI thread. There's a few ways to do it, but here's one way:
mainActivity.runOnUiThread( new Runnable() {
#Override
public void run() {
Toast.makeText(mainActivity, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
}
} );
You'll need to make the Exception variable final
Figured it out myself. Turns out that you can't create toasts in doInBackground(). Hope this helps someone else.
i also faced same problem that time i handle exception this way
public class ServerCheckingActvity extends Activity{
ProgressDialog progress;
static String constant="";
Map<String, Integer> result;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MyAsynchTask().execute();
}
private class MyAsynchTask extends AsyncTask<Void,Void,String>{
#Override
protected void onPreExecute(){
progress=new ProgressDialog(ServerCheckingActvity.this);
// progress.setTitle(" DATA RETRIVEING");
progress.setMessage("please wait........");
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progress.setCancelable(true);
progress.show();
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
String view="";
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet("www.facebook .com/...........");
//final HttpParams httpParams = httpclient.getParams();
//HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
//HttpConnectionParams.setSoTimeout(httpParams, 5000);
HttpResponse response =httpClient.execute(get);
Log.i("debug", "resp");
HttpEntity resEntityGet = response.getEntity();
//do stuff with resEntityGet
// assigen ur value to result map object here;
result = new HashMap<String, Integer>();
} catch (Exception e) {
constant="Exception";
//Toast.makeText(mainActivity, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
//return null;
}
return view="from doing background";
}
#Override
protected void onPostExecute(String view ){
if(constant=="Exception"){
constant="";
Toast.makeText(getApplicationContext(), "server problem", Toast.LENGTH_LONG).show();
}else if(result != null){
//use the result data
} else {
//exception occured
}
}
}
catch (Exception ex) {
// execep is here string variable u declare in globally
execep=ex.getMessage();
runOnUiThread( new Runnable() {
#Override
public void run() {
Toast.makeText( getApplicationContext(), "Error: " +execep, Toast.LENGTH_LONG).show();
}} );
}//catch
Your code is right but it's not clearly and safe. If you do not set up timeout, it is set default value 0. A timeout value of zero is interpreted as an infinite timeout. In that case , when response data has problem because of anything, your client either is interrupted or do not know anything. In case 2 - worse case - client will not throw any exception and your program will live forever.
Resolve for this problem, you should set timeout when get or post everything to server. It's safe.
I do not exactly know the cause client lives forever without any exception. I think it it a server problem or network problem.
Hope can help you.

Categories

Resources