There I am getting data from SQLite and send it to the server using Volley.
for now, I am sending all the data at a time.
I just want to know how can I create a queue that first data of one vehicle, gets its response and then send another one.
cursor=helperClass.readAllData();
if (cursor!=null)
{
while (cursor.moveToNext())
{
modelClass=new ModelClass(cursor.getInt(0),cursor.getString(1),
cursor.getString(2),cursor.getString(3),
cursor.getString(4),cursor.getString(5));
modelClasses.add(modelClass);
}
sizeOfArray=modelClasses.size();
for (int i=0; i<sizeOfArray;i++)
{
name = modelClasses.get(i).getName();
model=modelClasses.get(i).getModelName();
number=modelClasses.get(i).getEngineNumber();
image=modelClasses.get(i).getImageBase64();
hdimage=modelClasses.get(i).getHdimageBase64();
uploadData(name, model, number, image, hdimage);
Toast.makeText(UploadDataServiceClass.this, String.valueOf(sizeOfArray), Toast.LENGTH_SHORT).show();
Toast.makeText(UploadDataServiceClass.this, String.valueOf(i), Toast.LENGTH_SHORT).show();
}
}
uploadData(name,model,number,image,hdimage)
RequestQueue requestQueue=Volley.newRequestQueue(UploadDataServiceClass.this);
StringRequest stringRequest=new StringRequest(Request.Method.POST, showURL, new Response.Listener<String>()
{
#Override
public void onResponse(String response)
{
try
{
Log.d(TAG, "onResponse: " + response);
JSONObject jsonObject = new JSONObject(response);
}
catch (JSONException e)
{
e.printStackTrace();
}
}
}, new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error)
{ }
}
)
{
#Override
protected Map<String, String> getParams()
{
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("name", name);
parameters.put("model", model);
parameters.put("number", number);
parameters.put("image", image);
parameters.put("hdimage", hdimage);
parameters.put("crud_type", "insert");
return parameters;
}
};
requestQueue.add(stringRequest);
You need a Executor Service with singleThreadExecutor to execute your threads one by one
Creates an Executor that uses a single worker thread operating off an unbounded queue. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.) Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time. Unlike the otherwise equivalent newFixedThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads.
but what is Executor Service ?
with a Executor Service you can set the maximum running tasks (1 in your case)
here is a simple tutorials about ThreadPool , Executors and Future
Related
I have two global variables currentTemp and currentHum that are set when Volley's onResponse method is called. My code looks like this:
// Request a string response from the provided URL.
private JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, WEATHER_URL, null, new Response.Listener<JSONObject>() {
public void onResponse(JSONObject response) {
try {
JSONObject main = new JSONObject(response.getString("main"));
currentTemp = main.getString("temp");
currentHum = main.getString("humidity");
Log.i("RES", "Temp: " + main.getString("temp") + " Hum: " + main.getString("humidity"));
} catch (JSONException e) {
e.printStackTrace();
}
}}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(appContext, "An error occurred while retrieving weather info", Toast.LENGTH_LONG).show();
Log.e("ERR", "ERROR RET WEATHER DATA");
}
});
// Call the OpenWeatherMap API and get data such as temperature and humidity
private String getWeatherInfo(String key) {
// Add the request to the RequestQueue to invoke the API
queue.add(jsonObjectRequest);
// Access variables set by Volley's onResponse here.
switch (key) {
case "temp":
return String.valueOf(Float.parseFloat(currentTemp) - 273.15);
case "hum":
return currentHum;
default:
return " ";
}
}
I want to be able to access the values of the global variables set by the onResponse method in the getWeatherInfo method that invoked it. Then pass the values to a switch statement for processing. How do I do it without getting empty values for currentTemp and currentHum?
This work is meant to be done with use of an interface. If you don't know about an interface callbacks then please go through this answer. Which will help you understand interface, and plus point that this will guide you for handling volley response.
Also this is not recommended to take global variables to set any response, rather you can pass your whole JsonObject from volley class. and parse it where you make a call. You can use Gson for parsing the response to your Model or ArrayList.
I have this code below which makes 300 http requests and each request returns 10000 rows from database. Total size of 10000 is approximately 0.4mb. So 300*0.4 = 120mb.
Questions:
How increasing the ThreadPool size for handing requests in Volley, can affect the perfomance in app? I change it to 12, but the execution time and size of data was the same as with 4. Is there any difference at all?
When in creasing the number of Volley threads, does the resulted data increase as well? If had 1 thread the maximum returned data each time would be 0.4mb. But if we had 4, the maximum would be 1.6mb.
Emulator: 4 Cores MultiThread
ExecutorService service = Executors.newFixedThreadPool(4);
RequestQueue queue;
AtomicInteger counter = new AtomicInteger(0);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File cacheDir = new File(this.getCacheDir(), "Volley");
queue = new RequestQueue(new DiskBasedCache(cacheDir), new BasicNetwork(new HurlStack()), 4);
queue.start();
start();
}
public void start(){
String url ="...";
for(int i =0 ; i<300; i++) {
counter.incrementAndGet();
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
method(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("VolleyError", error.toString());
}
});
stringRequest.setTag("a");
queue.add(stringRequest);
}
}
public synchronized void decreased(){
if(counter.decrementAndGet()==0)
start();
}
public void method( String response){
Runnable task = new Runnable() {
#Override
public void run() {
List<Customer> customers= new ArrayList<>();
ObjectMapper objectMapper = new ObjectMapper();
TypeFactory typeFactory = objectMapper.getTypeFactory();
try {
customers= objectMapper.readValue(response, new TypeReference<List<Customer>>() {});
//Simulate database insertion delay
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
decreased();
} catch (IOException e1) {
e1.printStackTrace();
}
}
};
logHeap("");
service.execute(task);
}
Regarding Question 1:
Thread pool with size 4 will be better when compared to 12.
Thread pool size should be in conjunction with number of processors available.
Since the number of processors are limited, app should not spawn unnecessary threads as this may lead to performance problem. As android OS has to manage resource between more threads which will lead to increased wait and actual time for each thread.
Ideally assuming your threads do not have locking such that they do not block each other (independent of each other) and you can assume that the work load (processing) is same, then it turns out that, have a pool size of Runtime.getRuntime().availableProcessors() or availableProcessors() + 1 gives the best results.
Please refer link Setting Ideal size of Thread Pool for more info.
Regarding question 2: If I have understood your question correctly, there should be no change on returned data as thread pool size has no effect on network payload, only wait time and actual time will be changed, when thread pool size value is changed.
This Android app is using Android Studio. The function is to scan and display data from the beacon/eddystone. The app already functions and after the scanning stops, the data saves to the local file. But my problem is when I have to transfer the scanning data to the server, I have to ent it to the back-end server. But I really didn't know what is the best way as I'm a beginner.
Here is the code that the data will transfer to the local data:
private void stopScanning(Button scanButton) {
try {
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
// TODO - OK, what now then?
}
String scanData = logString.toString();
if (scanData.length() > 0)
{
// Write file
fileHelper.createFile(scanData);
// Display file created message.
Toast.makeText(getBaseContext(),
"File saved to:" + getFilesDir().getAbsolutePath(),
Toast.LENGTH_SHORT).show();
scanButton.setText(MODE_STOPPED);
} else {
// We didn't get any data, so there's no point writing an empty file.
Toast.makeText(getBaseContext(),
"No data captured during scan, output file will not be created.",
Toast.LENGTH_SHORT).show();
scanButton.setText(MODE_STOPPED);
}
}
To send Data to a server there are many ways, BUT I PREFER you use Volley Library because it's faster and easier
You can use volley for fetching and sending data ,For example:
//Request serever for JsonObject
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//Your code to proceed with fetched data
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}){
//This is the method used to put params into the body, this what you will have to use for sending post data
#Override
public Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> params = new HashMap<String, String>();
params.put("name","jois");
return params;
}
};
Volley.newRequestQueue(getApplicationContext()).add(request);
compile 'com.mcxiaoke.volley:library:1.0.19' This is the dependice you will have to add in build.gradle file to use volley library
I hope this was helpful, ThankYou
I'm working on a Oauth2 Token system to access my REST API for my Android app. I'm having some problems with the token refreshment part on the client side.
Here is the flow : My app makes a request (with an access Token in parameter) to the server thanks some asynctask ( PostCommentAsyncTask(), AddFriendAsyncTask() etc...), so if the accessToken is valid it's ok, but if it has expired I call another AsyncTask (GetRefreshTokenAsyncTask()) from the onPostExecute() method of the precedent AsyncTask to get new accessToken. Here is the tricky part for me. When I get the new access Token I want to re-execute the initial AsyncTask request to the server. I can't figure out how to do it properly.
example1 :
request PostCommentAsyncTask() --> (acessToken expired) -->GetRefreshTokenAsyncTask()-->request PostCommentAsyncTask()--> (good token)--> Ok
EDIT:
I finally chose to use the Volley library ( no need to use Asynctask anymore ).
As I use JSON Web Token I can check the expire date wich is encoded in the payload of the token.
Here is the isAccessTokenExpired() method to check if the Access Token is not expired before making a request to the server :
public Boolean isAccessTokenExpired(String accessToken){
String[] accessTokenPart = accessToken.split("\\.");
String header =accessTokenPart[0];
String payload =accessTokenPart[1];
String signature =accessTokenPart[2];
try {
byte[] decodedPayload = Base64.decode(payload, Base64.DEFAULT);
payload = new String(decodedPayload,"UTF-8");
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
JSONObject obj = new JSONObject(payload);
int expireDate = obj.getInt("exp");
Timestamp timestampExpireDate= new Timestamp( expireDate);
long time = System.currentTimeMillis();
Timestamp timestamp = new Timestamp(time);
return timestamp.after(timestampExpireDate);
} catch (JSONException e) {
e.printStackTrace();
return true;
}
}
And here is the refreshJsonWebToken() method to get a new pair of Access token/Refresh token from my OAUTH2 server:
public void refreshJsonWebToken(){
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
String refreshToken = settings.getString("refreshToken", null);
final HashMap<String, String> params = new HashMap<String, String>();
params.put("grant_type","refresh_token");
params.put("client_id","client");
params.put("refresh_token",refreshToken);
JsonObjectRequest req = new JsonObjectRequest(URL_OAUTH2, new JSONObject(params), new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
String newRefreshToken = response.getString("refresh_token");
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("accessToken", newAccessToken);
editor.putString("refreshToken", newRefreshToken);
editor.apply();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("grid", "Error: " + error.getMessage());
}
}
});
AppController.getInstance().addToRequestQueue(req);
}
And finnally the getPost() method where I use the precedent methods :
private void getPost(String latitude, String longitude) {
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
String accessToken = settings.getString("accessToken", null);
final HashMap<String, String> params = new HashMap<String, String>();
params.put("action", "getLocalPosts");
params.put("latitude", latitude);
params.put("longitude", longitude);
if (isAccessTokenExpired(accessToken)){
refreshJsonWebToken();
}
settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
accessToken = settings.getString("accessToken", null);
JsonObjectRequest req = new JsonObjectRequest(URL_APP+accessToken, new JSONObject(params), new Response.Listener<JSONObject>() {
//Some code ....
});
AppController.getInstance().addToRequestQueue(req);
}
I think Handler is better in this case because Looper has synchronous message queue which is convenient here. You create a HandlerThread and associate your Handler with it. Then you can call postRunnable on it depending on your needs, e.g. you add PostCommentRunnable, if token has expired you add GetRefreshTokenRunnable and PostCommentRunnable, - they will be executed sequentially.
If you still want to go with AsyncTasks, can you check whether token has expired before launching PostCommentAsyncTask? I think that will a be better design. If you can't, then you can execute them one after another because they work on the same background thread by default, e.g.:
new PostCommentAsyncTask().execute();
class PostCommentAsyncTask extends AsyncTask {
//...
onPostExecute() {
if (tokenExpired) {
new GetRefreshTokenAsyncTask().execute();
new PostCommentAsyncTask().execute(); // this guy will wait till refresh token is executed.
}
}
}
I'm trying to create a login page for my app. I check the credentials by doing a get request to a web server which is tied in to my user database.
public boolean checkCredentials(String email, String password) throws JSONException {
// Make a get request to the server
String url = MyUtils.createLoginUrl(email, password);
JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, url, requestParam, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
successLogin = response.length() > 0;
jsonResponse = response.length() > 0 ? response : null;
//requestPending -= 1;
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
MyUtils.showToast(getBaseContext(), error.getMessage().toString());
//requestPending -= 1;
}
});
SingletonRequestQueue.getInstance(this).addToRequestQueue(jsObjRequest);
//requestPending += 1;
// I WANT THE JOB TO FINISH BEFORE RETURNING FROM THIS FUNCTION
return successLogin;
}
Is there a non-blocking way to do this using the Volley library? Google wasn't giving me much info.
You can't with Volley and you shoudn't with other tools. Long running operations like going to database or to network block the UI thread which is a bad practice since the user can't interact to the UI.
Talking about volley, it does all this job asynchronous in three thread levels:
UI
Cache
Network
See here the schema.
All three levels allows the system to cache the responses and use a pool thread to dispatch all the requests at the same time if enough space and memory.
Some time ago people recommended you to do:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
This avoided the NetworkOnMainThreadException, but as I told you before it is a really bad practice because you will be skipping a bunch of frames by waiting.
I know listeners are a pain, but all we have to live with them in Android Dev.