I am using Volley library to communicate with my database. I use recursive function to check continuously my database but after a period of time seems like the recursive function stop working and I get the following error:
FATAL EXCEPTION: main
Process: com.example.sakis.loginregister, PID: 22637
java.lang.OutOfMemoryError: pthread_create (stack size 131072 bytes) failed: Try again
at java.lang.VMThread.create(Native Method)
at java.lang.Thread.start(Thread.java:1029)
at com.android.volley.RequestQueue.start(RequestQueue.java:145)
at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:66)
at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:78)
at com.example.sakis.loginregister.MultiPlayerActivity.func(MultiPlayerActivity.java:342)
at com.example.sakis.loginregister.MultiPlayerActivity$2.onResponse(MultiPlayerActivity.java:160)
at com.example.sakis.loginregister.MultiPlayerActivity$2.onResponse(MultiPlayerActivity.java:133)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:60)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:30)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
I think it is a stackoverflow error when i dont get the proper response in time.Here is the recursive function code that i first call in onCreate method:
void func(){
reject=0;
Response.Listener<String> response1Listener = new Response.Listener<String>() {
#Override
public void onResponse(final String response) {
try {
JSONObject jsonResponse = new JSONObject(response);
request = jsonResponse.getInt("request");
requestorigin = jsonResponse.getString("requestorigin");
category = jsonResponse.getInt("category");
dif_level = jsonResponse.getInt("dif_level");
number_of_questions = jsonResponse.getInt("number_of_questions");
time_of_answer = jsonResponse.getInt("time_of_answer");
if(request==0) {
func();
}
if (request == 1) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MultiPlayerActivity.this,R.style.myBackgroundStyle);
alertDialogBuilder.setMessage("Έχεις νέο αίτημα από τον χρήστη " + requestorigin + "\n" + "Κατηγορία Ερωτήσεων: " + array_category[category]
+ "\n" + "Επίπεδο Δυσκολίας: " + array_dif_level[dif_level] + "\n" + "Αριθμός Ερωτήσεων: " + number_of_questions + "\n "
+ "Χρόνος Απάντησης: " + time_of_answer);
alertDialogBuilder.setPositiveButton("Ναι", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
Response.Listener<String> response1Listener = new Response.Listener<String>() {
#Override
public void onResponse(final String response) {
try {
JSONObject jsonResponse = new JSONObject(response);
} catch (JSONException e)
{
e.printStackTrace();
}
}
};
SendResponseRequest sendResponseRequest = new SendResponseRequest(username, response1Listener);
RequestQueue queue1 = Volley.newRequestQueue(MultiPlayerActivity.this);
queue1.add(sendResponseRequest);
Response.Listener<String> responseListener=new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonResponse = new JSONObject(response);
boolean success1=jsonResponse.getBoolean("success1");
if(success1) {
Intent intent2 = new Intent(MultiPlayerActivity.this, MultiPlayerGame2Activity.class);
intent2.putExtra("username1",username);
intent2.putExtra("username2",requestorigin);
intent2.putExtra("category", category);
intent2.putExtra("dif_level", dif_level);
intent2.putExtra("number_of_questions", number_of_questions);
intent2.putExtra("time_of_answer", time_of_answer);
intent2.putExtra("level", level);
intent2.putExtra("score", score);
intent2.putExtra("music",music);
intent2.putExtra("sound",sound);
startActivity(intent2);
// android.os.Process.killProcess(android.os.Process.myPid());
finish();
}
} catch (JSONException e)
{
e.printStackTrace();
}
}
};
Back0Request back0Request = new Back0Request(username,responseListener);
RequestQueue queue = Volley.newRequestQueue(MultiPlayerActivity.this);
queue.add(back0Request);
}
});
alertDialogBuilder.setNegativeButton("Όχι", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Response.Listener<String> response1Listener = new Response.Listener<String>() {
#Override
public void onResponse(final String response) {
try {
JSONObject jsonResponse = new JSONObject(response);
reject = jsonResponse.getInt("reject");
if(reject==1) {
func();
}
} catch (JSONException e)
{
e.printStackTrace();
}
}
};
RejectRequestRequest rejectRequestRequest = new RejectRequestRequest(username, response1Listener);
RequestQueue queue1 = Volley.newRequestQueue(MultiPlayerActivity.this);
queue1.add(rejectRequestRequest);
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
} catch (JSONException e)
{
e.printStackTrace();
}
}
};
//text2.setText("OK");
CheckRequest checkRequest = new CheckRequest(username, response1Listener);
/***
int socketTimeout = 30000;//30 seconds - change to what you want
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
checkRequest.setRetryPolicy(policy);
******/
RequestQueue queue1 = Volley.newRequestQueue(MultiPlayerActivity.this);
queue1.add(checkRequest);
//text3.setText("After ");
}
When the variable requests that I take from the database has a zero value I want to check the database again until it will take a non-zero value. Is there any better way to achieve that so I can avoid recursion because it will cause some overflow errors.
Problem solved when i use Singleton Pattern and re-use the same instance of the queue so i prevent out of memory error:
public class MySingleton {
private static MySingleton mInstance;
private RequestQueue mRequestQueue;
private static Context mContext;
private MySingleton(Context context){
// Specify the application context
mContext = context;
// Get the request queue
mRequestQueue = getRequestQueue();
}
public static synchronized MySingleton getInstance(Context context){
// If Instance is null then initialize new Instance
if(mInstance == null){
mInstance = new MySingleton(context);
}
// Return MySingleton new Instance
return mInstance;
}
public RequestQueue getRequestQueue(){
// If RequestQueue is null the initialize new RequestQueue
if(mRequestQueue == null){
mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext());
}
// Return RequestQueue
return mRequestQueue;
}
public<T> void addToRequestQueue(Request<T> request){
// Add the specified request to the request queue
getRequestQueue().add(request);
}
Related
In my main activity i have a fragment which displays weather information. I have an interface between the fragment and the main activity that sends data from fragment to activity. The problem is when trying to specifically enter the fragment activity the app crashes and this error is displayed.
Any help or any alternative ways doing it would be appreciated.
private void loadData() {
final List<WeatherForeCast> listWeatherForeCasts = new ArrayList<>();
StringRequest stringRequest = new StringRequest(Request.Method.GET,
"https://www.metaweather.com/api/location/3534/",
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray array = jsonObject.getJSONArray("consolidated_weather");
JSONObject jsonObject1 = jsonObject.getJSONObject("parent");
String cityCountry = jsonObject1.getString("title");
cityCountry = cityCountry + " ," + jsonObject.getString("title");
textViewCity.setText(Html.fromHtml(cityCountry ));
for (int x = 0; x < 6; x++) {
JSONObject weatherObject = array.getJSONObject(x);
WeatherForeCast weatherForeCast = new WeatherForeCast(
weatherObject.getInt("air_pressure"),
weatherObject.getInt("wind_speed"),
weatherObject.getInt("the_temp"),
weatherObject.getInt("humidity"),
weatherObject.getString("weather_state_name"),
weatherObject.getString("applicable_date"));
listWeatherForeCasts.add(weatherForeCast);
weatherState = listWeatherForeCasts.get(0).getWeatherState();
if(x == 0) {
sendData();
}
}
;
adapter = new Adapter(listWeatherForeCasts, getActivity());
recyclerView.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
requestQueue.add(stringRequest);
}
public void sendData()
{
Log.i("fault", weatherState);
getFirstWeatherInterface getFirstWeather = (getFirstWeatherInterface) getActivity();
getFirstWeather.getFirst(weatherState);
}
//Interface is implemented in the Activity
#Override
public WeatherForeCast getFirst(String string) {
Log.i("fault2", string);
return null
}
java.lang.ClassCastException: com.fan4.outdoorplus.WeatherFragments.WeatherActivity cannot be cast to com.fan4.outdoorplus.getFirstWeatherInterface
at com.fan4.outdoorplus.WeatherFragments.WeatherFragment.sendData(WeatherFragment.java:143)
at com.fan4.outdoorplus.WeatherFragments.WeatherFragment$1.onResponse(WeatherFragment.java:117)
at com.fan4.outdoorplus.WeatherFragments.WeatherFragment$1.onResponse(WeatherFragment.java:92)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:82)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:29)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:102)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Your problem is in this line. You are trying casting your activity to getFirstWeatherInterface
getFirstWeatherInterface getFirstWeather = (getFirstWeatherInterface) getActivity();
Am implementing a service to get updates from server as below:
public class Myupdates extends Service {
private static final String TAG = "AutoUpdates";
private static final int started = 0;
static SQLiteDatabase db;
private boolean isRunning = false;
private CountDownTimer timer;
#Override
public void onCreate() {
this.db = openOrCreateDatabase("db", Context.MODE_PRIVATE, null);
//Log.i(TAG, "Service onCreate");
isRunning = true;
}
int mCount = 1;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Log.i(TAG, "Service onStartCommand");
//Creating new thread for my service
//Always write your long running tasks in a separate thread, to avoid ANR
new Thread(new Runnable() {
#Override
public void run() {
if (isRunning) {
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
updates();
}
}, 0, 30000);
}
//Stop service once it finishes its task
//stopSelf();
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
//Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onDestroy() {
isRunning = false;
//Log.i(TAG, "Service onDestroy");
}
/*
HANDLE ADVERTS
*/
protected void updates() {
/*
JSON
*/
final JSONObject json = new JSONObject();
final JSONObject manJson = new JSONObject();
try {
manJson.put("userid", "4444");
manJson.put("version", "6.0");
final String j = json.put("UPDATE", manJson).toString();
final String base_url = "https://myweburl.com";
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.POST, base_url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//Log.i(TAG, "received "+response);
try {
JSONObject object = (JSONObject) new JSONTokener(response).nextValue();
String update = object.getString("UPDATE");
} catch (JSONException e) {
return;
}
return;
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//perform operation here after getting error
return;
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
//pack message into json
try {
params.put("data", j.toString());
} catch (Exception e) {
//Log.i(TAG,"Map error: Unable to compile post");
}
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/x-www-form-urlencoded");
return params;
}
};
// Add the request to the RequestQueue.
queue.add(stringRequest);
// ends here
return;
} catch (Exception e) {
//Log.i(TAG,"ERROR: Unable to get setup settings");
} // end exception write
return;
}
}
However, after a long running of the service the app is crashing with the below error:
03-08 00:19:41.570 11239-11253/com.mobiledatabook.com.dialcode
E/AndroidRuntime: FATAL EXCEPTION: Timer-0
Process: com.mobiledatabook.com.dialcode, PID: 11239
java.lang.OutOfMemoryError: pthread_create (stack size 16384 bytes)
failed: Try again
at java.lang.VMThread.create(Native Method)
at java.lang.Thread.start(Thread.java:1029)
at com.android.volley.RequestQueue.start(RequestQueue.java:152)
at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:66)
at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:78)
at
com.mobiledatabook.com.dialcode.Myupdates.iDialAutoUpdates(Myupdates.java:128)
at
com.mobiledatabook.com.dialcode.Myupdates$1$1.run(Myupdates.java:74)
at java.util.Timer$TimerImpl.run(Timer.java:284)
Error: java.lang.OutOfMemoryError.
Could someone help me to improve this code so as to avoid crashing the app after long running of the service?
This is occurring because you are creating the RequestQueue instance multiple times by passing the activity context. You should create the instance once using an Application class and then use it again and again whenever needed. Create an application class like this,
public class AppController extends Application {
private static AppController sInstance;
private RequestQueue mRequestQueue;
#Override
public void onCreate() {
super.onCreate();
sInstance = this;
}
public static synchronized AppController getInstance() {
return sInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
}
Then use it like this
RequestQueue queue=AppController.getInstance().getRequestQueue();
NOTE : By passing the context to request queue again and again , you are filling up your ram, which leads to an OutOfMemoryException when no more space can be allocated
As mentioned in android's official docs here ,
A key concept is that the RequestQueue must be instantiated with the Application context, not an Activity context. This ensures that the RequestQueue will last for the lifetime of your app, instead of being recreated every time the activity is recreated (for example, when the user rotates the device).
I am getting outofmemory exception when calling volley continuousally everytime and getting error at RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
Calling Method every 5 seconds like this.
handlerGetJockyLatLong = new Handler();
runnableJockyLatLong = new Runnable() {
#Override
public void run() {
handlerGetJockyLatLong.postDelayed(runnableJockyLatLong, 10000);
getJockyLatLongFromBackEnd();
}
};
handlerGetJockyLatLong.postDelayed(runnableJockyLatLong, 10000);
Method is:
private void getJockyLatLongFromBackEnd() {
final String getJockyID_URL = getProfileInformationURL(getUserAccessToken(UserSideTrackingPage.this), UserID);
Log.e("getJockyID_URL", getJockyID_URL);
StringRequest request = new StringRequest(Request.Method.GET, getJockyID_URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
if (response != null && !response.startsWith("<HTML>")) {
Log.e("getJocky_Url_Responce", response);
//progressDialog.dismiss();
try {
JSONObject jsonObject = new JSONObject(response);
JSONObject jsonObbjectError = jsonObject.getJSONObject("error");
String errorCode = jsonObbjectError.getString("code");
String errorMessage = jsonObbjectError.getString("message");
if (errorCode.equals("0")) {
if (jsonObject.has("data")) {
JSONObject jsonObjectData = jsonObject.getJSONObject("data");
Double latitude = Double.valueOf(jsonObjectData.getString("latitude"));
Double longitude = Double.valueOf(jsonObjectData.getString("longitude"));
globalGoogleMap.clear();
currentLocationMarker = CommonUtils.createMultipleMarkers(globalGoogleMap, latitude, longitude, "Jocky Location", R.drawable.current_location);
PickupLocationMarker = CommonUtils.createMultipleMarkers(globalGoogleMap, Double.valueOf(pickupLat), Double.valueOf(pickupLong), "Pickup Location", R.drawable.pickup_marker_icon);
DropLocationMarker = CommonUtils.createMultipleMarkers(globalGoogleMap, Double.valueOf(dropLong), Double.valueOf(dropLat), "Drop Location", R.drawable.drop_location_marker_icon);
}
} else {
Toast.makeText(getApplicationContext(), errorMessage, Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
Log.e("Exception", e.toString());
}
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Error", error.toString());
}
});
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
queue.add(request);
}
Please tell me i am doing wrong? should not we call always volley? Or should i put volley in singleton class so i can instantiate only once? Any suggestion would be fine. Thanks.
Try to use static RequestQueue here like below given , I experienced the same . When i used static it worked for me .
public class name extends AppCompactActivity{
static RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
public void yourmethod{
//code here
queue.add(request);
}
}
I am working on a android project. I got the response from google api and parsed the json. But i want to return the value outside of onResponse method which seems to be impossible for me now. Below is my code, I have already seen this answer here. But i want this value outside of this async method. Is it possible to access this value.
UPDATE - I have updated my code for more details. This is my full activity class. You can see what i want to achieve. Please help me how i can access value returned by Volley onResponse in method get_time_to_travel, inside method parseJson. This is really killing me now. My first android project and i am stuck here from last two days.
Any help on this would be appreciated.
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private LinearLayoutManager linearLayoutManager;
private CustomAdapter adapter;
private List<UserData> userData;
private LocationManager locationManager;
private LocationListener locationListener;
String origin, mode = "driving";
private String API = "APIKey";
TextView textView;
RequestQueue requestQueue;
RequestQueue requestQueue1;
String url = "https://url/users";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setHasFixedSize(true);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
double lat = location.getLatitude();
double lng = location.getLongitude();
origin = String.valueOf(lat)+","+String.valueOf(lng);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.INTERNET
}, 10);
}
return;
}
else{
locationManager.requestLocationUpdates("gps", 5000, 0, locationListener);
}
getData();
linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new CustomAdapter(this, userData);
recyclerView.setAdapter(adapter);
}
private void getData(){
userData = new ArrayList<>();
requestQueue = Volley.newRequestQueue(this);
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
parseJson(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY", "ERROR");
}
}
);
requestQueue.add(jsonArrayRequest);
}
private void parseJson(JSONArray response){
try {
for (int i = 0; i < response.length(); i++) {
JSONObject users = response.getJSONObject(i);
String id = ("id: "+users.getString("id"));
String name = ("Name: "+users.getString("name"));
String username = ("Username: "+users.getString("username"));
String email = ("Email: "+users.getString("email"));
String address = parseAddress(users);
String destination = parseCoordinates(users);
String company = parseCompany(users);
String phone = ("Phone: "+users.getString("phone"));
String website = ("Website: "+users.getString("website"));
String eta = get_time_to_travel(origin, destination, API, mode);
UserData udata = new UserData(id, name, username, email, address, phone, website, company,eta);
userData.add(udata);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private String parseAddress(JSONObject users) {
JSONObject completeAdd = null;
String address = null;
try {
completeAdd = users.getJSONObject("address");
String street = completeAdd.getString("street");
String suite = completeAdd.getString("suite");
String city = completeAdd.getString("city");
String zipcode = completeAdd.getString("zipcode");
address = ("Address :" + street + ", " + suite + ", " + city + ", " + zipcode);
} catch (JSONException e) {
e.printStackTrace();
}
return address;
}
private String parseCoordinates(JSONObject users) {
JSONObject completeAdd = null;
String destination = null;
try {
completeAdd = users.getJSONObject("address");
JSONObject coordinates = completeAdd.getJSONObject("geo");
String latitude = coordinates.getString("lat");
String longitude = coordinates.getString("lng");
destination = latitude + "," + longitude;
} catch (JSONException e) {
e.printStackTrace();
}
return destination;
}
private String parseCompany(JSONObject users) {
JSONObject companyDetail = null;
String company = null;
try {
companyDetail = users.getJSONObject("company");
String company_name = companyDetail.getString("name");
String catchPhrase = companyDetail.getString("catchPhrase");
String bs = companyDetail.getString("bs");
company = ("Company: " + company_name + ", " + catchPhrase + ", " + bs);
} catch (JSONException e) {
e.printStackTrace();
}
return company;
}
private String get_time_to_travel(String origin, String destination, String API, String mode){
requestQueue1 = Volley.newRequestQueue(this);
String eta = null;
String google_api = "https://maps.googleapis.com/maps/api/distancematrix/json?origins="+origin+"&destinations="
+destination+"s&mode="+mode+"&language=fr-FR&key="+API;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, google_api, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
eta = parseGoogleData(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY", "ERROR");
}
}
);
requestQueue1.add(jsonObjectRequest);
return eta;
}
private String parseGoogleData(JSONObject response) {
String estimated_time_arrival = null;
try {
JSONArray rows = response.getJSONArray("rows");
JSONObject elements = rows.getJSONObject(0);
JSONArray elementsArr = elements.getJSONArray("elements");
JSONObject durationObj = elementsArr.getJSONObject(0);
JSONObject durationData = durationObj.getJSONObject("duration");
estimated_time_arrival = durationData.getString("text");
} catch (JSONException e) {
e.printStackTrace();
}
return estimated_time_arrival;
}
}
Async task is doing work on other thread. So if you want to access any variable out side that method, you need to wait until the task get completed. Otherwise the variable will be null.
eg: on on response method
#Override
public void onResponse(String response) {
res=response;
anyMethodtopassVar(DataType data);
}
in OnCreate() of activity, remove these 2 lines
adapter = new CustomAdapter(this, userData);
recyclerView.setAdapter(adapter);
in getData() remove this line
userData = new ArrayList<>();
put them in parseJson() as below:
private void parseJson(JSONArray response){
try {
if(userData==null){
userData = new ArrayList<>();
}else{
userData.clear();
}
for (int i = 0; i < response.length(); i++) {
JSONObject users = response.getJSONObject(i);
String id = ("id: "+users.getString("id"));
String name = ("Name: "+users.getString("name"));
String username = ("Username: "+users.getString("username"));
String email = ("Email: "+users.getString("email"));
String address = parseAddress(users);
String destination = parseCoordinates(users);
String company = parseCompany(users);
String phone = ("Phone: "+users.getString("phone"));
String website = ("Website: "+users.getString("website"));
String eta = get_time_to_travel(origin, destination, API, mode);
UserData udata = new UserData(id, name, username, email, address, phone, website, company,eta);
userData.add(udata);
}
if(adapter == null){
adapter = new CustomAdapter(this, userData);
recyclerView.setAdapter(adapter);
}else{
adapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
this way, when json call finish, parseJson() is called.
and after parsing the array into userData the adapter is initialized or notified.
EDIT:
Well, this is not the best sol. but it's just something from the top of my head
little nasty/dirty. i don't know but i think it will do the job
1- you don't have to reinit the queue every time, so in get_time_to_travel() put that line out of the method:
requestQueue1 = Volley.newRequestQueue(this);
add final int index param to the method and make it void:
private void get_time_to_travel(String origin, String destination, String API, String mode, final int index){...
make onResponse() in the method like this:
public void onResponse(JSONObject response) {
eta = parseGoogleData(response);
userData.get(index).setEta(eta);//add this setter to your data object if not exist.
}
remove return eta;
init udata with empty string as eta for now:
UserData udata = new UserData(id, name, username, email, address, phone, website, company,"");
userData.add(udata);
modify the call to get_time_to_travel() in parseJson() as below:
get_time_to_travel(origin, destination, API, mode, i);
when get_time_to_travel() is called at onResponse() the object will be modified to hold the eta value retrieved from the API
this is nasty, sometimes the adapter might be notified before all calls to google api is completed. so this is just to show you how to make it
Edit2
a workaround for this is
init userData object with label "Loading..." for eta
UserData udata = new UserData(id, name, username, email, address, phone, website, company,"Loading...");
and notify the adapter at end of onResponse() of get_time_to_travel():
public void onResponse(JSONObject response) {
eta = parseGoogleData(response);
userData.get(index).setEta(eta);//add this setter to your data object if not exist.
adapter.notifyDataSetChanged();
}
Do you want to get the result of parseJson inside onResponse?
Change the return type of parseJson to UserData, call return userDate; inside try block and return null; in catch block. This will help you catch the result of parseJson from where you are calling it.
Let me know if I did not understand your question properly.
public void getString(final VolleyCallback callback) {
StringRequest req = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
res=response;
callback.onSuccess(res);
}
}...
}}
public interface VolleyCallback{
void onSuccess(String result);
}
Now inside your mainactivity you can do like this.
public void onResume(){
super.onResume();
getString(new VolleyCallback(){
#Override
public void onSuccess(String res){
... //do something
}
});
}
I am developing an application using android and i'm trying to get the jSon Array displayed in Listfragment using the loadInBackground() method below in my DataListLoader class:
class DataListLoader extends AsyncTaskLoader<List<Model>> {
List<Model> mModels;
String jsonString;
String name = "Daniel Nyerere", phone = "0652400670";
public DataListLoader(Context context) {
super(context);
loadInBackground();
}
public List<Model> loadInBackground() {
// You should perform the heavy task of getting data from
// Internet or database or other source
// Here, we are generating some Sample data
// Create corresponding array of entries and load with data.
final List<Model> entries = new ArrayList<Model>(50);
StringRequest stringRequest = new StringRequest(
Request.Method.GET, "http://10.0.2.2/webapp/json_get_data.php", new Response.Listener<String>() {
#Override
public void onResponse(String response) {
if (response.trim().contains("server_response")) {
jsonString = response.toString();
try {
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray jsonArray = jsonObject.getJSONArray("server_response");
int count = 0;
while (count < jsonArray.length()) {
JSONObject jo = jsonArray.getJSONObject(count);
name = jo.getString("name");
phone = jo.getString("user_phone");
entries.add(new Model(name, phone));
System.out.println("DATA FROM JSON ARRAY: " + name + " " + phone);
count++;
return;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
RequestQueue requestQueue = VolleySingleton.getInstance().getRequestQueue();
requestQueue.add(stringRequest);
entries.add(new Model(name, phone));
return entries;
}
But when i try to run it the data from System.out.println("DATA ENTRIES: "+entries); comes as null list ,so no data get displayed in the fragment activity . Anyone who can help me to fix it so that i get data from json because it consume me a lot of time
//You can call it in UI thread
final List<Model> entries = new ArrayList<Model>(5);
StringRequest stringRequest = new StringRequest(
Request.Method.GET, "http://10.0.2.2/webapp/json_get_data.php", new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//you need to update the `ListView` content here
//If you need you can create new thread here too e.g. using AsyncTask
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
RequestQueue requestQueue = VolleySingleton.getInstance().getRequestQueue();
requestQueue.add(stringRequest);