In an application that I'm currently working on there is a huge need to determine user country as fast as possible and as reliable as possible. I have decided to rely on three ways for finding user country; each one has its advantages and disadvantages:
Android inner methods to get the SIM country.
GeoCoding.
IP to Location API.
Here are the three pieces of code:
1. Android inner methods to get the SIM country:
public static String getUserCountry(Context context) {
try {
final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
final String simCountry = tm.getSimCountryIso();
if (simCountry != null && simCountry.length() == 2) { // SIM country code is available
CupsLog.d(TAG, "getUserCountry, simCountry: " + simCountry.toLowerCase(Locale.US));
return simCountry.toLowerCase(Locale.US);
}
else if (tm.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) { // device is not 3G (would be unreliable)
String networkCountry = tm.getNetworkCountryIso();
if (networkCountry != null && networkCountry.length() == 2) { // network country code is available
CupsLog.d(TAG, "getUserCountry, networkCountry: " + networkCountry.toLowerCase(Locale.US));
return networkCountry.toLowerCase(Locale.US);
}
}
}
catch (Exception e) { }
return null;
}
2. GeoCoding:
public static void getCountryCode(final Location location, final Context context) {
CupsLog.d(TAG, "getCountryCode");
AsyncTask<Void, Void, String> countryCodeTask = new AsyncTask<Void, Void, String>() {
final float latitude = (float) location.getLatitude();
final float longitude = (float) location.getLongitude();
List<Address> addresses = null;
Geocoder gcd = new Geocoder(context);
String code = null;
#Override
protected String doInBackground(Void... params) {
CupsLog.d(TAG, "doInBackground");
try {
addresses = gcd.getFromLocation(latitude, longitude, 10);
for (int i=0; i < addresses.size(); i++)
{
if (addresses.get(i) != null && addresses.get(i).getCountryCode() != null)
{
code = addresses.get(i).getCountryCode();
}
}
} catch (IOException e) {
CupsLog.d(TAG, "IOException" + e);
}
return code;
}
#Override
protected void onPostExecute(String code)
{
if (code != null)
{
CupsLog.d(TAG, "getCountryCode :" + code.toLowerCase());
UserLocation.instance.setCountryCode(code.toLowerCase());
CookieUtil.formatLangueageAndLocationCookie();
CookieUtil.instance.instantateCookieUtil(context);
}
}
};
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
CupsLog.d(TAG, "countryCodeTask.execute();");
countryCodeTask.execute();
} else {
CupsLog.d(TAG, "countryCodeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);");
countryCodeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
3. IP to Location API:
private void getUserCountryByIp() {
AsyncHttpClient client = new AsyncHttpClient();
client.setCookieStore(CookieUtil.instance.getPersistentCookieStore());
String userCountryApi = "http://ip-api.com/json";
CupsLog.i(TAG, "country uri: " + userCountryApi);
client.get(userCountryApi, new JsonHttpResponseHandler() {
#Override
public void onSuccess(JSONObject orderResponseJSON) {
CupsLog.i(TAG, "onSuccess(JSONObject res)");
try
{
CupsLog.i(TAG, "JsonResponse: "+ orderResponseJSON.toString(3));
String tempString = orderResponseJSON.getString("countryCode");
if (tempString != null)
{
//countryCodeFromIpApi = tempString.toLowerCase();
UserLocation.instance.setCountryCode(tempString.toLowerCase());
CookieUtil.formatLangueageAndLocationCookie();
CookieUtil.instance.instantateCookieUtil(LoginActivity.this);
isGotCountryFromIp = true;
}
} catch (JSONException e) {
CupsLog.i(TAG, "JSONException: " + e);
}
}
#Override
public void onFailure(Throwable arg0, JSONObject orderResponseJSON) {
CupsLog.i(TAG, "onFailure");
try {
CupsLog.i(TAG, "JsonResponse: "+ orderResponseJSON.toString(3));
} catch (JSONException e) {
CupsLog.i(TAG, "JSONException: " + e);
}
}
#Override
public void onFinish() {
CupsLog.i(TAG, "onFinish");
super.onFinish();
}
});
}
Now I have those 3 methods that are working great, my problem is more of a Java problem. The first method give me the result right away, while the two others (2,3) are potentiality long running tasks. what more is that the first option is the most not reliable one, as users can travel to different countries with the SIM card. The second is more reliable but still sometimes does not returns an country (depending on the location of the user). The third one is the one that I found to be the most reliable one, but the most long as well.
The question: knowing this information, how would I construct a method that uses those 3 methods in the right order for reliability stand point and considering the long running tasks factor?
Unfortunately there is no really reliable way to determine the physical location of a user (e.g. his/her cellphone) because:
SIM card might be bought and/or manufactured in other country;
Geocoding (which is AFAIU based on GPS/GLONASS coordinates) might give wrong (~10m) results or no results at all if user disabled it or no satellites are visible (underground, for example);
Resolving country by IP might also give you wrong results, for example because of using VPN;
So my advice would be to ask user, which country he is currently in and willing to "tell" you so.
Related
I was wondering if there is a better way to code this piece of code:
private void getLatitudeAndLongitudeFromZipcode() {
String zipcode = mSharedPreferences.getString("Zipcode", "");
try {
List<Address> address = geocoder.getFromLocationName(zipcode, 1);
if ((address != null ? address.size() : 0) > 0) {
Address first = address.get(0);
mLatitude = first.getLatitude();
mLongitude = first.getLongitude();
mCurrentLocationName = getLocationAsName();
mSharedPreferences.edit().putLong("oldLat", Double.doubleToRawLongBits(mLatitude))
.apply();
mSharedPreferences.edit().putLong("oldLong", Double.doubleToRawLongBits(mLongitude))
.apply();
} else {
getOldZipcodeLocation();//duplicate method call
}
} catch (IOException e) {
getOldZipcodeLocation();//duplicate method call
e.printStackTrace();
}
}
Basic idea is that if they don't have internet and an exception is thrown, I want to get the old coordinates from storage. However, I also want to get the old coordinates if they are currently in a place that doesn't give them coordinates. For example, if the geocoder returns null. What bothers me is the duplicate method call in the else block and catch block. Any way to make this code cleaner? I'll take any other tips as well!
Yes you can , 1st get address through IOException separately , then use address in your if..else statement . that's it .
private void getLatitudeAndLongitudeFromZipcode() {
String zipcode = mSharedPreferences.getString("Zipcode", "");
List<Address> address = null;
try {
address = new Geocoder(this).getFromLocationName(zipcode, 1);
} catch (IOException e) {
e.printStackTrace();
}
if ((address != null ? address.size() : 0) > 0) {
Address first = address.get(0);
mLatitude = first.getLatitude();
mLongitude = first.getLongitude();
mCurrentLocationName = getLocationAsName();
mSharedPreferences.edit().putLong("oldLat", Double.doubleToRawLongBits(mLatitude))
.apply();
mSharedPreferences.edit().putLong("oldLong", Double.doubleToRawLongBits(mLongitude))
.apply();
} else {
getOldZipcodeLocation();
}
}
In the Geocoder.java class there is the below method
public List<Address> getFromLocation(double latitude, double longitude, int maxResults)
throws IOException {
if (latitude < -90.0 || latitude > 90.0) {
throw new IllegalArgumentException("latitude == " + latitude);
}
if (longitude < -180.0 || longitude > 180.0) {
throw new IllegalArgumentException("longitude == " + longitude);
}
try {
List<Address> results = new ArrayList<Address>();
String ex = mService.getFromLocation(latitude, longitude, maxResults,
mParams, results);
if (ex != null) {
throw new IOException(ex);
} else {
return results;
}
} catch (RemoteException e) {
Log.e(TAG, "getFromLocation: got RemoteException", e);
return null;
}
}
Here getFromLocation is the member function of the class. So to call this function can't we simply call that as List<Address> address = Geocoder.getFromLocation(//the required parameters). I know this won't work and to make it work we need to create an object of Geocoder class. So can anyone please explain why the object creation is necessary, I am bit confused as I had seen in some cases functions are called by directly using their class names
I have an android app with a donation system, these donations are integrated products that are automatically consumed to let the users donate more than once.
I need to know if there is some way to find out which users have donated at least once.
I appreciate any help.
EDIT:
In addition to Dima Kozhevin's answer... I used this code in onServiceConnected() event inside startSetup() method from my IabHelper.
Bundle purchaseHistoryBundle = mService.getPurchaseHistory(6,BuildConfig.APPLICATION_ID, "inapp", null, new Bundle());
ArrayList<String> mListItems = purchaseHistoryBundle.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
if (mListItems != null){
if (mListItems.size()>0){
//User have donated at least once
}else{
//User never donated
}
}
You should use getPurchaseHistory() method.
Signature of the method:
Bundle getPurchaseHistory(int apiVersion,
String packageName,
String type,
String continuationToken,
Bundle extraParams);
Your code will look like this:
Bundle purchaseHistoryBundle = service.getPurchaseHistory(6, BuildConfig.APPLICATION_ID, "subs", null, new Bundle());
In addition, guy from Google suggests in that example use queryPurchaseHistoryAsyncmethod:
This library also allows to get purchase history even though it's not
demonstrated inside the sample. Please use this method to get all
purchases history (up to 1 record per SKU).
I assume you have integrated the AIDL file and the in app billing code files for IabHelper etc.. following Android instructions for basic billing handling.
Once you are already handling billing you simply query the inventory to see if they have purchased it or not. I tend to do this in a singleton class called PurchaseManager.
I will share that class with you below. However, I only have one package, so I hard coded that package in my check for pro purchased, to be more dynamic you may want to do those checks in the calling class or in a loop.
/**
* Created by App Studio 35 on 9/28/17.
*/
public class PurchaseManager {
/*///////////////////////////////////////////////////////////////
// MEMBERS
*////////////////////////////////////////////////////////////////
private static PurchaseManager mInstance;
private static final String TAG = Globals.SEARCH_STRING + PurchaseManager.class.getSimpleName();
private static String PUBLIC_LICENSING_KEY = "<YOUR PUBLIC KEY HERE>";
private static final String PRO_PACKAGE_SKU = "pro_package_level_1";
public static final int RESULT_KEY_PURCHASE = 9876;
private IabHelper mHelper;
private Boolean mIABServiceIsAvailable = false;
private static String mAndroidId;
/*///////////////////////////////////////////////////////////////
// CONSTRUCTOR
*////////////////////////////////////////////////////////////////
private PurchaseManager(){}
public static synchronized PurchaseManager getInstance(){
if(mInstance == null){
mInstance = new PurchaseManager();
}
return mInstance;
}
/*///////////////////////////////////////////////////////////////
// EXTERNAL METHODS
*////////////////////////////////////////////////////////////////
public boolean getIsIABServiceAvailable(){
return mIABServiceIsAvailable;
}
public void checkForPurchasesOrTrials(final Context context, final IPurchaseSyncListener listener) {
mHelper = new IabHelper(context, PUBLIC_LICENSING_KEY);
if(!BuildConfig.DEBUG) {
mHelper.enableDebugLogging(true, TAG);
}
//Setup Purchase Processor
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
#Override
public void onIabSetupFinished(IabResult result) {
mIABServiceIsAvailable = result.isSuccess();
if (!result.isSuccess()) {
String error = "Problem setting up In-app Billing: " + result;
A35Log.d(TAG, error);
notifyUserOfError(listener, error);
return;
}
ArrayList<String> skus = new ArrayList<String>();
skus.add(PRO_PACKAGE_SKU);
checkExistingPurchasesForSkus(context, listener, skus);
}
});
}
public void attemptPurchaseOfPro(Activity activity, final IPurchaseConsumeListener listener){
mHelper.launchPurchaseFlow(activity, PRO_PACKAGE_SKU, RESULT_KEY_PURCHASE, new IabHelper.OnIabPurchaseFinishedListener() {
#Override
public void onIabPurchaseFinished(IabResult result, Purchase info) {
if (result.isSuccess()) {
mHelper.consumeAsync(info, new IabHelper.OnConsumeFinishedListener() {
#Override
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (result.isSuccess()) {
Log.d(TAG, "Successfully synced purchases" + result);
notifyUserOfPurchaseSuccess(listener, purchase, result, PRO_PACKAGE_SKU);
} else {
String error = "Could not sync purchases. Error: " + result;
Log.d(TAG, error);
notifyUserOfPurchaseError(listener, error, result, PRO_PACKAGE_SKU);
}
}
});
}else{
notifyUserOfPurchaseError(listener, "Purchase Incomplete", result, PRO_PACKAGE_SKU);
}
}
});
}
/*///////////////////////////////////////////////////////////////
// INTERNAL METHODS
*////////////////////////////////////////////////////////////////
private void checkExistingPurchasesForSkus(final Context context, final IPurchaseSyncListener listener, final ArrayList<String> skus) {
mHelper.queryInventoryAsync(true, skus, new IabHelper.QueryInventoryFinishedListener() {
#Override
public void onQueryInventoryFinished(IabResult result, Inventory inv) {
if (!result.isSuccess()) {
String error = "Unable to query inventory. Error: " + result;
A35Log.d(TAG, error);
notifyUserOfError(listener, error);
return;
}
ArrayList<Purchase> purchaseList = new ArrayList<Purchase>();
if (inv.getPurchase(PRO_PACKAGE_SKU) != null) {
purchaseList.add(inv.getPurchase(PRO_PACKAGE_SKU));
}
if (!purchaseList.isEmpty()) {
A35Log.d(TAG, "Attempting to sync purchases" + result);
attemptToSyncPurchases(context, listener, purchaseList);
} else {
A35Log.d(TAG, "We didn't see any purchases, attempting to check for Trials");
if(mAndroidId == null) {
getAdvertiserIDThenCheckTrialsForDevice(context, listener, skus);
}else{
checkTrialsForDeviceID(context, listener, skus);
}
}
}
});
}
private void attemptToSyncPurchases(final Context context, final IPurchaseSyncListener listener, final ArrayList<Purchase> purchaseList) {
for(Purchase purchase : purchaseList) {
mHelper.consumeAsync(purchase, new IabHelper.OnConsumeFinishedListener() {
#Override
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (result.isSuccess()) {
Log.d(TAG, "Successfully synced purchases" + result);
notifyUserOfPurchasedPackages(listener, purchaseList);
} else {
String error = "Could not sync purchases. Error: " + result;
Log.d(TAG, error);
notifyUserOfError(listener, error);
}
}
});
}
}
private void getAdvertiserIDThenCheckTrialsForDevice(final Context context, final IPurchaseSyncListener listener, final ArrayList<String> skus){
//If no purchases then check for trial times for skus get Advertiser ID for identifying device
new GetAdvertiserIDAsyncTask(context){
#Override
protected void onPostExecute(String advertisementID) {
mAndroidId = (advertisementID == null ? "unknownID" : advertisementID);
checkTrialsForDeviceID(context, listener, skus);
}
}.execute();
}
private void checkTrialsForDeviceID(final Context context, final IPurchaseSyncListener listener, final ArrayList<String> skus){
//Use device ID to check for Trials
new GetTrialTimeAsyncTask(context, mAndroidId){
#Override
protected void onPostExecute(ActiveTrialsListResponseModel activeTrialsListResponseModel) {
super.onPostExecute(activeTrialsListResponseModel);
A35Log.v(TAG, "onPostExecute");
if(activeTrialsListResponseModel.getErrorMessage() != null) {
String error = "Error getting trial time: " + activeTrialsListResponseModel.getErrorMessage();
A35Log.e(TAG, error);
notifyUserOfError(listener, error);
return;
}
notifyUserOfTrialCheckCompleteForPackages(listener, activeTrialsListResponseModel);
}
}.execute();
}
/*///////////////////////////////////////////////////////////////
// NOTIFY USER CALLBACKS
*////////////////////////////////////////////////////////////////
private void notifyUserOfError(IPurchaseSyncListener listener, String message){
if(listener != null){
listener.onPurchaseManagerError(message);
}
}
private void notifyUserOfPurchasedPackages(IPurchaseSyncListener listener, ArrayList<Purchase> purchasedSkus){
if(listener != null){
listener.onPackagePurchased(purchasedSkus);
}
}
private void notifyUserOfTrialCheckCompleteForPackages(IPurchaseSyncListener listener, ActiveTrialsListResponseModel activeTrialsListResponseModel){
if(listener != null){
listener.onTrialRetrievalComplete(activeTrialsListResponseModel);
}
}
private void notifyUserOfPurchaseSuccess(IPurchaseConsumeListener listener, Purchase purchase, IabResult result, String sku){
if(listener != null){
listener.onPurchaseSuccessful(purchase, result, sku);
}
}
private void notifyUserOfPurchaseError(IPurchaseConsumeListener listener, String message, IabResult result, String sku){
if(listener != null){
listener.onPurchaseFailure(message, result, sku);
}
}
/*///////////////////////////////////////////////////////////////
// INTERFACE
*////////////////////////////////////////////////////////////////
public interface IPurchaseSyncListener {
void onPackagePurchased(ArrayList<Purchase> sku);
void onTrialRetrievalComplete(ActiveTrialsListResponseModel activeTrialsListResponseModel);
void onPurchaseManagerError(String message);
}
public interface IPurchaseConsumeListener {
void onPurchaseSuccessful(Purchase purchase, IabResult result, String sku);
void onPurchaseFailure(String message, IabResult result, String sku);
}
}
Three things to note about my shared code as well.
I am using trials for my pro package so that is my async task to confirm that they are not in trials for any package, you won't do that piece.
I do not have authenticated users, I rely on the device advertiser id for knowing if they have a trial or not, this won't matter to you. Also advertiser ids can be reset by the user in Google Settings if they are crafty enough they can figure out how to get another free trial, but I'm not that concerned about the power user going that far to save a dollar haha.
I did my startup inside the checkfor purchases method because it is ONLY called one time on app startup and it is the first call. A more generic way may be to do it in the first getInstance if helper is null.
Goodluck.
I want to return a string array from Async class back to the activity that is calling this asynchronous class that is job is to do the reverse geocoding.
So, from my activity I call the constructor of the class like this:
Double[] lat_long = new Double[] { Double.parseDouble(map_lat), Double.parseDouble(map_long) };
ReverseGeocodingTask reverseGeocoding = new ReverseGeocodingTask(getActivity().getApplicationContext());
reverseGeocoding.execute(lat_long);
And this is the code of the class:
class ReverseGeocodingTask extends AsyncTask<Double, Void, List<String>> {
public static List<String> LIST = new ArrayList<String>();
Context mContext;
public ReverseGeocodingTask(Context context) {
super();
mContext = context;
}
#Override
protected List<String> doInBackground(Double... params) {
Geocoder gc= new Geocoder(mContext, Locale.getDefault());
List<Address> addrList = null;
double latitude = params[0].doubleValue();
double longitude = params[1].doubleValue();
Log.d("LATLONG", latitude + ":" + longitude);
try {
addrList = gc.getFromLocation(latitude, longitude, 1);
if (addrList.size() > 0) {
//format location info
Address address = addrList.get(0);
LIST.add(address.getLocality());
LIST.add(address.getSubAdminArea());
LIST.add(address.getCountryName());
Log.d("LIST", LIST.get(0));
}
else{
Log.d("addrList SIZE", "=0");
return null;
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
return LIST;
}
#Override
protected void onPostExecute(List<String> result) {
if (result != null) {
Log.d("ON POST", result.get(0));
}
}
}
This is the logcat:
02-28 19:20:04.323 12275-14109/guide_me_for_all.guide_me_for_all D/LATLONG﹕ 34.681377999999995:33.039339
02-28 19:20:05.434 12275-14109/guide_me_for_all.guide_me_for_all D/addrList SIZE﹕ =0
I get correctly the latitude and longitude point as you can see from the Log.d(), BUT getFromLocation.size() is always 0.
This may be a problem with your GeoCoder service. If you're backend service for the device is not present or has other problems, you will get this response.
use isPresent to check if an implementation is present.
Also, see this post here:
Geocoder.getFromLocation throws IOException on Android emulator
And the docs mention that you need a backend service:
http://developer.android.com/reference/android/location/Geocoder.html
okay guys, here is the thing, I have one application consuming ODATA service, in SMP server, I'm getting this Data like this:
public class callService extends AsyncTask<Void, Void, ArrayList<String>>
{
public ArrayList<String> doInBackground(Void... params)
{
ODataConsumer c = ODataJerseyConsumer.create("http://MyUrlService:8080");
List<OEntity> listEntities = c.getEntities("MYENTITYTOCONSUME").execute().toList();
System.out.println("Size" + listEntities.size());
if (listEntities.size() > 0)
{
for (OEntity entity : listEntities)
{
zmob_kunnr.add((String) entity.getProperty("Name1").getValue()
+ " - "
+ entity.getProperty("Kunnr").getValue().toString());
}
}
return zmob_kunnr;
}
protected void onPostExecute(ArrayList<String> result)
{
super.onPostExecute(result);
adapter = new ArrayAdapter<String>(ConsumoKnuur.this, android.R.layout.simple_list_item_1, result);
list.setAdapter(adapter);
}
}
Okay I got this solution from web and could implement as list, and I need to store this entity which one is a List of customers and get the two attributes from this entity and save in my database so:
Entity Customer:Custormer_ID, Customer_Name
Here is my code to call my sqlite:
public void sqlite()
{
sql_obj.open();
sql_obj.deleteAll();
for(int i=0; i < zmob_kunnr.size(); i++)
{
sql_obj.insert(zmob_kunnr.get(i).toString(), zmob_kunnr.get(i).toString() );
}
sql_obj.close();
}
And my SQLite:
private static final String TABLE_CLIENTE = "CREATE TABLE "
+ TB_CLIENTE
+ "(ID_CLIENTE INTEGER PRIMARY KEY AUTOINCREMENT, " //Id for controller my logics
+ " Kunnr TEXT , " //customer ID
+ " Name1 TEXT );"; //customer_name
public long insert(String name1, String Kunnr)
{
ContentValues initialValues = new ContentValues();
initialValues.put("Name1", Name1); //Customer_Name
initialValues.put("Kunnr", Kunnr); //Customer_ID
return database.insert(TB_CLIENTE, null, initialValues);
}
And off course my other methods, that is not important, so whats happening when I run my "for" in the sql call method, I get the size() of the list and the rows of the list and store the entire row in the one column of the database each time, so I got two different tables with the same values,
how can I change solve this problem instead of consume in list I need to consume in array ? or I need to create a method that get the list values and after a ,(coma) , create two differents objects to store these data ??
I took a long look in the internet and didn't find nothing, probably it's because i don't know yet, how so, I don't know for what I'm looking for it, I'm using the odata4j API and here is the link of the documentation, http://odata4j.org/v/0.7/javadoc/
I'm new on programming, so I'm really in trouble with this, any suggestions any helps will be truly, appreciate,
Thanks a lot and have a nice day !!!
You can add each entity to the `ArrayList' array by doing the following:
for (OEntity entity : listEntities) {
zmob_kunnr.add(entity);
}
This will allow you to access the data contained in the entity via getProperty() when inserted into the database.
The following statement is also not needed, as the for each loop runs through every element in the list, thus for (OEntity entity : listEntities) will not execute if the list is empty.
if (listEntities.size() > 0) {
...
}
If you have multiple ODataConsumers, you have two choices, depending on your requirements (if I understand you question correctly):
You can sequentially get each ODataConsumer, get the listEntities, and add it to the zmob_kunnr list, and after the list items are added to the database, clear the zmob_kunnr list, and call doInBackground with a new URL. This is what your current solution allows.
It appears to need to know which property is associated with a URL when reading the values into the DB. You can use a POJO as a holder for the entity and its list of properties. You can now add and remove properties. Note that properties will be removed in the same order they where inserted.
public class OEntityHolder {
private final OEntity entity;
private Queue<String> properties;
public OEntityHolder(OEntity entity) {
this.entity = entity;
this.properties = new LinkedBlockingQueue<>();
}
public OEntity getEntity() {
return this.entity;
}
public void addProperty(String property) {
this.properties.add(property);
}
public void removeProperty() {
this.properties.poll();
}
}
This will require a change to the list holding the entities:
ArrayList<OEntityHolder> zmob_entity_holders = new ArrayList<>();
If you would like to add all the entities from the different URLs at the same time, you will need to have access to all the URLs when doInBackground is called. Something like this:
public ArrayList<OEntityHolder> doInBackground(Void... params) {
String [][] urls = {{"http:MyUrl/ZMOB_FECODSet", "Name1", "Fecod"},
{"http:MyUrl/ZMOB_OTEILSet", "Name2", "Oteil"},
{"http:MyUrl/ZMOB_KUNNRSet", "Name3", "Kunnr"},
{"http:MyUrl/ZMOB_BAULTSet", "Name4", "Bault"}};
for (String [] urlProp:urls) {
//Here you get the list of entities from the url
List<OEntity> listEntities = ODataJerseyConsumer.create(urlProp[0]).getEntities("MYENTITYTOCONSUME").execute().toList();
for (OEntity entity:listEntities) {
OEntityHolder holder = new OEntityHolder(entity);
for (int i = 1; i < urlProp.length; i++)
holder.addProperty(urlProp[i]);
zmob_entity_holders.add(holder);
}
}
//At this point, all of the entities associated with the list of URLS will be added to the list
return zmob_entity_holders;
}
You now have ALL of the entities associated with the list of URLs in zmob_kunnr. Before you can and can insert then into the DB like so:
for (OEntityHolder holder : zmob_entity_holders) {
sql_obj.insert(holder.getEntity().getProperty(holder.removeProperty()).toString(), holder.getEntity().getProperty(holder.removeProperty()).toString());
}
If each entity has a associated name, you can store the names in a map, where the key is the URL and the value the name.
HashMap<String, String> urlEntityNames = new HashMap<>();
urlEntityNames.put("http://MyUrlService:8080", "MYENTITYTOCONSUME");
...//Add more URLs and entity names
You can then, when running through the list of entities, do a look-up in the map to find the correct name:
List<OEntity> listEntities = ODataJerseyConsumer.create(url).getEntities(urlEntityNames.get(url)).execute().toList();
I hope this helps, if I misunderstood you just correct me in the comments.
EDIT: Added list of URLs, holder and DB insert.
I guess i found a solution, but my log cat, is giving an exception to me any updtades about my 2nd doInBackgroundBault (Material),
public class callServiceCliente extends AsyncTask<Void, Void, ArrayList<OEntity>> {
protected void onPreExecute() {
progressC = ProgressDialog.show(Atualizar_Dados.this, "Aguarde...", "Atualizando Clientes", true, true);
}
public ArrayList<OEntity> doInBackground(Void... params) {
ODataConsumer ccli = ODataJerseyConsumer.create(URL);
List<OEntity> listEntitiesKunnr = ccli.getEntities("ZMOB_KUNNRSet").execute().toList();
System.out.println("Size" + listEntitiesKunnr.size());
for (OEntity entityKunnr : listEntitiesKunnr) {
zmob_kunnr.add(entityKunnr);
}
return zmob_kunnr;
}
protected void onPostExecute(ArrayList<OEntity> kunnr) {
super.onPostExecute(kunnr);
try {
sql_obj.open();
sql_obj.deleteAll();
for (int k = 0; k < zmob_kunnr.size(); k++) {
sql_obj.insertCliente(zmob_kunnr.get(k).getProperty("Kunnr").getValue().toString().toUpperCase(), zmob_kunnr.get(k).getProperty("Name1").getValue().toString().toUpperCase());
}
sql_obj.close();
} catch (Exception e) {
}
try {
clienteAdapter = new ArrayAdapter<OEntity>(Atualizar_Dados.this, android.R.layout.simple_list_item_1, kunnr);
listCliente.setAdapter(clienteAdapter);
} catch (Exception eq) {
}
progressC.dismiss();
new callServiceMaterial().execute();
}
}
public class callServiceMaterial extends AsyncTask<Void, Void, ArrayList<OEntity>> {
protected void onPreExecute() {
progressM = ProgressDialog.show(Atualizar_Dados.this, "Aguarde...", "Atualizando Materiais", true, true);
}
public ArrayList<OEntity> doInBackground(Void... params) {
ODataConsumer cmat = ODataJerseyConsumer.create(URL);
List<OEntity> listEntitiesBault = cmat.getEntities("ZMOB_BAULTSet").filter("IErsda eq '20141101'").execute().toList();
System.out.println("Size" + listEntitiesBault.size());
for (OEntity entityBault : listEntitiesBault) {
zmob_bault.add(entityBault);
}
return zmob_bault;
}
protected void onPostExecute(ArrayList<OEntity> bault) {
super.onPostExecute(bault);
try {
sql_obj.open();
sql_obj.deleteAll();
for (int b = 0; b < zmob_bault.size(); b++) {
sql_obj.insertMaterial(zmob_bault.get(b).getProperty("Matnr").getValue().toString().toUpperCase(), zmob_bault.get(b).getProperty("Maktxt").getValue().toString().toUpperCase());
}
sql_obj.close();
} catch (Exception e) {
}
try {
materialAdapter = new ArrayAdapter<OEntity>(Atualizar_Dados.this, android.R.layout.simple_list_item_1, bault);
listMaterial.setAdapter(clienteAdapter);
} catch (Exception eq) {
}
progressM.dismiss();
new callServiceProblema().execute();
}
}
public class callServiceProblema extends AsyncTask<Void, Void, ArrayList<OEntity>> {
protected void onPreExecute() {
progressProb = ProgressDialog.show(Atualizar_Dados.this, "Aguarde...", "Atualizando Problemas", true, true);
}
public ArrayList<OEntity> doInBackground(Void... params) {
ODataConsumer cprob = ODataJerseyConsumer.create(URL);
List<OEntity> listEntitiesFecod = cprob.getEntities("ZMOB_FECODSet").execute().toList();
System.out.println("Size" + listEntitiesFecod.size());
for (OEntity entityFecod : listEntitiesFecod) {
zmob_fecod.add(entityFecod);
}
return zmob_fecod;
}
protected void onPostExecute(ArrayList<OEntity> fecod) {
super.onPostExecute(fecod);
try {
sql_obj.open();
sql_obj.deleteAll();
for (int f = 0; f < zmob_fecod.size(); f++) {
sql_obj.insertProblema(zmob_fecod.get(f).getProperty("Fecod").getValue().toString().toUpperCase(), zmob_fecod.get(f).getProperty("Kurztext").getValue().toString().toUpperCase());
}
sql_obj.close();
} catch (Exception e) {
}
try {
problemaAdapter = new ArrayAdapter<OEntity>(Atualizar_Dados.this, android.R.layout.simple_list_item_1, fecod);
listProblema.setAdapter(problemaAdapter);
} catch (Exception eq) {
}
progressProb.dismiss();
new callServiceProcedencia().execute();
}
}
public class callServiceProcedencia extends AsyncTask<Void, Void, ArrayList<OEntity>> {
protected void onPreExecute() {
progressProc = ProgressDialog.show(Atualizar_Dados.this, "Aguarde...", "Atualizando base de dados", true, true);
}
public ArrayList<OEntity> doInBackground(Void... params) {
ODataConsumer c = ODataJerseyConsumer.create(URL);
List<OEntity> listEntitiesProcedencia = c.getEntities("ZMOB_OTEILSet").execute().toList();
System.out.println("Size" + listEntitiesProcedencia.size());
for (OEntity entityProcedencia : listEntitiesProcedencia) {
zmob_oteil.add(entityProcedencia);
}
return zmob_oteil;
}
protected void onPostExecute(ArrayList<OEntity> oteil) {
super.onPostExecute(oteil);
try {
sql_obj.open();
sql_obj.deleteAll();
for (int o = 0; o < zmob_oteil.size(); o++) {
sql_obj.insertCliente(zmob_oteil.get(o).getProperty("Fecod").getValue().toString().toUpperCase(), zmob_oteil.get(o).getProperty("Kurztext").getValue().toString().toUpperCase());
}
sql_obj.close();
} catch (Exception e) {
}
try {
procedenciaAdapter = new ArrayAdapter<OEntity>(Atualizar_Dados.this, android.R.layout.simple_list_item_1, oteil);
// listCliente.setAdapter(clienteAdapter);
} catch (Exception eq) {
}
progressProc.show(Atualizar_Dados.this, "Finalizado", "Base de dados atualizada", true, true).dismiss();
Toast.makeText(Atualizar_Dados.this, "Base de dados atualizada com sucesso", Toast.LENGTH_LONG).show();
}
}
Okay, so here is the solution that i find, and i couldn't insert your solution because, when i put inser.add(entity), they didn't show me the properties but if you have a better way to do what i did, i will really appreciate,
and by the way i need to query this consume by range date in the filter(). like i did here...
List listEntitiesBault = cmat.getEntities("ZMOB_BAULTSet").filter("IErsda eq '20141101'").execute().toList(); but isn't working, so i don't have any ideas why, i saw couple close solution on the internet and saw fields like .top(1) and .first(); that i didn't understand...
thanks a lot !!!