I have a Volley request, and I'm trying to get the results set in a variable, but I get the error "Variable 'stuff' is accessed from inner class, needs to be declared final." The problem is, once I declare it as final, I'm not allowed to set the variable equal to the response (like I'm trying to in the try block). I've looked around for the other questions that discuss this, but none have really been helpful to my situation.
Here is the code:
public ArrayList getStuff() {
ArrayList<JSONObject> stuff;
new Thread(new Runnable() {
#Override
public void run() {
// Instantiate the RequestQueue.
RequestQueue queue = MySingleton.getInstance(getApplicationContext()).getRequestQueue();
String url ="http://localhost:6000/stuff";
RequestFuture<String> future = RequestFuture.newFuture();
// Testing out blocking
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, future, future);
// Add the request to the RequestQueue.
queue.add(stringRequest);
try {
String response = future.get(30, TimeUnit.SECONDS);
stuff = response;
Log.i("tutors after blocked: ", tutors);
} catch(InterruptedException e) {
e.printStackTrace();
} catch(ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}).start();
// I want to be able to return 'stuff' here
return stuff;
}
Just add the word final as indicated below.
public ArrayList getStuff() {
final ArrayList<JSONObject> stuff; <--Add final here
new Thread(new Runnable() {
#Override
public void run() {
// Instantiate the RequestQueue.
RequestQueue queue = MySingleton.getInstance(getApplicationContext()).getRequestQueue();
String url ="http://localhost:6000/stuff";
RequestFuture<String> future = RequestFuture.newFuture();
// Testing out blocking
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, future, future);
// Add the request to the RequestQueue.
queue.add(stringRequest);
try {
String response = future.get(30, TimeUnit.SECONDS);
stuff = response;
Log.i("tutors after blocked: ", tutors);
} catch(InterruptedException e) {
e.printStackTrace();
} catch(ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}).start();
// I want to be able to return 'stuff' here
return stuff;
}
Just move that variable declaration outside the method. this means it is already a Global Variable of that class
ArrayList<JSONObject> stuff;
public ArrayList getStuff() {
new Thread(new Runnable() {
#Override
public void run() {
// Instantiate the RequestQueue.
RequestQueue queue = MySingleton.getInstance(getApplicationContext()).getRequestQueue();
String url ="http://localhost:6000/stuff";
RequestFuture<String> future = RequestFuture.newFuture();
// Testing out blocking
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, future, future);
// Add the request to the RequestQueue.
queue.add(stringRequest);
try {
String response = future.get(30, TimeUnit.SECONDS);
stuff = response;
Log.i("tutors after blocked: ", tutors);
} catch(InterruptedException e) {
e.printStackTrace();
} catch(ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}).start();
// I want to be able to return 'stuff' here
return stuff;
}
After digging so much I got something in my mind that SharedPreferences,
If you really want response data outside , You can use SharedPreferences to store the response value in some variable and read the same value outside whenever you want.
To set value to the variable
String MyPREFERENCES = "MyPrefs";
SharedPreferences.Editor editor = context.getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE).edit();
editor.putString("returnResponse", "success");
editor.apply();
To get value of the variable
String return_value = sharedpreferences.getString("returnResponse", "");
Related
I have such an OkHttp code to retreive data from OpenWeather API:
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new okhttp3.Request.Builder().url(url).build();
AsyncTask.execute(() -> {
Response response = null;
try {
response = okHttpClient.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
if(response.code() == 200) {
Log.d("weather", "200");
JSONArray array;
try {
JSONObject mObj = new JSONObject(response.body().string());
array = mObj.getJSONArray("weather");
widgetView.setTextViewText(R.id.weatherTextView, array.getJSONObject(0).getString("main"));
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
It's located in my Widget class in void updateWidget, which is called from onUpdate() void. But the problem is that this OkHttp code just doesn't get executed.
What can cause this problem?
I am using the strava API for an app. I am making synchronous requests as can be seen by the code below.
try {
RequestQueue queue = Volley.newRequestQueue(context);
RequestFuture<String> future = RequestFuture.newFuture();
StringRequest request = new StringRequest(Request.Method.GET, urlRequest, future, future);
queue.add(request);
dataResponse = dealWithResponse(future.get());
} catch (ExecutionException e) {
System.err.println(e.getLocalizedMessage());
System.err.println(e.getMessage());
System.err.println(e.toString());
} catch (java.lang.Exception e) {
e.printStackTrace();
}
I want to know how can I get the response code in the event of an error? for example some rides I request have been deleted / are private and i receive a 404 error code. Other times I have run out of API requests and get a code of 403. How can i differentiate between the thrown errors.
Thank you very much for your help!
In your catch clause, where you handle the ExecutionException you can add the following:
if (e.getCause() instanceof ClientError) {
ClientError error = (ClientError)e.getCause();
switch (error.networkResponse.statusCode) {
//Handle error code
}
}
Override parseNetworkError on your request:
StringRequest request = new StringRequest(Request.Method.GET, urlRequest, future, future) {
#Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
if (volleyError != null && volloeyError.networkResponse != null) {
int statusCode = volleyError.networkResponse.statusCode;
switch (statusCode) {
case 403:
// Forbidden
break;
case 404:
// Page not found
break;
}
}
return volleyError;
}
};
Im trying to return a boolean value from a runnable method within a Thread. I need to know whether a HTTPRequest method succeeded or not. The problem is I know the request is successful but I always get false as the response.
public boolean SmsDelivery;
SmsDelivery=sendSMS(prefix, number);
if(SmsDelivery){
//Do stuff
}
//The method itself
private boolean sendSMSinThread(final String str){
final AtomicBoolean b = new AtomicBoolean(false);
Thread thread = new Thread(new Runnable(){
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(str);
#Override
public void run() {
try {
// Execute HTTP Post Request
//HttpResponse response = httpclient.execute(httppost);
httpclient.execute(httppost);
b.set(true);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
Log.e("Thread:","Unable to generate call"+e);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("Thread:","Unable to generate call"+e);
}
}
});
thread.start();
return b.get();
}
UPDATE
Based on the advices here i managed to get the desired result, however, I dont know which method is more suitable for my needs. Can someone recommend whats the best usage in my case? Using AsyncTask or a Thread + join method.
First method is using AsyncTask in the following manner:
SmsTask smsTask = new SmsTask();
try{
smsResult = smsTask.execute(urlString).get();
}catch (InterruptedException e){
e.printStackTrace();
}catch (ExecutionException e){
e.printStackTrace();
}
//the class itself
class SmsTask extends AsyncTask<String,Void, Boolean> {
final AtomicBoolean b = new AtomicBoolean(false);
#Override
protected Boolean doInBackground(String... params) {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(params[0]);
try {
httpclient.execute(httppost);
b.set(true);
} catch (IOException e) {
e.printStackTrace();
}
return b.get();
}
#Override
protected void onPostExecute(Boolean result) {
// result holds what you return from doInBackground
Log.i("result from async: ",""+result);
super.onPostExecute(result);
}
}
Second method, almost as I initially posted but with the 'thread.join()' method:
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return b.get();
You should wait until task will be performed. In this case you should run this code in single thread (new Thread is useless) or use Android's AsyncTask-like class and process result in onPostExecute method.
You could use some Observer pattern or something.
Something like this:
// have a custom Runnable
public class HTTPRequestRunnable implements Runnable {
HttpClient httpclient;
HttpPost httppost;
private HTTPRequestListner listner;
public HTTPRequestRunnable(String str, HTTPRequestListner listner) {
httpclient = new DefaultHttpClient();
httppost = new HttpPost(str);
this.listner = listner;
}
#Override
public void run() {
try {
// Execute HTTP Post Request
//HttpResponse response = httpclient.execute(httppost);
httpclient.execute(httppost);
if (listner != null)
listner.onSuccess();
} catch (ClientProtocolException e) {
if (listner != null)
listner.onFail();
Log.e("Thread:", "Unable to generate call" + e);
} catch (IOException e) {
if (listner != null)
listner.onFail();
e.printStackTrace();
Log.e("Thread:", "Unable to generate call" + e);
}
}
public void setListner(HTTPRequestListner listner) {
this.listner = listner;
}
/**
* here is your observer class
*/
public interface HTTPRequestListner {
void onSuccess();
void onFail();
}
}
Then use it like this in your method:
public void sendSMSinThread(final String str){
HTTPRequestRunnable httpRequestRunnable = new HTTPRequestRunnable(str,new HTTPRequestListner() {
#Override
public void onSuccess() {
//DO your logic here on success
}
#Override
public void onFail() {
//DO your logic here on fail
}
});
Thread thread = new Thread(httpRequestRunnable);
thread.start();
}
Here you go and i hope it will help you
There are multiple ways to achieve this.
Use a callable, instead of runnable, as callable's call method can return result
Stick to your approach, but before returning the result, call thread.join()
thread.start();
thread.join();
return b.get();
Drawbacks
If there are thousands of SMS to be sent, it will create those many threads.
There is no use of thread creation here as you can the incoming thread itself to send SMS.
Use Runnable and Future.
a. For each SMS create a SendSms object,
b. It will create a maximum of 10 threads.
c. The send SMS and getSMSdelivery will be synchronous events. So for each SMS sent, you can get the delivery status if that's your requirement.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SendSms
{
private static ExecutorService pool = Executors.newFixedThreadPool(10);
public boolean submitSms(String message,String phNo)
{
Runnable run = new SendSMSThread(message,phNo);
Future future = pool.submit(run);
try {
if(null ==future.get())
{
return true;
}
} catch (InterruptedException | ExecutionException e) {
// SMS Sending failed.
e.printStackTrace();
return false;
}
return false;
}
private class SendSMSThread implements Runnable
{
String message;
String phNo;
public SendSMSThread(String message,String phNo)
{
this.message = message;
this.phNo = phNo;
}
public void run()
{
//Send SMS
}
}
}
All the above three solution are blocking. So it will keep the threads in BLOCKING state, thereby posing significant threat to scalability of system.
a. Use a BlockingQueue.
b. For each SMS request, add a SMSObject to BlockingQueue.
c. Use a threadpool and process the objects in Queue.
d. Once the SMS is sent successfully, save the result to another data-structure.
e. Use a threadpool, read the data from above data-structure and notify about successful SMS delivery.
Try this
thread.start();
thread.join();
return b.get();
okay so i created a inner class which extends AsycTask in order for my code to run outwith the UI thread. However i'm getting this error so i assume this means some part of my onPostExecute needs to be done in doInBackground however i cant figure out exactly what this is
public class asyncTask extends AsyncTask<String, Integer, String> {
ProgressDialog dialog = new ProgressDialog(PetrolPriceActivity.this);
#Override
protected void onPreExecute() {
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setProgress(0);
dialog.setMax(100);
dialog.setMessage("loading...");
dialog.show();
}
#Override
protected String doInBackground(String...parmans){
{
for(int i = 0; i < 100; i++){
publishProgress(1);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
String urlString = petrolPriceURL;
String result = "";
InputStream anInStream = null;
int response = -1;
URL url = null;
try {
url = new URL(urlString);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
return null;
}
URLConnection conn = null;
try {
conn = url.openConnection();
} catch (IOException e) {
// TODO Auto-generated catch block
return null;
}
// Check that the connection can be opened
if (!(conn instanceof HttpURLConnection))
try {
throw new IOException("Not an HTTP connection");
} catch (IOException e) {
// TODO Auto-generated catch block
return null;
}
try
{
// Open connection
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
// Check that connection is OK
if (response == HttpURLConnection.HTTP_OK)
{
// Connection is OK so open a reader
anInStream = httpConn.getInputStream();
InputStreamReader in= new InputStreamReader(anInStream);
BufferedReader bin= new BufferedReader(in);
// Read in the data from the RSS stream
String line = new String();
while (( (line = bin.readLine())) != null)
{
result = result + "\n" + line;
}
}
}
catch (IOException ex)
{
try {
throw new IOException("Error connecting");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result;
}
}
#Override
protected void onProgressUpdate(Integer...progress){
dialog.incrementProgressBy(progress[0]);
}
#Override
protected void onPostExecute(String result) {
// Get the data from the RSS stream as a string
errorText = (TextView)findViewById(R.id.error);
response = (TextView)findViewById(R.id.title);
try
{
// Get the data from the RSS stream as a string
result = doInBackground(petrolPriceURL);
response.setText(result);
Log.v(TAG, "index=" + result);
}
catch(Exception ae)
{
// Handle error
errorText.setText("Error");
// Add error info to log for diagnostics
errorText.setText(ae.toString());
}
if(dialog.getProgress() == dialog.getMax())
dialog.dismiss();
}
}
if someone could point out my error as well as show an example of where the code is suppose to go in my doInBackground that would be great. Thanks
problem:
result = doInBackground(petrolPriceURL);
you are implicitly calling the doInbackground method in the onPostExecute which will actually run in your UI thread instead on a different thread thus resulting to Android:NetworkOnMainThreadException.
Also it is unnecessary to call doInBackground that it is already executed before onPostExecute when you execute your Asynctask. Just directly use the result parameter of the onPostExecute.
sample:
#Override
protected void onPostExecute(String result) {
// Get the data from the RSS stream as a string
errorText = (TextView)findViewById(R.id.error);
response = (TextView)findViewById(R.id.title);
response.setText(result);
if(dialog.getProgress() == dialog.getMax())
dialog.dismiss();
}
I suspect the error is related to this part of your code:
try
{
// Get the data from the RSS stream as a string
result = doInBackground(petrolPriceURL);
response.setText(result);
Log.v(TAG, "index=" + result);
}
doInBackgound is called automatically when you call asynctask.execute. To start your task correctly you should (1) create a new instance of your task; (2) pass the string params you need to use in doInBackground in the execute method; (3) use them; (4) return the result to onPostExecute.
For Example:
//in your activity or fragment
MyTask postTask = new MyTask();
postTask.execute(value1, value2, value3);
//in your async task
#Override
protected String doInBackground(String... params){
//extract values
String value1 = params[0];
String value2 = params[1];
String value3 = params[2];
// do some work and return result
return value1 + value2;
}
#Override
protected void onPostExecute(String result){
//use the result you returned from you doInBackground method
}
You should try to do all of your "work" in the doInBackground method. Reutrn the result you want to use on the main/UI thread. This will automaticlly be passed as an argument to the onPostExecute method (which runs on the main/UI thread).
I have an android app that most of its feature consumes an API. My client complained that the retrieving of data from the web api is very slow. I wonder what's causing this.
Here's a basic structure of how I do my calls:
String returnString = "";
token = tokenBuilder.generateToken("Customers/All");
try {
HttpGet request = new HttpGet(apiUrl + "CustomerRewards/All?customerId=" + id);
request.setHeader(HTTP.CONTENT_TYPE, "application/json");
request.setHeader("AccountId", headerAccountId);
request.setHeader("StoreId", headerStoreId);
request.setHeader("AppKey", headerAppKey);
request.setHeader("Token", token);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);
String responseString = EntityUtils.toString(response.getEntity());
Log.i("Api Message", responseString);
returnString = responseString;
} catch (Exception e) {
returnString = e.getMessage();
}
return returnString;
I'm calling this method from a progress dialog in order to display a loader while, retrieving data from the web API. Is there a better way to do this? Or is somewhat my android code affects its performance?
Here's the code on the calling progress dialog.
rewardsErrorMessage = "";
progressBar = new ProgressDialog(this);
progressBar.setCancelable(true);
progressBar.setMessage("Loading info ...");
progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressBar.setProgress(0);
progressBar.setMax(100);
progressBar.setCancelable(false);
progressBar.show();
apiLoadStatus = false;
new Thread(new Runnable() {
public void run() {
while (!apiLoadStatus) {
apiLoadStatus = RewardApi();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (apiLoadStatus) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
progressBar.dismiss();
}
}}).start();
progressBar.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
SetValues();
}
});
And here's the method that actually calls the api class that connects to the web api
ApiConnection api = new ApiConnection();
try {
Log.i("CustomerId", customerInfos.getString("customer_id", ""));
transactionMessage = api.GetTransactions(customerInfos.getString("customer_id", ""));
availableRewardsMessage = api.GetCustomerRewards(customerInfos.getString("customer_id", ""));
try
{
if(transactionMessage.contains("Timestamp"))
{
Log.i("Transaction", "Success");
GetPoints(transactionMessage);
}
if(!availableRewardsMessage.equals("[]") && !availableRewardsMessage.equals("[]"))
{
JSONObject rewardsJson = new JSONObject(availableRewardsMessage);
availableRewardsMessage = rewardsJson.getString("AvailableRewards");
hasRewards = true;
}
return true;
}
catch(Exception e)
{
rewardsErrorMessage = transactionMessage.replace('[', ' ').replace(']', ' ').replace('"', ' ');
}
} catch(Exception e) {
e.printStackTrace();
rewardsErrorMessage = e.getMessage();
return true;
}
return true;
As you notice, I have two api calls here.
I really would like to speed up the retrieving of data. Or is the api I'm consuming that slow? Any ideas guys? Thanks!
As you're probably aware, there are a number of factors that can affect HTTP service calls, of which the client code is only one:
Network speed and latency
Server availability and load
Size of data payload
Client device resources
Client code
You really need to determine where the bottleneck(s) are in order to know where to try to optimize. Additionally, you should make sure that the server is using Gzip to compress the payload and add the following to your client code:
request.setHeader("Accept-Encoding", "gzip");