Volley library vs Android SyncAdapter - android

I've developed an aplication which been using sqlite database. The application needs to comunicate/synchronize (master-master) some database tables after following events:
On application start up
On click on refresh button
In case if uses perform some operation which changes data in the sqlite database
The Android sqlite database do not needs to be synchronized in case if the application is not running. Every sync request needs to be extended of Authorization header. The Volley lib is already integrated in the aplication.
The question is (considering use case above) whould be better to use Volley library for comunication between app and server or implement AsyncAdapter? Is possible to combinate both approaches?

SyncAdapter should use volley for data fetching like this :
public class SyncAdapter extends AbstractThreadedSyncAdapter {
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, final SyncResult syncResult) {
RequestQueue queue = VolleyService.getInstance(this.getContext()).getRequestQueue();
StringRequest request = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// we got the response, now our job is to handle it
try {
//Parse JSON response and Insert/Update data to SQLite DB
} catch (RemoteException | OperationApplicationException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//something happened, treat the error.
}
});
queue.add(request);
}
}
SyncAdapter is used for Syncing data on demand or periodically. On your content resolver you can set type of refresh and period :
ContentResolver.addPeriodicSync(account, "com.android.app", params, 150);
ContentResolver.setSyncAutomatically(account, "com.android.app", true);
Volley service :
public class VolleyService {
private static VolleyService instance;
private RequestQueue requestQueue;
private ImageLoader imageLoader;
private VolleyService(Context context) {
requestQueue = Volley.newRequestQueue(context);
imageLoader = new ImageLoader(requestQueue, new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(20);
#Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
#Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url,bitmap);
}
});
}
public static VolleyService getInstance(Context context) {
if (instance == null) {
instance = new VolleyService(context);
}
return instance;
}
public RequestQueue getRequestQueue() {
return requestQueue;
}
public ImageLoader getImageLoader() {
return imageLoader;
}
}

Sync adapters run asynchronously, so you should use them with the expectation that they transfer data regularly and efficiently, but not instantaneously. If you need to do real-time data transfer, you should use Volley (or basically an AsyncTask or an IntentService). Refer Android documentation. So in your case Volley is more preferable over Sync adapter.

Syncadapter is for handling periodic syncs between server and clientSyncAdapter
Looking at you app needs, i would suggest volley.

Related

Is there an way to access AWS RDS database by StringRequest URL in android app?

I'm very new to server system and have been struggling over making login system work on android app that I'm developing.
I connected RDS database with AWS EC2 server but have no idea how to access to RDS database with app.
Here is class I'm using for server:
public class ValidateRequest extends StringRequest {
final static private String URL = "https://localhost/UserValidate.php";
private Map<String, String> parameters;
// send parameter values to database by posting method
public ValidateRequest(String userID, Response.Listener<String> listener) {
super(Method.POST, URL, listener, null);
parameters = new HashMap<>();
parameters.put("userID",userID);
}
#Override
protected Map<String, String> getParams(){
return parameters;
}
}
When program is executed, it doesn't display any error messages. I'm thinking my URL variable is set wrong but have no idea how to fix it. Can anyone suggest what to do here?
my php files are located under /var/www/html remote site. Any help will be appreciated.
I realize this is a month late but I'm guessing this will be useful for anyone else that has the same problem. This answer assumes you have made the necessary security group settings for the rds instance (like making it accessible publicly, although I would only recommend doing that for development purposes).
This answer uses volley as well albeit using a singleton class for the request queue.
Solution -
1. PHP constants file. (Declare your database constants)
define ('DB_HOST', 'aws rds access point goes here');
define ('DB_USER', 'rds user name goes here ' );
define ('DB_PASSWORD', 'rds password goes here ');
2. PHP Connection file. (Initiate connection)
require_once "constants.php";
$con = new mysqli(DB_HOST,DB_USER,DB_PASSWORD);
if($con)
{
$sql = "SQL Query";
$result = mysqli_query($con,$sql);
//Whatever you echo here will be treated as the response at the android end
//Can be JSON,string etc.
}
3. Java file. (Initiate String request in android)
This is an example of how it would look like if you were trying to login users into your application.
private void login(final String emailText, final String passText) {
final StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),error.toString(),Toast.LENGTH_SHORT).show();
System.out.println("Error is " + error.toString());
}
})
{
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map <String,String> params = new HashMap<String,String>();
params.put(Constants.KEY_EMAIL,emailText);
params.put(Constants.KEY_PASSWORD,passText);
return params;
}
};
MySingleton.getInstance(this).addToRequestQueue(request);
}
4. Java singleton class. (Recommended to use if you're making a lot of requests)
public class MySingleton {
private static MySingleton instance;
private RequestQueue requestQueue;
private ImageLoader imageLoader;
private static Context ctx;
private MySingleton(Context context) {
ctx = context;
requestQueue = getRequestQueue();
imageLoader = new ImageLoader(requestQueue,
new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap>
cache = new LruCache<String, Bitmap>(20);
#Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
#Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
public static synchronized MySingleton getInstance(Context context) {
if (instance == null) {
instance = new MySingleton(context);
}
return instance;
}
public RequestQueue getRequestQueue() {
if (requestQueue == null) {
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
requestQueue = Volley.newRequestQueue(ctx.getApplicationContext());
}
return requestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return imageLoader;
}
}

Volley using StringRequest not calling getParams for sending POST Request Parameters after 1st time

I am facing a problem where my POST request parameters are not going to server after 1st time. I know Volley is using cache mechanism for responses, but in my case my request parameter values can be changed at runtime as i am using pagination in Recyclerview.
So my questions is how can i send Post request parameter every time and wont loose cache mechanism of volley.
I have tried using below ones and get my things done (calling getParams() every-time).. but it loses caches response and i don't want that.
requestQueue.getCache().clear();
stringRequest.setShouldCache(false);
Also have Searched Google and below links but cant find any proper solution. below are the SO links
Volley not calling getParams() for second time
Volley not calling getParams()
Android volley does not calling getParams in POST request
Volley not calling getParams() for standard POST request
Below is my code:
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.e("RES", response);
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("M/d/yy hh:mm a"); //Format of our JSON dates
Gson gson = gsonBuilder.create();
NewsFeedPOJO resultObj = (NewsFeedPOJO) gson.fromJson(response, (Class) NewsFeedPOJO.class);
inCurrPage = Integer.parseInt(resultObj.getPagination().getCurrent_page());
inTotalPage = Integer.parseInt(resultObj.getPagination().getTotal_pages());
inCurrPage++;
arrayList.addAll(resultObj.getNewsFeedList());
if (isFtym) {
isFtym = false;
layoutManager = new LinearLayoutManager(MainActivity.this);
rcNewsFeed.setLayoutManager(layoutManager);
adapter = new NewsFeedAdapter(MainActivity.this, arrayList);
rcNewsFeed.setAdapter(adapter);
} else {
adapter.notifyItemInserted(arrayList.size());
adapter.notifyDataSetChanged();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> map = new HashMap<>();
map.put("user_id", "188");
if (inCurrPage == 0)
map.put("page", "1");
else {
map.put("page", "" + inCurrPage);
}
Log.e("RES", inCurrPage + " PARA");
return map;
}
};
//RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
//requestQueue.add(stringRequest);
//requestQueue.getCache().clear();
//AppController.getInstance().addToRequestQueue(stringRequest);
// stringRequest.setShouldCache(false);
VolleySingleton.getInstance(this).addToRequestQueue(stringRequest);
using below Volley Dependency.
compile 'com.android.volley:volley:1.1.0'
If need more information please do let me know. Thanks in advance. Your efforts will be appreciated.
Did you check your Volley Singleton?
import android.content.Context;
import android.graphics.Bitmap;
import android.util.LruCache;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;
public class VolleySingleton {
private static AppSingleton mAppSingletonInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mContext;
private AppSingleton(Context context) {
mContext = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap>
cache = new LruCache<String, Bitmap>(20);
#Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
#Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
public static synchronized AppSingleton getInstance(Context context) {
if (mAppSingletonInstance == null) {
mAppSingletonInstance = new AppSingleton(context);
}
return mAppSingletonInstance;
}
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(mContext.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req,String tag) {
req.setTag(tag);
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
Or maybe there is another issue in your code...

How to load data from local realm db?

I have populated data from server in UI through realm and volley.
Is it possible to store that data locally and show in UI from local db? And how to do it?
Any example would be very helpful.Thanks.
Actually I am trying to get the data locally after fetching and populating the data from the server like this.
if(realm!=null){
Log.d(AppConstants.TAG, "realm fetching");
RealmResults<SellerProducts> sellerProductItems=realm.where(SellerProducts.class).findAll();
adapter.setData(sellerProductItems);
adapter.notifyDataUpdate();
}else {
//network fetch operation
// getting data
//populating data like this
sellerProductItems= gson.fromJson(products.toString(), new TypeToken<List<SellerProducts>>(){}.getType());
//Products is from server response
realm.beginTransaction();
realm.copyToRealmOrUpdate(sellerProductItems);
realm.commitTransaction();
adapter.setData(sellerProductItems);
adapter.notifyDataUpdate();
}
Is it correct?
To save data in realm create a realm object and do Transaction like this
myRealm.beginTransaction();
// Create an object
Country country1 = myRealm.createObject(Country.class);
country1.setName("Norway");
country1.setPopulation(5165800);
country1.setCode("NO");
myRealm.commitTransaction();
To read the data saved
RealmResults<Country> results1 =
myRealm.where(Country.class).findAll();
for(Country c:results1) {
Log.d("results1", c.getName());
}
For complete information visit
http://code.tutsplus.com/tutorials/up-and-running-with-realm-for-android--cms-25241
No, you're completely wrong. If you're doing it right, realm can never be null at that point in your code.
Anyways it works vaguely like this (based on this):
public class GsonRequest<T extends RealmObject> extends Request<T> {
private final Gson gson = new Gson();
private final Listener<T> listener;
/**
* Make a GET request and return a parsed object from JSON.
*
* #param url URL of the request to make
*/
public GsonRequest(Method method, String url,
Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.listener = listener;
}
#Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
final List<T> result = gson.fromJson(json, new TypeToken<ArrayList<T>>() {}.getType());
Realm realm = null;
try {
realm = Realm.getInstance(realmConfiguration); //get realm config
realm.executeTransaction(new Realm.Transaction() {
for(T t : result) {
realm.copyToRealmOrUpdate(t);
}
});
} finally {
if(realm != null) {
realm.close();
}
}
return Response.success(null, //returning null because
//Realm handles all reload of data on UI thread
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
}
And
Realm realm;
RealmResults<SellerProducts> results;
final RealmChangeListener<RealmResults<SellerProducts>> realmChangeListener;
SellerProductsAdapter adapter;
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
realm = Realm.getInstance(this);
results = realm.where(SellerProducts.class).findAll();
realmChangeListener = new RealmChangeListener<RealmResults<SellerProducts>>() {
#Override
public void onChange(RealmResults<SellerProducts> element) {
adapter.notifyDataSetChanged();
}
}
setContentView(R.layout.retrofit_is_better_than_volley);
ListView whyIsThisNotRecyclerView = (ListView) findViewById(R.id.not_recycler_for_some_reason_view);
adapter = new SellerProductsAdapter(this, results);
whyIsThisNotRecyclerView.setAdapter(adapter);
results.addChangeListener(realmChangeListener);
}
#Override
public void onDestroy() {
if(results != null && results.isValid()) {
results.removeChangeListener(realmChangeListener);
}
if(realm != null) {
realm.close();
}
super.onDestroy();
}
And then something like
GsonRequest<SellerProducts> request = new GsonRequest(Method.GET, url,
new Response.Listener<SellerProducts>() {
#Override
public void onResponse(SellerProducts nullObject) {
// hide dialog or something
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Error: " + error.getMessage()/*, exception? */);
// hide dialog or something
}
});
//add to request queue
If you are planning to bring Realm to your production code, it takes more than what is discussed here, Realm is a major library and there are also some limitations like Realm, RealmObject and RealmResults can not be passed across threads.
To solve this problem, you need a good architecture, where Realm is isolated from rest of the code. Create a realmModel for each jsonModel and a DAO (Data Access Object). All Realm related calculations should be part of DAO, so that none of your code base needs to know about Realm.
Here is an article about Realm best practices with a good architechture https://medium.com/#Viraj.Tank/realm-integration-in-android-best-practices-449919d25f2f
Also a sample project demonstrating Integration of Realm on Android with MVP(Model View Presenter), RxJava, Retrofit, Dagger, Annotations & Testing. https://github.com/viraj49/Realm_android-injection-rx-test

Response coming from Volley the first time only

I'm using Volley to fetch data from server. I have 2 activities, Activity A and B. Both uses Volley and the same Request Queue via a Singleton to fetch data. Everything works fine in Activity A, and when I start Activity B I get Volley's response.
The problem is, if I finish from activity B and move to A, and then start B again, Volley seems to fail to get a response. What am I doing wrong?
My Singleton
public class CustomVolleyRequestQueue {
private static CustomVolleyRequestQueue mInstance;
private static Context mCtx;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private CustomVolleyRequestQueue(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache(
LruBitmapCache.getCacheSize(mCtx)));
}
public static synchronized CustomVolleyRequestQueue getInstance(Context context) {
if (mInstance == null) {
mInstance = new CustomVolleyRequestQueue(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
Cache cache = new DiskBasedCache(mCtx.getCacheDir(), 10 * 1024 * 1024);
Network network = new BasicNetwork(new HurlStack());
mRequestQueue = new RequestQueue(cache, network);
// Don't forget to start the volley request queue
mRequestQueue.start();
}
return mRequestQueue;
}
public ImageLoader getmImageLoader(){
return mImageLoader;
}
}
My Custom request
public class CustomJSONObjectRequest extends JsonObjectRequest{
private Priority mPriority;
public CustomJSONObjectRequest(int method, String url, JSONObject jsonRequest,
Response.Listener<JSONObject> listener,
Response.ErrorListener errorListener) {
super(method, url, jsonRequest, listener, errorListener);
//this.setShouldCache(true);
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json; charset=utf-8");
return headers;
}
#Override
public RetryPolicy getRetryPolicy() {
// here you can write a custom retry policy
return super.getRetryPolicy();
}
public void setPriority(Priority priority) {
mPriority = priority;
}
#Override
public Priority getPriority() {
return mPriority == null ? Priority.NORMAL : mPriority;
}
}
I perform and add the request on the onStart of my Activity B as follows,
protected void onStart() {
super.onStart();
mQueue = CustomVolleyRequestQueue.getInstance(this.getApplicationContext())
.getRequestQueue();
final CustomJSONObjectRequest jsonRequest = new CustomJSONObjectRequest(Request.Method
.GET, url,
new JSONObject(), this, this);
jsonRequest.setTag(REQUEST_TAG);
jsonRequest.setPriority(Request.Priority.HIGH);
mQueue.add(jsonRequest);
setupRecyclerView(rv, rv2, rv3);
}
My activity B Implements the Response Listener, where I simple parse the JSON and display the data on the UI.
I've been going on about this issue for a quite while, I've learned the tips and tricks of other features of Volley, caching, Ignoring requests, going deep to play around with the library and using it with other libraries. Yet, I still fail to see what I could be doing wrong here.
Alright found my solution, and it's quite embarrassing. I was using a static URL to add the GET parameter. Since it was my first time using Volley, I didn't know how to add GET parameters to requests, was supposed to come back to it later on. I forgot.
So basically I am concatenating the GET parameter value the next time I move to the next activity, hence getting a null response from the server since those values don't exist there.
It was too simple to notice, I should have been more careful with my debugging.

No volley response when I access activity again

I have a main page where I fetch a bunch of items from server using Volley and then I load them up on screen. If I click on an item, it should take me to the item page displaying its details which I'm fetching from server again using Volley. The latter (getting details for a single item on the single item page) works only once.
So for example if I access item page the first time, Volley gets me the response, so I can load data to screen. But if I press back or just go back to main page and select another item, Volley fails to give any responses, so the item page is empty. How do I make Volley send request and get response every time I access the Item page? or at least tell me why is it working only the first time?
My singleton class
public class MyApplication extends Application {
private RequestQueue mRequestQueue;
private static MyApplication mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized MyApplication getInstance() {
return mInstance;
}
public RequestQueue getReqQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToReqQueue(Request<T> req, String tag) {
getReqQueue().add(req);
}
public <T> void addToReqQueue(Request<T> req) {
getReqQueue().add(req);
}
public void cancelPendingReq(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
How I make request and deal with response on Item Page, my ReadDataFromDB() method...
private void ReadDataFromDB() {
JsonObjectRequest jreq = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
int success = response.getInt(TAG_SUCCESS);
if (success == 1) {
//parse JSON
JSONObject productJSONObject = response.getJSONObject(TAG_PRODUCTS);
product = new ProdItem (productJSONObject.getString(TAG_PRODUCT_PICTURE), productJSONObject.getString(TAG_PRODUCT_TITLE), productJSONObject.getString(TAG_PRODUCTS_DESCRIPTION),
productJSONObject.getString(TAG_PRODUCTS_DATETIME), productJSONObject.getDouble(TAG_PRODUCTS_RATING),
productJSONObject.getDouble(TAG_PRODUCTS_PRICE), productJSONObject.getInt(TAG_PRODUCT_ID), productJSONObject.getInt(TAG_CAT_ID), productJSONObject.getInt(TAG_PRODUCTS_VIEWS),
productJSONObject.getInt(TAG_PRODUCTS_SHOPID), productJSONObject.getInt(TAG_PRODUCT_POINTS), 1, productJSONObject.getString(TAG_PRODUCTS_SHOPNAME));
} // if ends
//update UI
runOnUiThread(new Runnable() {
#Override
public void run() {
adTitleLBL.setText(product.getProdTitle());
shopNameLBL.setText(product.getShopName());
prodDescriptionLBL.setText(product.getProdDescription());
shopIDLBL.setText(String.valueOf(product.getProdShopID()));
catIDLBL.setText(String.valueOf(product.getMasterCatID()));
prdoIDLBL.setText(String.valueOf(product.getProdID()));
adRating.setRating((float) product.getProdRating());
loadAdImage(product.getProdImage());
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(), "Server is terrible", Toast.LENGTH_SHORT).show();
error.printStackTrace();
}
});
//add request to queue
MyApplication.getInstance().addToReqQueue(jreq);
}
I checked for other questions here, but they're not what I'm looking for. I'm probably using Volley wrong, just need to know what I'm missing or what is it.

Categories

Resources