Call Async task class inside for loop - android

I am sending data to web server using asynctask task class. So I am taking all value from SQLite in one array list and in for loop I'm calling asynctask class to send data but the problem is loop finishes its execution and send only last value from array list to the web service. But the web service is calling according to for loop.
Any suggestion would be helpful.
Following is my code:
for (int i = 0; i < outletMasterList.size(); i++) {
outletMaster = outletMasterList.get(i);
outlet_Code = outletMaster.getOutletCode();
outlet_UID = outletMaster.getOutletUID();
finalValue = AppConstant.IMEI_NUMBER;
System.out.println("Sync i : : : : " + i + " " + respose_count);
new CommonAsyncTaskWithoutProgressBar(Sync.this, callbackInterface)
.execute("0",
AppConstant.NAMESPACE,
AppConstant.METHOD_NAME,
AppConstant.ACCESS_KEY,
AppConstant.Set_OutletFromHH,
AppConstant.OutletSyncParameters, finalValue);
}

Related

How to wait/observe incoming data from server correctly with rxjava/retrofit

I have a problem with downloading data from server, to be more specific I cannot implement a "waiting/observing incoming data" behavior. I want to fill up my RecyclerView and Spinner with lists come from server, but right know, the methods return null/empty list. I understand, the problem is that the method finish before the data arrives.
I've checked these two questions which are similar, but none of the answers worked for me:
Waiting for API Calls to complete with RxJava and Retrofit
RXJava retrofit waiting having the UI wait for data to be fetched from API
My code:
API:
#GET("/api/categories")
Observable<Response<JsonObject>> getCategories();
netWorker:
public List<String> getCat() {
List<String> incomingDataSet = new ArrayList<>();
compositeDisposable.add(
apiConnector.getCategories()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> {
if (response.code() >= 200 && response.code() < 300) {
JsonArray incomingArray = response.body().getAsJsonArray("category");
for (int i = 0; i < incomingArray.size(); i++) {
incomingDataSet.add(incomingArray.get(i).getAsJsonObject().get("categoryname").toString().replaceAll("\"", ""));
Log.i("LOG", "downloadCategories response: " + incomingDataSet.toString());
}
} else {
Log.i("LOG", "Response error: " + response.code());
}
})
);
Log.i("LOG", "getCat: " + incomingDataSet.toString());
return incomingDataSet;
}
MainActivity:
List<String> categorylist = new ArrayList<>();
categorylist = netWorker.getCat();
Log.i("LOG", "list:" + categorylist );
So, what I see in log:
First:
getCat: []
list: []
and then:
downloadCategories response: [cat1]
downloadCategories response: [cat1, cat2]
downloadCategories response: [cat1, cat2, cat3]
Show spinner in doOnSubscribe() and hide in doFinally(). Put code that fills RecyclerView inside subscribe() to fill it when data arrives. Otherwise you just get empty new list on Main thread and do not update RecyclerView further.

How to make multiple queries and load into array?

How would I load multiple Firestore query results into the same array? I am using a for-loop but since Firestore queries are async, the array is set to 0. Here is my code:
private void loadMealplans() {
for (int i = 0; i < restaurantArrayList.size(); i++) {
Query planQuery = firebaseFirestore.collection("Meal_Plans").whereEqualTo("restaurantId", restaurantArrayList.get(i).getRestaurantId());
planQuery.get().addOnSuccessListener(queryDocumentSnapshots -> {
for (QueryDocumentSnapshot allPlans : queryDocumentSnapshots) {
Mealplan mealplan = allPlans.toObject(Mealplan.class);
mealplan.setMealplanId(allPlans.getId());
myPlans.add(mealplan);
}
});
Log.d(TAG, "mealplan size:"+ myPlans.size()); // this is always zero
}
// Loading data into recycler view
}
When you call planQuery.get() it returns a Task<QuerySnapshot>. To wait for multiple tasks to be completed, gather all those tasks and pass them to Tasks.whenAll.
For more on this, I recommend reading Become a Firebase task master.

Updating realm object by increments

I have a realm object that contains list of items with IDs
#SerializedName("products")
RealmList<ProductDialItem> products;
#SerializedName("previous_suppliers")
RealmList<SuppliersDialItem> previousSuppliers;
#SerializedName("tariffs")
RealmList<TariffsDialItem> tariffs;
#SerializedName("deposit_frequencies")
RealmList<SimpleDialItem> depositFrequencies;
#SerializedName("bank_codes")
RealmList<SimpleDialItem> bankCodes;
#SerializedName("gas_usages")
RealmList<SimpleDialItem> gasUsages;
And so on, each item in list has ID. The server sends a json response with values to be filled in the object.
But we also use Last-Modified header, so that server only sends items that changed. I want only to update items, not to delete any of them.
Tl;dr how do I only update/add items to realm, but not delete them
let the object contain:
class MyClass{
int x = 0;
int y = 0;
int z = 0;
}
then if you need to increment the variables from the web:
MyClass finalObject = new MyClass();
MyClass tempObject = new Gson().fromJson(response,MyClass.class);
incrementObjects(tempObject,finalObject);
and now create the method incrementObjects() :
private void incrementObjects(MyClass obj1, MyClass obj2){
obj2.x += obj1.x;
obj2.y += obj1.y;
obj2.z += obj1.z;
}
You can Query on Realm when you get updated data response like,
//Create RealmList when you get updated Data in your api response.
RealmList<YourModel> updatedData = yourResponseData.getData();
//Get data from localDatabase and Query on
RealmQuery<YourModel> where = mRealm.where(YourModel.class);
for (int i = 0; i < updatedData.size(); i++) {
//put condition to match data based on your database.
where = where.notEqualTo(YourModel.NAME,updatedData.get(i).getName());
}
//Now this where.findAll(); , will return list of data which is notEqual To updatedData
//perform update operation with this or deleteFrom local Data and insert new/updated Data.
where.findAll();

Calling Async task in a loop?

I want to call an Async task in a loop and execute it a few times in parallel.
I have a List of items which I split out into smaller lists with 10 items in each list.
Then for every small List I execute the Async task using THREAD_POOL_EXECUTOR.
Problem is, its not working. I'm thinking its because I use the same list each time when it is passed to the AsyncTask - and I think it may be passed as reference.
Do I need to somehow create new Lists dynamically?
//split the ListItems into 10s
if (actualThumbs.size() > 10){
List<List<ListItem>> parts = chopped(actualThumbs, 10); // this splits it into parts of 10
List< ListItem > listToSend = new ArrayList<ListItem>(); //this is the list to pass
for(int i = 0; i < parts.size(); i++){ //for every part
for(int x = 0; x < parts.get(i).size(); x++){ //for everything in that part
//add to its own List
listToSend.add(parts.get(i).get(x));
}
//this is the async task
loadActualThumbs thumbs = new loadActualThumbs();
//execute multiple threads
thumbs.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,listToSend );
listToSend.clear(); //clearing the list ready for a new one - PROBLEM?
}
}
else
{
//else just execute AsyncTask normally, this works OK
loadActualThumbs thumbs = new loadActualThumbs();
thumbs.execute(actualThumbs);
}
EDIT:
I tried changing my code, to instead add every List that I want to send to the Async task to another List, and then loop through that List of Lists and send each one:
if (actualThumbs.size() > 10){
List<List<ListItem>> parts = chopped(actualThumbs, 10);
List< ListItem > listToSend = new ArrayList<ListItem>();
List<List<ListItem>> sendMe = new ArrayList<List<ListItem>>();
for(int i = 0; i < parts.size(); i++){ //for every part
for(int x = 0; x < parts.get(i).size(); x++){ //for everything in that part
//add to its own ListItem?
listToSend.add(parts.get(i).get(x));
}
sendMe.add(listToSend);// add the List to this List
listToSend.clear();
}
for(int e = 0; e<sendMe.size();e++){ //loop through the list of lists
loadActualThumbs thumbs = new loadActualThumbs();
//execute multiple threads?
thumbs.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,sendMe.get(e) ); // execute async with correct List
}
}
else
{
if (actualThumbs.size() > 0){
//load actual thumbnails
loadActualThumbs thumbs = new loadActualThumbs();
thumbs.execute(actualThumbs);
}
}
Your code should look like this now :
List<List<ListItem>> parts = chopped(actualThumbs, 10);
for(List<ListItem> list : parts) {
new loadActualThumbs().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, list);
}
I am actually not sure what size the threadpool is or if it's a cached thread pool, but you can create your own threadpool with Executors.newCachedThreadPool() and Executors.newFixedThreadPool(int count)... but I'd just go with the AsyncTask.THREAD_POOL_EXECUTOR....should work :)
If you need to execute your asynctask for particular interval of time then you may make use of Timer for same ..
Like this ..
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
try {
System.out
.println("=================== I am in pooling state ===============");
GetBookingStatusAsyncTask performBackgroundTask = new GetBookingStatusAsyncTask();
performBackgroundTask.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
};
Now when you need to kill this timer ..
timer.cancel();
timer = null;
Also make use of boolean check so as to avaoid infinite loop .. i.e if true then execute AsyncTask .. and if false then stop AsyncTask .. just like ..
public void callAsynchronousTask(boolean b) {
// timer.cancel();
if (b) {
System.out.println("============= Check for timer check " + tcheck);
// execute in every 10000 ms
tcheck++;
} else {
System.out
.println("============= Check for timer check + cancelling timer task "
+ tcheck);
timer.cancel();
timer = null;
System.out.println("=============timer is ===" + timer);
// finish();
return;
}
}
When you need to close this task then simply of true / false condition pass like ..you need to pass this in your AsyncTask.
callAsynchronousTask(true); / callAsynchronousTask(false);
Hope it helps!..

How to ensure that data is inserted only one time in sqlite

I'm using a web service which returns data in JSON format like this:
{"content":[{"id":"1","asset_id":"62","title":"sample page","alias":"","introtext":"","fulltext":"Some Contents"},{"id":"2","asset_id":"62","title":"sample page2","alias":"","introtext":"","fulltext":"Some Contents"},{"id":"3","asset_id":"62","title":"sample page3","alias":"","introtext":"","fulltext":"Some Contents"}]}
onCreate() of MainActivity.java is :
boolean myFlag = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.myView);
setFlag = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
dataSource = new ContentsDataSource(this);
dataSource.open();
parseAndIsertData();
}
the parseAndInsertData() is :
EDIT
private void parseAndIsertData() {
// Creating JSON Parser instance
MyJSONParser jParser = new MyJSONParser();
contentDataObject = new ContentDataObject();
// getting JSON string from URL
JSONObject json = jParser.getJSONFromUrl(BASE_URL);
try {
// first time check if data is inserted
editor = setFlag.edit();
editor.putBoolean(MY_KEY, true);
// Getting Array of Contents
jsonArray = json.getJSONArray(MOBILE_CONTENT);
// looping through All Contents
if(!myFlag){
for(int i = 0; i < jsonArray.length(); i++){
contentDataObject.setId(jsonArray.getJSONObject(i).getInt(MOBILE_CONTENT_ID));
contentDataObject.setTitle(jsonArray.getJSONObject(i).getString(MOBILE_CONTENT_TITLE));
contentDataObject.setFulltext(jsonArray.getJSONObject(i).getString(MOBILE_CONTENT_FULLTEXT));
contentDataObject.setState(jsonArray.getJSONObject(i).getInt(MOBILE_CONTENT_STATE));
contentDataObject.setNewValue(jsonArray.getJSONObject(i).getInt(MOBILE_CONTENT_NEW));
contentDataObject.setHeader(jsonArray.getJSONObject(i).getString(MOBILE_CONTENT_HEADER));
contentDataObject.setColor(jsonArray.getJSONObject(i).getInt(MOBILE_CONTENT_COLOR));
contentDataObject.setNext(jsonArray.getJSONObject(i).getString(MOBILE_CONTENT_NEXT));
contentDataObject.setPrevious(jsonArray.getJSONObject(i).getString(MOBILE_CONTENT_PREVIOUS));
contentDataObject = dataSource.create(contentDataObject);
Log.i(MY_TAGT, "Data Inserted " + contentDataObject.getId() + " Times");
}
myFlag = setFlag.getBoolean(MY_KEY, false);
}
} catch (JSONException e) {
e.printStackTrace();
}
}}
Now My logcat for first time launch is :
and when I relaunch the app my logcat is :
Now I want ask that is this approach correct or not if YES! then will I be able to update that later on!!
Thanks!
You are correct that this code will insert the data multiple times. It will be up to you to implement a pattern that allows only one row.
You need to either query the data source first and not insert the data if it exists or you need to delete the data from the data source and then insert it every time. There are other patterns but these two will be the most common. Which one you choose will depend on what the data is and how you want it maintained or updated.
define a column in your table to be primary key or unique
use SQLiteDatabase.insertWithOnConflict(...) with the conflictAlgorithm parameter (the last one) set to ``SQLiteDatabase.CONFLICT_IGNORE`
See this

Categories

Resources