I have 3 API GET calls. The problem I'm facing with my approach is, the app is able to fetch the data successfully from two APIs and I'm able to display it on UI as well. But, for the third API call, due to the below error, the data that is being shown previously disappears which is bad.
D/Volley: [380] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://example.com/api/search/getTwitterData?limit=10&tag=JavaScript 0x865f5dc2 NORMAL 3> [lifetime=6683], [size=10543], [rc=200], [retryCount=0]
How do I make concurrent API GET calls using Volley without losing the data on UI. Could anyone please guide me?
Here are excerpts from my code.
public class StaggeredSearchActivity extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_staggered_search);
requestQueue = Volley.newRequestQueue(this);
Intent intent = getIntent();
String searchText = intent.getStringExtra("searchText");
// Three concurrent API GET Calls
getMediumData(searchText);
getExampleData(searchText);
getGoogleData(searchText);
recyclerView = findViewById(R.id.staggered_recycler_view);
staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
}
ArrayList<StaggeredCustomCard> dataset = new ArrayList<>();
private void getMediumData(String searchText) {
progressBar = findViewById(R.id.progressBar);
progressBar.setVisibility(View.VISIBLE);
String url = UrlConstants.getUrl() + searchText;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
progressBar.setVisibility(View.INVISIBLE);
JSONArray array = response.getJSONArray("mediumposts");
...
dataset.add(new StaggeredCustomCard(user, userpost, postdate));
}
staggeredGridAdapter = new StaggeredGridAdapter(StaggeredSearchActivity.this, dataset);
recyclerView.setAdapter(staggeredGridAdapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO: Handle error
progressBar.setVisibility(View.INVISIBLE);
}
});
jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(
DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 15,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
}
private void getExampleData(String searchText) {
...
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest
(Request.Method.GET, url, null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
try {
...
dataset.add(new StaggeredCustomCard(user, userpost, postdate));
staggeredGridAdapter = new StaggeredGridAdapter(StaggeredSearchActivity.this, dataset);
recyclerView.setAdapter(staggeredGridAdapter);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
...
}
});
jsonArrayRequest.setRetryPolicy(new DefaultRetryPolicy(
DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 15,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonArrayRequest);
}
private void getGoogleData(String searchText) {
...
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
...
dataset.add(new StaggeredCustomCard(user, userpost, postdate));
}
staggeredGridAdapter = new StaggeredGridAdapter(StaggeredSearchActivity.this, dataset);
recyclerView.setAdapter(staggeredGridAdapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
...
}
});
jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(
DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 15,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
}
}
The problem is that you are initializing Adapter every time that's why your data will be lost once a new API call. I prefer below approach so that can help you,
Add Data in ArrayList and notify adapter,
Add this line in onCreate,
staggeredGridAdapter = new StaggeredGridAdapter(StaggeredSearchActivity.this, dataset);
recyclerView.setAdapter(staggeredGridAdapter);
Changes in API Callback Response :
...
dataset.add(new StaggeredCustomCard(user, userpost, postdate));
After loop add below line
staggeredGridAdapter.notifyDataSetChanged();
Changes in Adapter
private ArrayList<StaggeredCustomCard> dataSet;
private Context context;
public MyAdapter(ArrayList<StaggeredCustomCard> dataSet, Context context) {
this.data = data;
this.context = context;
}
Note : Don't create new object on adapter.
The approach just doesn't make a lot of sense.
Once you get a response from one of the three endpoints, you seem to create a new Adapter and attach it to the recycler with a random "notifyDataSetChanged" every time...
Maybe look at using a ViewModel with a service layer and network layer that deal with the business login.
The ViewModel updates/posts a MutableLiveData> when a callback from one of the Network methods responds from the endpoints...merging the three pieces of data.
The activity just observes the ViewModel's MutableLiveData and uses a DiffUtil to update the look/cards in the recycler.
The best way is to register your LiveData in the StaggeredSearchActivity in onCreate method and listen for db changes like you did. In the each success responce save its result to db without LiveData. LiveData in onCreate method will be triggered.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ViewModel viewModel = ViewModelProviders.of(this, factory).get(ViewModel.class);
viewModel.getEntity().observe(this, entity -> {
if (entity != null) {
adapter.notifyDataSetChanged(entity );
}
});
requestQueue = Volley.newRequestQueue(this);
Intent intent = getIntent();
String searchText = intent.getStringExtra("searchText");
// Three concurrent API GET Calls
getMediumData(searchText);
getExampleData(searchText);
getGoogleData(searchText);
recyclerView = findViewById(R.id.staggered_recycler_view);
staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
}
ArrayList<StaggeredCustomCard> dataset = new ArrayList<>();
private void getMediumData(String searchText) {
progressBar = findViewById(R.id.progressBar);
progressBar.setVisibility(View.VISIBLE);
String url = UrlConstants.getUrl() + searchText;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
StaggeredCustomCardDAO.insert();
// TODO just insert to dataBase
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO: Handle error
progressBar.setVisibility(View.INVISIBLE);
}
});
jsonObjectRequest.setRetryPolicy(new
DefaultRetryPolicy(
DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 15,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
}
private void getExampleData(String searchText) {
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest
(Request.Method.GET, url, null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
try {
// TODO just insert to dataBase
StaggeredCustomCardDAO.insert();
} catch (
JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
jsonArrayRequest.setRetryPolicy(new DefaultRetryPolicy(
DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 15,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonArrayRequest);
}
private void getGoogleData(String searchText) {
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// TODO just insert to dataBase
StaggeredCustomCardDAO.insert();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(
DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 15,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
}
class ViewModel extends androidx.lifecycle.ViewModel {
private LiveData<StaggeredCustomCard> entity;
public ViewModel(Repository repository) {
entity = repository.getNetworkData();
}
public LiveData<StaggeredCustomCard> getEntity() {
return entity;
}
}
class Repository {
LiveData<StaggeredCustomCard> getNetworkData() {
LiveData<StaggeredCustomCard> localeData = StaggeredCustomCardDAO .getLocaleData();//... todo Read from data base
return localeData;
}
#Dao
public interface StaggeredCustomCardDAO {
#Query("Select * from tbl_staggeredCustomCard ")
LiveData<StaggeredCustomCard> getLocaleData();
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(List<StaggeredCustomCard> items);
}
}
The data should not disappear due to that error. First thing first I would suggest you to check maybe you clear your dataset somewhere or your screen is getting recreated.
Secondly I would recommend you to move from Volley since it is quite outdated from modern techniques library that requires a lot of attention to details. Use Retrofit - it is modern, powerful and community approved library. Using it you will be sure that all the requests you want to be async are async and all the responses are handled well.
Also I would suggest you not to create adapter each time you load data but use one adapter and add data to it and them use notifyDataSetChanged() to reload list with relevant data.
First way : firstly i would suggest you to make a central request queue.
public class AppController extends Application {
public static final String TAG = AppController.class
.getSimpleName();
private RequestQueue mRequestQueue;
private static AppController mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized AppController getInstance() {
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
// set the default tag if tag is empty
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getRequestQueue().add(req);
}
public <T> void addToRequestQueue(Request<T> req) {
req.setTag(TAG);
getRequestQueue().add(req);
}
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
then add your desired requests to the queue
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq);
Second way :
Create a Generic Volley class and a Interface, Use the interface to get success and failure responds.
Step 1 Create a separate Volley class
Step 2 Create a interface for accessing the response from volley class
Step 3 create new object for the class and send required parameters
new PostVolleyJsonRequest(TestVolley.this, TestVolley.this(interfcae), "Submit", url, params);
Context of the class
Interface for sending Success and failure responds
Type of request to identify on success
url (mandatory)
Param (optional) for GET no need
Generic volley class
public class PostVolleyJsonRequest {
private String type;
private Activity act;
private VolleyJsonRespondsListener volleyJsonRespondsListener;
private String networkurl;
private JSONObject jsonObject = null;
private JSONObject params;
public PostVolleyJsonRequest(Activity act, VolleyJsonRespondsListener volleyJsonRespondsListener, String type, String netnetworkUrl,JSONObject params) {
this.act = act;
this.volleyJsonRespondsListener = volleyJsonRespondsListener;
this.type = type;
this.networkurl = netnetworkUrl;
this.params = params;
sendRequest();
}
private void sendRequest() {
Log.d("url", "url" + networkurl);
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.POST,networkurl,params,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.e("response", "response " + response);
volleyJsonRespondsListener.onSuccessJson(response, type);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
try {
NetworkResponse response = error.networkResponse;
Log.e("response", "response " + response);
if (response != null) {
int code = response.statusCode;
String errorMsg = new String(response.data);
Log.e("response", "response" + errorMsg);
try {
jsonObject = new JSONObject(errorMsg);
} catch (JSONException e) {
e.printStackTrace();
}
String msg = jsonObject.optString("message");
volleyJsonRespondsListener.onFailureJson(code, msg);
} else {
String errorMsg = error.getMessage();
volleyJsonRespondsListener.onFailureJson(0, errorMsg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
jsObjRequest.setRetryPolicy(new DefaultRetryPolicy(
600000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
RequestQueue requestqueue = Volley.newRequestQueue(act);
requestqueue.add(jsObjRequest);
}
}
Use the interface to get responds message
public interface VolleyJsonRespondsListener {
public void onSuccessJson(JSONObject result, String type);
public void onFailureJson(int responseCode, String responseMessage);
}
In your class where you want to include multiple request
public class TestVolley extends AppCompatActivity implements VolleyJsonRespondsListener{
//Your class code goes here
//network request
try {
//parameters
//Context,Interface,Type(to indentify your responds),URL,parameter for your request
//request 1
new PostVolleyJsonRequest(TestVolley.this, TestVolley.this, "Submit", url, params);
//request 2
new PostVolleyJsonRequest(TestVolley.this, TestVolley.this, "AccessData", url_2, params_2);
} catch (Exception e) {
e.printStackTrace()
}
//Methods from Interface
#Override
public void onSuccessJson(JSONObject result, String type) {
//Based on the Type you send get the responds and parse it
switch (type) {
case "Submit":
try {
parseSubmit(result);
} catch (Exception e) {
Am new to android and i have just checked out volley android library and i want to use it in my custom http request bu this fails with error in android studio at .getInstance
I have tried the following
So am using android studio and have the following folder structure
com.geowan .....
frontend
1.LoginActivity
helpers
ApiSingleTon
So in my ApiSingleton i have
public class ApiSingleton {
private static ApiSingleton mInstance;
private RequestQueue mRequestQueue;
private static Context mCtx;
private ImageLoader mImageLoader;
private ApiSingleton(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue();
....stuff copy pasted from volley docs on IMage disc cache loader
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
Now to my java login code i have
ApiSingleton singleton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
login_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
trylogin(); //login method
}
});
}
tryLogin(){ //trying to emulate a http request
//proceed with authentication
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, loginurl, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i(TAG, response.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO: Handle error
Log.i(TAG, error.toString());
}
});
}
singleton.getInstance(this).addToRequestQueue(jsonObjectRequest); //fails
The above throws an error at
singleton.getInstance(this)
Where could i be going wrong.
First I guess you Need To Read More About Singleton
Second
singleton.getInstance(this)
this Means You Have A Function Called getInstance return the class type in your class
So I guess You Need to Add this
public static synchronized AppSingleton getInstance(Context context) {
if (mAppSingletonInstance == null) {
mAppSingletonInstance = new AppSingleton(context);
}
return mAppSingletonInstance;
}
I am making a volley String request from a separate class and return the result to main activity
public class FetchFlages {
Context context;
String
placeurl="https://maps.googleapis.com/maps/api/place/textsearch/json
query=";
String myapi = "&key=AIzaSyBuI5wpF733jBS8s7HzjybE1rYAp1hA5tA";
RequestQueue requestQueue;
String abc=null;
public FetchFlages(Context context) {
this.context = context;
requestQueue = Volley.newRequestQueue(context);
}
public String getPhotoReference(){
String url = placeurl +"China"+myapi;
StringRequest objectRequest = new StringRequest(Request.Method.GET, url,
new Listener<String>() {
#Override
public void onResponse(String response) {
abc = response;
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Volly Error",error.toString());
}
});
requestQueue.add(objectRequest);
return abc;
}
}
and in main Class
FetchFlages fetchFlages = new FetchFlages(this);
flag = fetchFlages.getPhotoReference();
String g = flag;
But i can't get any value from that...the value of abc always return null
and
When i run debugger then debugger not comes neither on Volley on Response Listener method and nor on Error Listener Method...Please help me..
This is because as soon as getPhotoReference() is called, its returning the value. The network call is still running. Create a listener and call the listener method on onRespose
Sample pseudo code:
CustomListener.java
public interface CustomListener{
void onVolleyResponse(String response);
}
FetchFlages.java
public class FetchFlages {
Context context;
String placeurl="https://maps.googleapis.com/maps/api/place/textsearch/jsonquery=";
String myapi = "&key=AIzaSyBuI5wpF733jBS8s7HzjybE1rYAp1hA5tA";
RequestQueue requestQueue;
CustomListener listener = null; //Your listener instance
public FetchFlages(Context context, CustomListener listener) {
this.context = context;
this.listener = listener;
requestQueue = Volley.newRequestQueue(context);
}
public void getPhotoReference(){
String url = placeurl +"China"+myapi;
StringRequest objectRequest = new StringRequest(Request.Method.GET, url,
new Listener<String>() {
#Override
public void onResponse(String response) {
listener.onVolleyResponse(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Volly Error",error.toString());
}
});
requestQueue.add(objectRequest);
}
}
Now in your main activity,
FetchFlages fetchFlages = new FetchFlages(this, new CustomListener() {
#Override
public void onVolleyResponse(String response) {
//response is your response
}
});
fetchFlages.getPhotoReference()
Use interface Method like:
public class FetchFlages {
Context context;
String placeurl = "https://maps.googleapis.com/maps/api/place/textsearch/json?query=";
String myapi = "&key=AIzaSyBuI5wpF733jBS8s7HzjybE1rYAp1hA5tA";
RequestQueue requestQueue;
IResult result;
public FetchFlages(Context context, IResult result) {
this.context = context;
requestQueue = Volley.newRequestQueue(context);
this.result = result;
}
public void getPhotoReference() {
String url = placeurl + "China" + myapi;
StringRequest objectRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
result.notifySuccess(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Volly Error", error.toString());
result.notifyError(error);
}
});
requestQueue.add(objectRequest);
}
public interface IResult {
public void notifySuccess(String response);
public void notifyError(VolleyError error);
}
and call it:
FetchFlages fetchFlages = new FetchFlages(this, new IResult() {
#Override
public void notifySuccess(String response) {
//response here
Log.e("responce",response);
}
#Override
public void notifyError(VolleyError error) {
//error here
}
});
fetchFlages.getPhotoReference()
I am trying to create a register activity which uses volley and PHP to connect to mySQL. I have attached some of the code. The code works perfectly fine till i try to get the response back from the Database. While using StringRequest, the control is not entering this section of the code. How can i fix this problem? Please Help.
public class RegisterActivity extends AppCompatActivity {
String rurl = "http://102.160.2.104/register.php";
String message;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
final EditText etName = (EditText) findViewById(R.id.etName);
....
final EditText weig = (EditText) findViewById(R.id.weight);
final Button bRegister = (Button) findViewById(R.id.bRegister);
bRegister.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String name = etName.getText().toString();
final String username = etUsername.getText().toString();
...
if(!(conpassword.equals(password))){
etPassword.setText("");
etconpas.setText("");
Toast.makeText(getApplicationContext(),"Passwords don't match",Toast.LENGTH_LONG).show();
}
//The problem arises over here as it does not enter the onResponse() method.
StringRequest stringRequest = new StringRequest(Request.Method.POST, rurl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray jsonArray = new JSONArray(response);
JSONObject jsonObject = jsonArray.getJSONObject(0);
message = jsonObject.getString("message");
fin();
} catch (JSONException e) {
System.out.println("hhellooo");
e.printStackTrace();
}
}
private void fin() {
System.out.println(message);
if(message.equals("User already exists")){
etName.setText("");
etPassword.setText("");
contact.setText("");
etUsername.setText("");
age.setText("");
heig.setText("");
weig.setText("");
Toast.makeText(getApplicationContext(),"User already Exists",Toast.LENGTH_LONG).show();
}
else
{
Intent intent = new Intent(RegisterActivity.this,MainActivity.class);
startActivity(intent);
finish();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<>();
params.put("name",name);
params.put("username",username);
params.put("password",password);
params.put("value", finalValue);
params.put("phone", String.valueOf(phone));
params.put("years", String.valueOf(years));
params.put("height", String.valueOf(height));
params.put("weight", String.valueOf(weight));
return params;
}
};
MySingleton.getInstance(RegisterActivity.this).addtoRQ(stringRequest);
}
});
}
The MySingleton class file to add the request into the queue.
class MySingleton {
private static MySingleton mInstance;
private static RequestQueue requestQueue;
private Context context;
private MySingleton(Context ctx) {
context = ctx;
requestQueue = getRequestQueue();
}
private RequestQueue getRequestQueue() {
if(requestQueue==null)
{
requestQueue = Volley.newRequestQueue(context.getApplicationContext());
}
return requestQueue;
}
static synchronized MySingleton getInstance(Context con){
if(mInstance==null)
{
mInstance = new MySingleton(con);
}
return mInstance;
}
<T>void addtoRQ(Request<T> request) {
requestQueue.add(request);
}
I think your request is not being sent because you haven't added it to a request queue.
RequestQueue mRequestQueue;
// Instantiate the cache
Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap
// Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack());
// Instantiate the RequestQueue with the cache and network.
mRequestQueue = new RequestQueue(cache, network);
// Start the queue
mRequestQueue.start();
<Your request setup>
// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
From: Android Developer
I am making an app that makes a JsonObjectRequest and retrieves a JSON data from an URL using the Volley Networking Library for android.
AppController.java
public class AppController extends AppCompatActivity {
public static final String TAG = AppController.class.getSimpleName();
private RequestQueue mRequestQueue;
private static AppController mInstance;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInstance = this;
}
public static synchronized AppController getInstance(){
return mInstance;
}
public RequestQueue getRequestQueue(){
if(mRequestQueue == null){
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
req.setTag(TAG);
getRequestQueue().add(req);
}
}
Method in MainActivity.class
private void makeJSONObjectRequest() {
showDialog();
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
urlJsonObj, (String) null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, response.toString());
try {
//Parsing JSON Object response
String name = response.getString("name");
String email = response.getString("email");
JSONObject phone = response.getJSONObject("phone");
String home = phone.getString("home");
String mobile = phone.getString("mobile");
jsonResponse = "";
jsonResponse += "Name: " + name + "\n\n";
jsonResponse += "Email: " + email + "\n\n";
jsonResponse += "Home: " + home + "\n\n";
jsonResponse += "Mobile: " + mobile + "\n\n";
txtResponse.setTag(jsonResponse);
}
catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
hideDialog();
}
},
new ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
VolleyLog.d(TAG+"Error:"+ volleyError.getMessage());
Toast.makeText(getApplicationContext(), volleyError.getMessage(), Toast.LENGTH_SHORT).show();
hideDialog();
}
});
/*THE ERROR OCCURS HERE! */
//adding request to the RequestQueue
AppController.getInstance().addToRequestQueue(jsonObjReq);
}
It gives the following error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.h8pathak.volleyjson.AppController.addToRequestQueue(com.android.volley.Request)' on a null object reference
How can I rectify this code?
Your AppController class needs to extend Application class instead of the AppCompatActivity class.
And remember to update your Manifest as well. ie. Add this class in your AndroidManifest.xml using name attribute for <application> tag.
<application
android:name=".AppController"/>
i think you should create the "AppController" like this :
public class AppController {
private static AppController mInstance;
private RequestQueue mRequestQueue;
private static Context mCtx;
private AppController(Context context){
mCtx = context;
mRequestQueue = getRequestQueue();
}
public static synchronized AppController getInstance(Context context) {
if (mInstance == null) {
mInstance = new AppController(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(#NonNull final Request<T> request) {
getRequestQueue().add(request);
}
public <T> void addToRequestQueueWithTag(#NonNull final Request<T> request, String tag) {
request.setTag(tag);
getRequestQueue().add(request);
}
}
and the MainActivity.class
//adding request to the RequestQueue
AppController.getInstance(this).addToRequestQueue(jsonObjReq);
you can't use an Activity like a Singleton. An Activity is a screen of your app and it could be in different states during the usage of your app. You are also leaking it, since you keep a static reference to it. For your purpose, if you need a Context, extend Application instead of AppCompatActivity, and register it in your Manifest.
Don't you forget to initialize the RequestQueue Object. You need to initialize the RequestQueue inside the onCreate method, like you can see in the example:
(Else when you call request.add(jsonObjectRequest) the application will try to reference the null object)
RequestQueue request;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//request qwe
request= Volley.newRequestQueue(this);
}