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 !!!
Related
I've got this code with fetches the "rate" data from an API, along with "rate", I need to get the "name". If I get "name" it often binds it below the "rate".
I need it to join on the same row of the List View, so it is like [Rate Name].
I need to get two objects of a JSON Array and bind it to the array adapter so I can display two objects in the same row of a List View so it is more user friendly.
The code below is of the AsyncTask, the code works fine but I need to add one more object and make sure it is displayed as one rate - one name and then iterating through the loop and adding more as needed in the same order.
public class AsyncTaskParseJson extends AsyncTask<String, String, String> {
// the url of the web service to call
String yourServiceUrl = "eg: URL";
#Override
protected void onPreExecute() {
}
String filename = "bitData";
#Override
protected String doInBackground(String... arg0) {
try {
// create new instance of the httpConnect class
httpConnect jParser = new httpConnect();
// get json string from service url
String json = jParser.getJSONFromUrl(yourServiceUrl);
// parse returned json string into json array
JSONArray jsonArray = new JSONArray(json);
// loop through json array and add each currency to item in arrayList
//Custom Loop Initialise
for (int i = 1; i < 8; i++) {
JSONObject json_message = jsonArray.getJSONObject(i);
// The second JSONObject which needs to be added
JSONObject json_name = jsonArray.getJSONObject(i);
if (json_message != null) {
//add each currency to ArrayList as an item
items.add(json_message.getString("rate"));
String bitData = json_message.getString("rate");
String writeData = bitData + ',' +'\n';
FileOutputStream outputStream;
File file = getFileStreamPath(filename);
// first check if file exists, if not create it
if (file == null || !file.exists()) {
try {
outputStream = openFileOutput(filename, MODE_PRIVATE);
outputStream.write(writeData.getBytes());
outputStream.write("\r\n".getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// if file already exists then append bit data to it
else if (file.exists()) {
try {
outputStream = openFileOutput(filename, Context.MODE_APPEND);
outputStream.write(writeData.getBytes());
outputStream.write("\r\n".getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
// below method will run when service HTTP request is complete, will then bind text in arrayList to ListView
#Override
protected void onPostExecute(String strFromDoInBg) {
ListView list = (ListView) findViewById(R.id.rateView);
ArrayAdapter<String> rateArrayAdapter = new ArrayAdapter<String>(BitRates.this, android.R.layout.simple_expandable_list_item_1, items);
list.setAdapter(rateArrayAdapter);
}
}
Just Create Custom Class Messsage:
public class Item{
private String name;
private String rate;
public void Message(String n, String r){
this.name=n;
this.rate=r;
}
// create here getter and setter
}
Now in your background, you have to add name and rate in Message class
Public class MainAcitity extends Activity{
public static List<Item> items= new ArrayList<>();// define in inside the class
// this has to be down on background
Item i=new Item(json_message.getString("name"),json_message.getString("rate"));
items.add(i);
Now pass this listmessge onPostExecute :
ListView list = (ListView) findViewById(R.id.rateView);
ArrayAdapter<String> rateArrayAdapter = new ArrayAdapter<String>(BitRates.this, android.R.layout.simple_expandable_list_item_1, items);
list.setAdapter(rateArrayAdapter);
Is that any helpful for you.
Follow this link.You will get my point.
https://devtut.wordpress.com/2011/06/09/custom-arrayadapter-for-a-listview-android/
I'm pretty new to Java, and currently build client program based on Android.
I have backend server written in Python that will produce result containing some List inside Array.
Here is result from python I should get:
[[id, shopName], [id, shopName], ...]
Example:
[[1, Jakarta], [2, Bali], ...]
Basically, I need to have String[] containing id, and String[] containing name, for spinner adapter.
String[] shopServId, shopServName;
List arrayListShopServId, arrayListShopServName;
// in onCreate()
arrayListShopServId = new ArrayList();
arrayListShopServName = new ArrayList();
and on XMLRPCCallback listener onResponse()
Object[] classObjs = (Object[]) result;
int length = classObjs.length;
shopServId = new String[classObjs.length];
shopServName = new String[classObjs.length];
if ( length > 0) {
arrayListShopServId.clear();
arrayListShopServName.clear();
for (int i=0; i<length; i++) {
#SuppressWarnings("unchecked")
Map<String,Object> classObj = (Map<String,Object>)classObjs[i];
arrayListShopServId.add(classObj.get("id"));
arrayListShopServName.add(classObj.get("name"));
// id and name here are object fields key to get by using XMLRPC
shopServId[i] = arrayListShopServId.get(i).toString();
shopServName[i] = arrayListShopServName.get(i).toString();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
loadSpinnerSaleShop();
}
});
} else {
System.out.println("SaleShop not found!");
}
But it gives me an error
java.lang.ClassCastException: java.lang.Object[] cannot be cast to java.util.Map
How can I achieve that?
EDIT
For those who want to know, I use XMLRPC AsynTask.
Full part of the relevant code:
TaskId:
private void readSaleShop() {
readSaleShopTaskId = util.soe_salesman_shops(listener, database, uid, password, "sale.order",
employeeId);
}
The Listener:
XMLRPCCallback listener = new XMLRPCCallback() {
public void onResponse(long id, Object result) {
Looper.prepare();
if(id==readSaleShopTaskId) {
Object[] classObjs = (Object[]) result;
int length = classObjs.length;
shopServId = new String[classObjs.length];
shopServName = new String[classObjs.length];
if ( length > 0) {
arrayListShopServId.clear();
arrayListShopServName.clear();
for (int i=0; i<length; i++) {
#SuppressWarnings("unchecked")
Map<String,Object> classObj = (Map<String,Object>)classObjs[i];
arrayListShopServId.add(classObj.get("id"));
arrayListShopServName.add(classObj.get("name"));
shopServId[i] = arrayListShopServId.get(i).toString();
shopServName[i] = arrayListShopServName.get(i).toString();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
loadSpinnerSaleShop();
}
});
} else {
System.out.println("SaleShop not found!");
}
} else if(id==updateSaleOrderTaskId) {
final Boolean updateResult =(Boolean)result;
if(updateResult)
{
Log.v("SO UPDATE", "successfully");
util.MessageDialog(SOFormActivity.this,
"Update SO succeed.");
}
else{
util.MessageDialog(SOFormActivity.this,
"Update SO failed. Server return was false");
}
} else if (id == createSOTaskId) {
String createResult = result.toString();
if(createResult != null)
{
Log.v("SO CREATE", "successfully");
util.MessageDialog(SOFormActivity.this,
"Create SO succeed. ID = " + createResult);
}
else
{
util.MessageDialog(SOFormActivity.this,
"Create SO failed. Server return was false");
}
}
Looper.loop();
}
public void onError(long id, XMLRPCException error) {
Looper.prepare();
Log.e("SOForm", error.getMessage());
util.MessageDialog(SOFormActivity.this, error.getMessage());
Looper.loop();
}
public void onServerError(long id, XMLRPCServerException error) {
Looper.prepare();
Log.e("SOForm", error.getMessage());
util.MessageDialog(SOFormActivity.this, error.getMessage());
Looper.loop();
}
};
method I use from UtilAsync class:
public long soe_salesman_shops(XMLRPCCallback listener, String db, String uid, String password,
String object, String employeeId) {
long id = client.callAsync(listener, "execute", db, Integer.parseInt(uid), password, object,
"soe_salesman_shops", Integer.parseInt(employeeId));
return id;
}
classObjs[i] is a an object array. What you can do is cast it to an Array and then get the required data:
Object[] classObj = (Object[])classObjs[i];
arrayListShopServId.add(classObj[0]);
arrayListShopServName.add(classObj[1]);
Your result is a Object[][], so you can do
classObj.put(classObjs[i][0], classObjs[i][1]);
But you can directly do
arrayListShopServId.add(classObjs[i][0]);
arrayListShopServName.add(classObjs[i][1]);
This is a normal behavior.
You have :
Object[] classObjs = (Object[]) result;
Map<String,Object> classObj = (Map<String,Object>)classObjs[i];
You're trying to cast an Object[] element (classObjs[i]) to a different type (Map).
You have to construct the element of the classObj Map in a proper way.
I've ended up changing my python code so it will produce result List of Python Dictionary like this
[{'id':id, 'name':name}, {'id':id, 'name':name}, ...}]
So my code is working now.
But still confuse how to get certain element from List inside List.
So, if someone have working solution, I'll mark that as an answer.
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.
I have no idea how to solve problem, which I met while designing API for Android.
API must contain a method which will be able to get JSON Object from specific URL. So, I decide to put into the method AsyncTask to achieve that.
After execution method from this API I need populate a ListView, but I do not know how. As far as I know it is not possible to put AsyncTask( from method in my API) into other AsyncTask.
Any ideas, solutions, suggestions?
EDIT:
In the other words I want to create a method which will call restful services and get JSON.
This method will be executed (from other package) to populate ListView with the result.
My AsyncTask:
protected String doInBackground(HashMap<String,Boolean>... args)
{
JSONArray readings=null;
JSONObject json = getReadingsFromDB(args[0]);
try
{
int i;
readings = json.getJSONArray(TAG_READINGS);
for(i =0; i<readings.length();i++)
{
JSONObject ob = readings.getJSONObject(i);
ReadingH newReading = new ReadingH();
HashMap<String,String> map = new HashMap<String, String>();
String id;
String date;
String humidity;
String temp;
if(!ob.isNull(TAG_TEMPERATURE))
{
temp = ob.getString(TAG_TEMPERATURE);
newReading.setValue(TAG_TEMPERATURE, temp);
map.put(TAG_TEMPERATURE, temp);
}
if(!ob.isNull(TAG_ID))
{
id = ob.getString(TAG_ID);
newReading.setValue(TAG_ID, id);
map.put(TAG_ID, id);
}
if(!ob.isNull(TAG_DATE))
{
date = ob.getString(TAG_DATE);
map.put(TAG_DATE, date);
newReading.setValue(TAG_DATE, date);
}
if(!ob.isNull(TAG_HUMIDITY))
{
humidity= ob.getString(TAG_HUMIDITY);
map.put(TAG_HUMIDITY, humidity);
newReading.setValue(TAG_HUMIDITY, humidity);
}
readingsListH.add(newReading);
readingsList.add(map);
}
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String file_url)
{
// pDialog.dismiss();
a.runOnUiThread(new Runnable()
{
public void run()
{
ListAdapter adapter = new SimpleAdapter(
a,readingsList,
R.layout.reading_item,new String[]{TAG_ID,TAG_DATE,TAG_TEMPERATURE},
new int[]{R.id.ReadingID,R.id.ReadingDate,R.id.ReadingTemperature});
a.setListAdapter(adapter);
}
});
}
doInBackground will be in my new method, but code from onPostExecute will be there where new method will be executed.
Regards
I am a rookie in the Android world and I built up a small training SW based on the 2.1 Google API.
At that time I did not know yet about main thread and worker threads, so I put all my code in the main thread.
Since, I fixed it with async classes for my netwkork access to fit the 4.0 Google API.
Ok, but one last thing bothers me and I just can not find any clues.
It is about an AutoCompleteTextView on a field ville ("town" in french).
BEFORE (2.1):
public void onTextChanged(CharSequence s, int start, int before, int count)
{
String result = null;
InputStream is = null;
List<String> r = new ArrayList<String>();
if (ville.enoughToFilter())
{
is = connexionHttp(BASE_URL + "ville.php?ville=" + ville.getText());
result = lectureData(is);
try
{
JSONArray jArray = new JSONArray(result);
JSONObject json_data=null;
for(int i=0;i<jArray.length();i++)
{
json_data = jArray.getJSONObject(i);
r.add(json_data.getString("VILLE"));
a_idVil.add(json_data.getString("CLEF_VILLE"));
}
ville.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_selectable_list_item,r));
ville.setOnItemSelectedListener(new villeListener());
}
catch(JSONException e1)
{
Toast.makeText(getBaseContext(),e1.toString() ,Toast.LENGTH_LONG).show();
Log.d("***** TestActivity/onTextChanged: JSONException *****", "--"+e1.toString()+"--");
}
catch(ParseException e1)
{
Toast.makeText(getBaseContext(),e1.toString() ,Toast.LENGTH_LONG).show();
Log.d("***** TestActivity/onTextChanged: ParseException *****", "--"+e1.toString()+"--");
}
}
}
public class villeListener implements OnItemSelectedListener
{
public void onItemSelected(AdapterView<?> parent, View v, int pos, long row)
{
villePosition = pos;
}
public void onNothingSelected(AdapterView<?> arg0) { }
}
runs 100% perfect:
-> after the 4th caracters, the query runs on MySql to find all the towns beginning with the 4 given letters, and displays the selection list to select the right one: OK
-> the listener give the index of the choosen town: OK
AFTER (4.0)
public void onTextChanged(CharSequence s, int start, int before, int count)
{
if (ville.enoughToFilter())
{
new RemplirVille().execute(BASE_URL + "ville.php?ville=" + ville.getText());
Log.d("***********","AVANT");
ville.setOnItemSelectedListener(new villeListener());
Log.d("***********","APRES");
}
}
public class villeListener implements OnItemSelectedListener
{
public void onItemSelected(AdapterView<?> parent, View v, int pos, long row)
{
villePosition = pos;
Log.d("*************9999999", "1111111111");
}
public void onNothingSelected(AdapterView<?> arg0) { }
}
class RemplirVille extends AsyncTask<String, String, List<String>>
{
Integer errorMsgId;
String errorMsgParam;
protected List<String> doInBackground(String... param)
{
List<String> listeAffichageVille = new ArrayList<String>();
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(param[0]);
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
if (response.getStatusLine().getStatusCode() < 400)
{
HttpEntity entity = response.getEntity();
String entityStr = EntityUtils.toString(entity);
JSONArray json_array = new JSONArray(entityStr);
for(int i=0;i<json_array.length();i++)
{
JSONObject json_ligne = json_array.getJSONObject(i);
listeAffichageVille.add(json_ligne.getString("VILLE"));
a_idVil.add(json_ligne.getString("CLEF_VILLE"));
}
}
else
{
Log.d("***** TestActivity/ASYNC RemplirVille: EXCEPTION http error *****", "--"+response.getStatusLine().toString()+"--");
this.errorMsgId = R.string.http_site_error;
listeAffichageVille = null;
}
}
catch (Exception ex)
{
Log.d("***** TestActivity/ASYNC RemplirVille: EXCEPTION decode error *****", "--"+ex.toString()+"--");
this.errorMsgId = R.string.http_decode_error;
this.errorMsgParam = ex.getLocalizedMessage();
listeAffichageVille = null;
}
return listeAffichageVille;
}
protected void onProgressUpdate(String... item) { }
protected void onPreExecute(List<String> list) { }
protected void onPostExecute(List<String> list)
{
if (list == null)
{
if (this.errorMsgId != null)
{
String msg = TestActivity.this.getString(this.errorMsgId);
Toast.makeText(TestActivity.this,msg,Toast.LENGTH_LONG).show();
}
}
else
{
ville.setAdapter(new ArrayAdapter<String>(TestActivity.this,android.R.layout.simple_selectable_list_item,list));
}
}
}
runs with troubles:
-> you have to put in (enoughToFilter + 1) caractères to diplay the list of the towns: BAD
-> the listener is even not run anymore: BAD
In fact enoughToFilter works well, it launches the RemplirVille class which runs ok except that it does not displays the list!
But, if you put in 1 more caracter:
-> enoughToFilter still working well
-> RemplirVille brings the data one more time.... but this time the selection list displays well.
Any idea about that topic?
I guess it is a context problem, but even with a GetApplicationCOntext I just can not get it.
Thanks.
Calling AutoCompleteTextView.setAdapter() does not automatically show the dropdown, but you can force the dropdown to be shown with AutoCompleteTextView.showDropDown().
protected void onPostExecute(List<String> list){
//...
ville.setAdapter(new ArrayAdapter<String>(TestActivity.this,android.R.layout.simple_selectable_list_item,list));
if(ville.isInputMethodTarget()){
ville.showDropDown();
}
//...
}
Without this, the dropdown was not shown until the next character was typed, which gave the (enoughToFilter + 1) problem.