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?
Related
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;
}
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
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!
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.
I am trying to get data from RSS feed to display it in fragments (11 fragment), but each time i pass to a new fragment the UI block for a several seconds because it's fetching data so i try to use asyncTask to do this in background but it seems that it does not work.
public class AndroidSaxFeedParser extends AsyncTask<String, Long, ArrayList<Article>>{
String dt;
String bb;
String nameCat;
RootElement root;
Element item;
static final String RSS = "rss";
static final String FEED = "feed";
static final String ENTRY = "entry";
static final String CHANNEL = "channel";
static final String PUB_DATE = "pubDate";
static final String DESCRIPTION = "description";
static final String LINK = "link";
static final String TITLE = "title";
static final String ITEM = "item";
static final String CATEGORY = "category";
static final String DURATION = "itunes:duration";
ArrayList<Article> rssItems = new ArrayList<Article>();
public URL feedUrl;
Context mContext;
public AndroidSaxFeedParser(Context context)
{
mContext = context;
}
// ProgressDialog pd = new ProgressDialog(mContext);
#Override
protected void onPostExecute(ArrayList<Article> result) {
// pd.dismiss();
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
// ProgressDialog.show(mContext, "", "Chargement...");
super.onPreExecute();
}
#Override
protected ArrayList<Article> doInBackground(String... params) {
try {
feedUrl = new URL(params[0]);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
final Article currentRssItem = new Article();
root = new RootElement(RSS);
Element channel = root.getChild(CHANNEL);
item = channel.getChild(ITEM);
item.getChild(TITLE).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentRssItem.setTitle(body);
Log.i("Title Article", " "+currentRssItem.getTitle());
}
});
item.getChild(CATEGORY).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentRssItem.setCategorie(body);
Log.i("Category Article", " "+currentRssItem.getCategorie());
}
});
item.getChild(DESCRIPTION).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
String imgUrl, desc;
try {imgUrl = body.substring(body.indexOf("src=")+5,body.indexOf("\"", body.indexOf("src=")+6));}
catch (Exception e)
{imgUrl = "";}
try {desc=body;}
catch (Exception e)
{ desc = "";}
currentRssItem.setImageUrl(imgUrl);
currentRssItem.setDescription(desc);
Log.i("Image URL Article", " "+currentRssItem.getImageUrl());
Log.i("Description Article", " "+currentRssItem.getDescription());
}
});
item.getChild(PUB_DATE).setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentRssItem.setPubDate(body);
Log.i("Date Article", " "+currentRssItem.getPubDate());
}
});
item.setEndElementListener(new EndElementListener(){
public void end() {
rssItems.add(currentRssItem.copy());
}
});
try {
Xml.parse(feedUrl.openConnection().getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
return rssItems;
}
I am calling it this way in each fragment
ArrayList<Article> feeds ;
try {
feeds=AndroidSaxFeedParser.execute(url).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
You should always download the file and save it as a String before asking the XML class to parse it.
public String getXml(String url) {
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
// HTTP OK 200
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
// NOTE: Here need to set the default charset to be UTF-8
content = EntityUtils.toString(entity, "UTF-8");
return content;
}
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
content = null;
}
}
In this way it is less likely to get interrupted due to connection problem. In addtition, please tell us more about what "it seems that it does not work" means. Did it fail to parse the xml, fail to run the task, or fail what?
Also, you should not be calling
feeds=AndroidSaxFeedParser.execute(url).get();
in your fragment. You should modify this function of your AndroidSaxFeedParser:
#Override
protected void onPostExecute(ArrayList<Article> result) {
feeds = result;
// Do whatever you wanna do to set up things with the feeds
}
To make this work you must put your AndroidSaxFeedParser as an inner class of your fragment.