How to make threads synchronize in a loop statement? - android

I am new to threads. I am trying to load a small array of photos. Right now I am using Async tasks/ threads, but how do I make the outcome sequential? Below is an illustration:
What I want:
a[0] = photo1;
a[1] = photo2;
a[2] = photo3;
a[3] = photo4
What my program gives me instead. Note that the order changes and is random:
a[0] = photo[2];
a[1] = photo[1];
a[2] = etc
Here's a snippet of my code:
...
for (int i = 0; i < mNoOfContacts; i++) {
String stringContactUri = storeSettings.getString("contactUri"+i, "");
if (stringContactUri != ""){
Uri contactUri = Uri.parse(stringContactUri);
loadContactInfo(contactUri);
}
...
private void loadContactInfo(Uri contactUri) {
AsyncTask<Uri, Void, ContactInfo> task = new AsyncTask<Uri, Void, ContactInfo>() {
#Override
protected ContactInfo doInBackground(Uri... uris) {
return mContactAccessor.loadContact(getContentResolver(), uris[0]);
}
#Override
protected void onPostExecute(ContactInfo result) {
Contacts[mNoOfContacts] = result;
Toast.makeText(getApplicationContext(), mNoOfContacts+"Picked Contact"+Contacts[mNoOfContacts].getDisplayName(), Toast.LENGTH_SHORT).show();
mNoOfContacts++;
}
};
task.execute(contactUri);
}
...
My code is a modification of the Google Android demo app - Business Cards.
Please help! Thanks!

What might be the easiest thing to do is make the onPostExecute method call a routine that does the sorting: pass both the ContactInfo and the Uri and then compare the Uri with the original and put it in the proper place.
Alternatively modify your AsyncTask so instead of launching one per Uri you launch one you pass all the Uris at once and then go from there.

I would think that, by definition, "Asynchronous Tasks" are not synchronized...Asynchronous literally means "not synchronized." If you want it synchronized, just load them the old fashioned way by doing a URI call, get your photo and do it again once the last photo was loaded.

Related

Arraylist of strings into one comma separated string

Trying to convert a Arraylist of strings into one big comma separated string.
However when I use the
String joined = TextUtils.join(", ", participants);
Debugger shows me size of 4 for participants however the joined value as "" therefore empty
private ArrayList<String> participants;
Not sure what is going wrong?
UPDATE:
List<String> list = new ArrayList<>();
list.add("Philip");
list.add("Paul Smith");
list.add("Raja");
list.add("Ez");
String s = TextUtils.join(", ", list);
This works when I have a list that I manually populate however below is how the code is working right now.
In the onCreate()
callApi(type);
String s = TextUtils.join(", ", participants);
getSupportActionBar().setTitle(s);
In callAPI():
JSONArray participantsR = sub.getJSONArray("referralParticipants");
Log.e("Participants length ", String.valueOf(participantsR.length()));
for (int i = 0; i < participantsR.length(); i++)
{
JSONObject object = participantsR.getJSONObject(i);
String firstname = (String) object.get("fullName");
participants.add(firstname);
Log.e("Times", String.valueOf(i));
}
I'm trying to reproduce your error and am unable to. Here is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_temp);
List<String> list = new ArrayList<>();
list.add("Philip Johnson");
list.add("Paul Smith");
list.add("Raja P");
list.add("Ezhu Malai");
String s = TextUtils.join(", ", list);
Log.d(LOGTAG, s);
}
My output is Philip Johnson, Paul Smith, Raja P, Ezhu Malai as expected.
Are you importing the correct TextUtils class?
android.text.TextUtils;
Given the new information, here is my approach:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_temp);
callApi(type, new OnResponseListener<List<String>>() {
#Override public void onResponse(List<String> list) {
getSupportActionBar().setTitle(TextUtils.join(", ", list));
}
});
}
I don't know what networking library you're using, but you may have to define OnResponseListener as an interface. It's very easy:
public interface OnResponseListener<T> {
public void onResponse(T response);
}
You will then need to modify your callApi function to take an instance of OnResponseListener> and call it's onResponse method after completing the call.
I would recommend looking into the Volley library, and reading the Android documentation about simple network calls.
I use StringUtils.join from Apache Common Utilities.
The code is super-simple just the way you wanted,
StringUtils.join(participants,", ");
Works flawlessly for me.
EDIT
As requested, here is the StringUtils.java file for those who just want to use this single utility class and not the entire library.
I don't know what TextUtils does. This will do it.
StringBuffer sb = new StringBuffer();
for (String x : participants) {
sb.append(x);
sb.append(", ");
}
return sb.toString();
Easy enough, just use that.
Try with kotlin
val commaSeperatedString = listOfStringColumn.joinToString { it ->
"\'${it.nameOfStringVariable}\'" }
// output: 'One', 'Two', 'Three', 'Four', 'Five'

dreamfactory : Querying records with multiple filters

I am working on an ecommerce android app. I am trying to fetch records using dreamfactory API for android, based on multiple filters.
Using an AsyncTask named as GetProductsBySubCatIdTask
public class GetProductsBySubCatIdTask extends BaseAsyncRequest {
Context context;
public Products productsRec;
int subCatId;
String sort_str,fltr_str;
public GetProductsBySubCatIdTask(Context context, int subCataId, String sort_str, String fltr_str){
this.context = context;
this.subCatId = subCataId;
this.sort_str = sort_str;
this.fltr_str = fltr_str;
}
#Override
protected void doSetup() throws ApiException, JSONException {
callerName = "getProductsBySubCatId";
serviceName = AppConstants.DB_SVC;
endPoint = "product";
verb = "GET";
// filter to only select the contacts in this group
if(!TextUtils.isEmpty(fltr_str)){
fltr_str = "&&" + fltr_str;
}
else{
fltr_str = "";
}
queryParams = new HashMap<>();
queryParams.put("filter", "sub_category_id=" + subCatId + fltr_str);
queryParams.put("order", sort_str);
applicationApiKey = AppConstants.API_KEY;
sessionToken = PrefUtil.getString(context, AppConstants.SESSION_TOKEN);
}
#Override
protected void processResponse(String response) throws ApiException, JSONException {
//Log.d("Tang Ho"," >>>>> " + response);
productsRec =
(Products) ApiInvoker.deserialize(response, "", Products.class);
}
#Override
protected void onCompletion(boolean success) {
if(success && productsRec != null && productsRec.products.size() > 0){
Log.d("Tang Ho"," >>>>> Success");
}
}
}
I have used filters which is constructed outside the class and provided as parameter, the possible filters are
unit_offerprice < unit_mrp<br>
unit_offerprice = unit_mrp<br>
(unit_offerprice > 200) && (unit_offerprice > 500)<br>
unit_offerprice > 100<br>
unit_offerprice < 600<br>
All the above filters can be used either individually or in combination of 2 or 3 like
unit_offerprice < unit_mrp && unit_offerprice > 100
After escaping the symbols in the string like
unit_offerprice%3Cunit_mrp
Not able to get desired result,
Searched in documentations but din't found exact thing.
what can be the possible solution for this ?
If your filter has multiple conditions, each condition needs to be placed inside parentheses (). Additionally, the proper syntax for joining filters with and is AND, not &&.
Supported logical operators are AND, OR, and NOT.
In your example, this:
unit_offerprice < unit_mrp && unit_offerprice > 100
should be this:
(unit_offerprice < unit_mrp) AND (unit_offerprice > 100)
See these portions of the documentation:
http://wiki.dreamfactory.com/DreamFactory/Features/Database/Records#Filtering_Records
http://wiki.dreamfactory.com/DreamFactory/Tutorials/Querying_records_with_logical_filters
DreamFactory also offers a number of official support avenues, including user forums. http://www.dreamfactory.com/support
Got it resolved by adding parenthesis for multiple filters.
But there was issue using the special characters (like <,>) and
this needed to be
encoded into %3C (for <) and %3E (for >),
the string used for the filtering is :
"(unit_offerprice>100)AND(unit_offerprice<500)"
the encoded form is :
"(unit_offerprice%3E100)AND(unit_offerprice%3C500)"

Randomize different ArrayList to get a value

I searched for related questions but didn´t find a solution (at least i don´t know if i named it correctly)
So, i have two ArrayLists and i would like to randomize all of them to get a value:
public class ListBox {
public static ArrayList listOne(){
ArrayList<Lists> listOne = new ArrayList<>();
listOne.add(new Item("Text One"));
listOne.add(new Item("Text Two"));
return listOne;
}
public static ArrayList listTwo(){
ArrayList<Lists> listTwo = new ArrayList<>();
listTwo.add(new Item("Text Three"));
listTwo.add(new Item("Text Four"));
return listTwo;
}
}
in other activity:
public void buttonClick(View view){
ArrayList<Lists> algumasListas = ListBox.listOne();
...
}
This is where i shuffle it
public class ListMixer extends ListBox{
public ArrayList<Lists> listas = null;
public ListMixer(ArrayList<Lists> listas ) {
this.listas = listas;
}
protected String mixList(){
Double randomNumber = new Double(Math.random() * listas.size());
int randomNum = randomNumber.intValue();
Lista lista= listas.get(randomNum);
String listaString2 = String.valueOf(lista);
String message = ("This is your list: " + listas);
return message;
}
}
my desired output would be one of the four listItems.
Appreciate the help!
Merge arrays into single one of size N.
Choose a random number in range 0..N-1.
Choose an element by index.
The first bug I'm seeing in your code is that listOne() returns object listTwo when called, which doesn't exist. It probably shouldn't even compile, unless something funky is going on with global scope variables.
The following code should do what you want by merging the two lists into one and then returning a random object from them.
public Object randomFromList(List<Object> listOne, List<Object> listTwo){
List<Object> bigList = new ArrayList<Object>(listOne.size() + listTwo.size());
bigList.addAll(listOne);
bigList.addAll(listTwo);
return bigList.get(new Random().nextInt(bigList.size()));
}
For optimization, if you call this a lot, I would save the Random() object outside of the method to avoid instantiating it every time you make the call.

AsyncTask do not work in for loop

My AsyncTask class do not work inside for loop. Below is my code please review it.
for (int i = 0; i < size; i++) {
String id = careplan_disease_Parser.DiseaseID.get(i);
String method = "GetCarePlan_Comment?CurrentValue=0&OptionId=" + id + "&DiseaseID=" + id + "&OrgId=" + orgId + "";
String link = "GetCarePlan_Comment_dislink";
task = new AsyncTask123();
task.execute(link, method);
method=null;
link=null;
task=null;
}
Task executes only once. so i can't get value from web service second time in a loop.
Please help me how to make it work.
Thanks
You can write a start-method, that gets called in the onPostExecute-part of you AsyncTask. It should look like this:
private void start(int number)
{
if(number == size)
{
//exit
}
else
{
new AsyncTask123().execute(link, method);
}
}
private class AsyncTask123 extends AsyncTask<> {
protected void onPostExecute() {
start(i++);
}
}
This should work, you just have to fit it for your needs.
if you want AsyncTask in for loop then you should call your class like:
new AsyncTask123().execute(link, method);
Not like :
task = new AsyncTask123();
task.execute(link, method);

Parsing JSON then adding multiple strings to an ArrayList

Currently working on an app that takes results from a search, parses the JSON object returned, and then adds the resulting pieces into a few ArrayLists within a class created called VenueList.
Here is the method that receives the results from the service and parses the JSON:
private static List<String> getResultsFromJson(String json) {
ArrayList<String> resultList = new ArrayList<String>();
try {
JSONObject resultsWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray results = resultsWrapper.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
resultList.add(result.getString("text"));
}
}
catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
return resultList;
}
What results of this becomes a List variable call mResults (to clarify: mResults = getResultsFromJson(restResult);. That is then used, among other places, in the following loop that puts the results into an ArrayAdapter that is used for displaying them in a ListFragment:
for (String result : mResults) {
VenueList.addVenue(result, "HELLO WORLD");
adapter.add(result);
}
I also add the result to a class called VenueList that manages the results and makes them accessible for multiple views. It essentially just holds multiple ArrayLists that hold different types of details for each venue returned in the search. The method I use to add a venue to VenueList is below (and you can see it used in the for loop above):
public static void addVenue(String name, String geo) {
venueNames.add(name);
venueGeos.add(geo);
}
I want the addVenue method to be able to take multiple arguments and update the VenueList class. Yet, when I call the addVenue method in the for loop, I can only pass it String result (from the parameters of the loop) and can't figure out how to pass it a second argument (which should also come from the JSON parsed by getResultsFromJson) so I've used "HELLO WORLD" as a placeholder for now.
I realize getResultsFromJson only has one list returned. I need to be able to take multiple elements from the JSON object that I parse, and then add them to VenueList in the right order.
So my questions are:
1) Given the getResultsFromJson method and the for loop, how can I use the addVenue() method as designed? How do I parse multiple elements from the JSON, and then add them to the VenueList at the same time? I plan on adding more arguments to it later on, but I assume if I can make it work with two, I can make it work with four or five.
2) If that's not possible, how should the getResultsFromJson, the for loop, and the addVenue method be redesigned to work properly together?
Please let me know if you need more detail or code - happy to provide. Thank you!
EDIT - Full VenueList class:
public class VenueList {
private static ArrayList<String> venueNames;
private static ArrayList<String> venueGeos;
public VenueList() {
venueNames = new ArrayList<String>();
venueGeos = new ArrayList<String>();
}
public static void addVenue(String name, String geo) {
venueNames.add(name);
venueGeos.add(geo);
}
public static String getVenueName(int position) {
return venueNames.get(position);
}
public static String getVenueGeo(int position) {
return venueGeos.get(position);
}
public static void clearList() {
venueNames.clear();
venueGeos.clear();
}
}
Clarification: I will have additional ArrayLists for each element of data that I want to store about a venue (phone number, address, etc etc)
1) I don't think methods getResultsFromJson(String json) and addVenue(String name, String geo) fit your needs.
2) I would consider rewriting method getResultsFromJson(String json) to something like this:
private static SortedMap<Integer, List<String>> getResultsFromJson(String json) {
Map<Integer, String> resultMap = new TreeMap<Integer, String>();
//...
return resultMap;
}
where the number of keys of your map should be equal to the number of objects you're extracting info, and each one of them will properly have their own list of items just in the right order you extract them.
With this approach you can certainly change your logic to something like this:
// grab your retuned map and get an entrySet, the just iterate trough it
SortedMap<Integer, String> result = returnedMap.entrySet();
for (Entry<Integer, String> result : entrySet) {
Integer key = result.getKey(); // use it if you need it
List<String> yourDesiredItems = result.getValue(); // explicitly shown to know how to get it
VenueList.addVenue(yourDesiredItems);
}
public static void addVenue(List<String> yourDesiredItems) {
// refactor here to iterate the items trough the list and save properly
//....
}
EDIT -- as you wish to avoid the go-between map i'm assuming you need nothing to return from the method
First i'm providing you with a solution to your requirements, then i'll provide you with some tips cause i see some things that could smplify your design.
To save VenueList things directly from getResultsFromJSON do something like this:
private static void getResultsFromJson(String json) {
try {
JSONObject resultsWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray results = resultsWrapper.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
//FOR EXAMPLE HERE IS WHERE YOU NEED TO EXTRACT INFO
String name = result.getString("name");
String geo = result.getString("geo");
// and then...
VenueList.addVenue(name, geo, ..., etc);
}
} catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
}
This implies that your addVenue method should know receive all params needed; as you can see this is just a way (that you can consider a workaround to your needs), however as i don't know all requirements that lead you to code this model, i will point to a few things you might consider:
1. If there's a reason for VenueList class to use everything static, consider doing this:
static{
venueNames = new ArrayList<String>();
venueGeos = new ArrayList<String>();
//....
}
private VenueList(){
}
This way you won't need to get an instance every time and also will avoid null pointer exceptions when doing VenueList.addVenue(...) without previous instantiation.
2. Instead of having an ArrayList for every characteristic in VenueList class consider defining a model object for a Venue like this:
public class Venue{
String name;
String geo;
//... etc
public Venue(){
}
// ... getters & setters
}
then if you need that VenueList class you will just have a list o Venue objects (List<Venue>), this means that instead of calling the method addVenue, you will first create a brand new instance of Venue class and will call the setter method of each characteristic, as an example of the refactored for loop from the workaround i provided you you'd be using something like this:
List<Venue> myListOfVenues = new ArrayList<Venue>();
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
// THIS WOULD REMAIN THE SAME TO EXTRACT INFO
String name = result.getString("name");
String geo = result.getString("geo");
// and then instead of calling VenueList.addVenue(name, geo, ..., etc)...
Venue v = new Venue();
v.setName(name);
v.setGeo(geo);
// ...etc
myListOfVenues.add(v);
}
// Once you're done, set that List to VenueList class
VenueList.setVenueList(myListOfVenues);
So VenueList class would now have a single property List<Venue> venueList; and would suffer minor tweeks on methods getVenueName, etc... and everything would be more readable... i hope this helps you to get another approach to solve your problem, if i still don't make my point let me know and i'll try to help you out...

Categories

Resources