In my application, each user signs in with a phone number. In other words, each username corresponds to a different number. I want to detect which phone contacts are using this application in a way. However, I could not determine how should I do this. At first, I think about querying for each contact and get users_in_contacts by using an OR query at the end. This method is given in this answer:
public void getFriends(List<String> numbers) {
List<ParseQuery<ParseUser>> queries = new ArrayList<ParseQuery<ParseUser>>();
for (String number : numbers) {
ParseQuery<ParseUser> parseQuery = ParseUser.getQuery();
parseQuery.whereEqualTo("username", number);
queries.add(parseQuery);
}
ParseQuery<ParseUser> userQuery = ParseQuery.or(queries);
userQuery.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> numberList, ParseException e) {
if (e == null) {
for (int i = 0; i < numberList.size(); i++) {
Log.v("" + i + ". user_contact", numberList.get(i).getUsername());
}
}
}
});
}
It is a working solution but I do not want to burst too many queries and exceed the limit of request per second. Thus, I want to know is there a better alternative or not.
In short, how can I achieve to find the users that are in contacts as fast and costless (with respect to request per second) as possible? I will be all ears to every advice and alternative ways comes from you. Thank you in advance.
There is a querying method named as .whereContainedIn() in Parse. By using this query, I can get users which are already in my contracts without using any other query. I put all of my contracts (which associated with a phone number) as parameter in this method and it worked. I wrote a AsyncTask to perform these operations and monitor the results in a ListView. If you give any advice to increase the performance of this task, I will appreciate it.
public class RetrieveContactedUsersTask extends AsyncTask<String, Void, String> {
private Activity activity;
HashMap<String, String> contactsMap = new HashMap<>();
String[] contactedUserNumbers;
ListView contactsView;
public RetrieveContactedUsersTask (Activity activity, ListView contactsView) {
this.activity = activity;
this.contactsView = contactsView;
}
#Override
protected String doInBackground(String... params) {
retrieveContactList();
return "Executed";
}
#Override
protected void onPostExecute(String result) {
TreeMap<String, String> contactedUsersMap = new TreeMap<>();
for (int i = 0; i < contactedUserNumbers.length; i++) {
contactedUsersMap.put(contactsMap.get(contactedUserNumbers[i]), contactedUserNumbers[i]);
}
contactsView.setAdapter(new ContactAdapter(activity, contactedUsersMap));
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
public void retrieveContactList() {
Cursor phones = null;
try {
phones = activity.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while (phones.moveToNext())
{
String _number = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)).replaceAll("\\s+", "");
String _name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
contactsMap.put(_number, _name);
}
phones.close();
} catch ( Exception e ) {}
finally {
if(phones != null){
phones.close();
}
}
try {
retrieveContactedUsers(contactsMap);
} catch (ParseException e) {
e.printStackTrace();
}
}
public void retrieveContactedUsers(Map<String, String> numbers) throws ParseException {
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereContainedIn("username", numbers.keySet());
List<ParseUser> users= query.find();
contactedUserNumbers = new String[users.size()];
for (int i = 0; i < users.size(); i++) {
String value = users.get(i).getUsername();
contactedUserNumbers[i] = value;
}
}
}
Related
I know this question has been asked a lot but I still can't figure out how on my code. I'm trying to get values out of this block of code:
private void getAnswerKey(){
class GetAnswerKey extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
JSON_STRING = s;
showAnswerKey();
}
#Override
protected String doInBackground(Void... params) {
RequestHandler rh = new RequestHandler();
String s = rh.sendGetRequest(Configuration.URL_GET_ANSWER);
return s;
}
}
GetAnswerKey gA = new GetAnswerKey();
gA.execute();
}
private void showAnswerKey () {
correctAnswers = new ArrayList<Integer>();
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(JSON_STRING);
JSONArray result = jsonObject.getJSONArray(Configuration.TAG_JSON_ARRAY);
for (int i = 0; i < result.length(); i++) {
JSONObject jo = result.getJSONObject(i);
int answerKey = jo.getInt(Configuration.TAG_ANSWERKEY);
correctAnswers.add(answerKey);
System.out.println((i + 1) + "a. " + options[correctAnswers.get(i)]); //data are there
}
} catch (JSONException e) {
e.printStackTrace();
}
}
How do I access correctAnswers arrayList on my main activity? correctAnswers itself isn't empty in this code, but when I tried accessing it on other method, it's null. I've tried passing data to other method. Still return null. I have the arrayList as global variable. Any ideas how??
Like suvojit_007 might have correctly assumed, you may be attempting to access the arraylist before it is populated..
You can use interfaces. Create your interface...
public interface ResponseInterface {
public void getResponse(String data);
}
In your AsyncTask declare your interface
private ResponseInterface responseInterface;
Create a constructor within the AsyncTask with the interface as a parameter
public GetAnswerKey(ResponseInterface responseInterface) {
this.responseInterface = responseInterface;
}
Within your onPostExecute, call the interface
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
responseInterface.getResponse(s);
}
... and finally when executing your AsyncTask, do this...
new GetAnswerKey(new ResponseInterface() {
#Override
public void getResponse(String data) {
// do whatever you want with your answers here.
// Also, whatever function that is accessing the
// arrayList, call it here, that way you avoid any
// possibility of the arrayList being null
}
}).execute();
I am trying to make a complex SQLite query using AsyncTask and it results in ANR. I can get where the problem is. Here is my AsyncTask class:
private void callBackground(String type, int page, Date date){
SetParamsForQuery params = new SetParamsForQuery(type, page, date);
backgroundTask backgroundTask = new backgroundTask();
backgroundTask.execute(params);
}
private static class SetParamsForQuery {
String type;
int page;
Date sDate;
public SetParamsForQuery(String type, int page, Date date) {
this.type = type;
this.page = page;
this.sDate = date;
}
}
private class backgroundTask extends AsyncTask<SetParamsForQuery, Void, HashMap<String, ArrayList<ArrayList<esProperty>>>>
{
#Override protected void onPreExecute()
{
}
#Override protected HashMap<String, ArrayList<ArrayList<esProperty>>> doInBackground(SetParamsForQuery... params) {
return esData.requestData(params[0].type, params[0].page, params[0].sDate);
}
#Override protected void onPostExecute(HashMap<String, ArrayList<ArrayList<esProperty>>> result)
{
Log.d(TAG, " result "+ result.size());
if(mode == R.string.today)
otherChart(result, TODAY);
if(mode == R.string.week)
otherChart(result, WEEK);
if(mode == R.string.month)
otherChart(result, MONTH);
}
}
here is my requestData method
public HashMap<String,ArrayList<ArrayList<esProperty>>> requestData(final String mode, final int page,final Date second){
es = new esDatabaseHandler();
HashMap<String, ArrayList<ArrayList<esProperty>>> hash = new HashMap<>();
try{
ActiveAndroid.beginTransaction()
for (int i = 0; i < 24; i++) {
if (page == 1) {
Calendar c = Calendar.getInstance();
hash = es.createHash(es.getDayFromToday(c.getTime(), too, page), null, mode);
}
else {
hash = es.createHash(es.getDayFromToday(second, too, page), null, mode);
}
}
Log.d(TAG, " Background "+ hash.size());
ActiveAndroid.setTransactionSuccessful();
}
finally {
ActiveAndroid.endTransaction();
}
}
The method requestData is running queries in loop in SQLite and returning hash. I know the reasons why ANR happens but it seems like I am doing correct
Well, syntax is correct, but you are forcing UI update all at once in your onPostExecute method. You should update the Activity little by little, extracting a bunch of data and passing it to publishProgress() AsyncTask method. Your way, it is too much to handle for the Main Thread.
I am trying to get records from parse. My table in parse contains an array of pointers; I was facing difficulties to write parse query, so I first save array of pointers in an ArrayList, now I make a for loop to execute the query; for each loop iteration, I want to get records from parse and update local db then same as for next iterations. But this is creating some different problems. parse getInBackground is not working sequentially.... my outer for loop completely executes then parse method called due to which I am facing problems to save values in local db.
public void insertGroupsInDB(ArrayList<TempGroupClass> temp)
{
Log.d(TAG,"insertGroupsInDB: temp size:"+temp.size());
for(int i = 0;i<temp.size();i++) `//my target is to make inner query run till no of loop times and for each iterations inner parse query will run and then insert records in db against outer insertion group`
{
Groups grp = new Groups();
grp.setGroupTitle(temp.get(i).getGroupTitle());
grp.setGroupType(temp.get(i).getGroupType());
grp.setParseObjectId(temp.get(i).getParseObjectId());
long groupinsert = (YouinDatabase.getInstance(context)).addGroup(grp,context);
//}
/*try
{
final CountDownLatch latch = new CountDownLatch(1);*/
if(groupinsert != -1)
{
//now insert friends
//long friendInsertId = YouinDatabase.getInstance(context).addFriend();
//now get friends from members id
Log.d(TAG,"groups inserted successfully:"+groupinsert);
final ArrayList<Integer> list = new ArrayList<Integer>();
if(temp.get(i).getFriendObjectIdList().size() > 0)
{
for(int j =0;j<temp.get(i).getFriendObjectIdList().size();j++)
{
Log.d(TAG," >>>>>>>>>>>>>>>friend objectId>>>>>>>>>>>>>>:"+temp.get(i).getFriendObjectIdList().get(j));
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereContainedIn("objectId",temp.get(i).getFriendObjectIdList());
query.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> arg0,
ParseException arg1) {
// TODO Auto-generated method stub
if(arg1 == null)
{
//Log.d(TAG,"arg0 size:"+arg0.size());
if(arg0.size() >0)
{
for(int i = 0;i<arg0.size();i++)
{
Log.d(TAG,"arg0.size():"+arg0.size());
Friend f = new Friend();
f.setUsername(arg0.get(0).getString("username"));
f.setParseObjectId(arg0.get(0).getObjectId());
f.setHasAdded(false);
boolean userAlreadyExist = YouinDatabase.getInstance(context).checkUserExistInFriendTable(arg0.get(0).getString("username"));
long friendInsertId = -1;
ArrayList<Integer> list = new ArrayList<Integer>();
int friendid;
if(!userAlreadyExist)
{
// Log.d(TAG,"friend Already not exist :"+userAlreadyExist);
friendInsertId = YouinDatabase.getInstance(context).addFriend(f);
list.add(YouinDatabase.getInstance(context).findFriendIdOfLatestRecord());
friendid = YouinDatabase.getInstance(context).findFriendIdOfLatestRecord();
}
else
{
//Log.d(TAG,"friend Already exist :"+userAlreadyExist);
//list.add(YouinDatabase.getInstance(context).getFriendIdFromFriendName(arg0.get(0).getString("username")));
friendid = YouinDatabase.getInstance(context).getFriendIdFromFriendName(arg0.get(0).getString("username"));
}
// Log.d(TAG,"list size 1 :"+list.size());
int latestGroupInsertId = YouinDatabase.getInstance(context).findGroupIdOfLatestRecord();
long id = YouinDatabase.getInstance(context).addFriendInConnection(friendid,latestGroupInsertId);
//now update user setHasAdded
long updateFriendTable = -1;
if(id != -1)
{
updateFriendTable = YouinDatabase.getInstance(context).updateFriendTable(friendid);
}
Log.d(TAG,">>>>updated friend id information:>>>>");
if(updateFriendTable != -1)
{
Friend friendDetails = YouinDatabase.getInstance(context).getFriendDetailsFromFriendId(friendid);
Log.d(TAG,"friend name:"+friendDetails.getUsername());
Log.d(TAG,"friend:"+friendDetails.getParseObjectId());
Log.d(TAG,"friend added :"+friendDetails.isHasAdded());
Log.d(TAG,"groupId:"+latestGroupInsertId);
}
//YouinDatabase.getInstance(context).get
}
Log.d(TAG,"list size 2"+list.size());
}
}
else
{
Log.d(TAG,"arg1 != null:"+arg1.getMessage());
}
}
});
}
// Log.d(TAG,"list size:"+list.size());
}
//latch.countDown();
}
/*latch.await();
}
catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
*/
}
Right now, the problem is that my outer loop executes twice one after another and then after the loop ends, then my parse method brings data from parse ...due to which it's only updating record in db against last group id ...and it's not inserting records against first groupId
How to resolve this issue? I have used this technique because I failed to write query to get object result of array of pointers using parse.
You could use find() which should do a synchronous operation which might hold up your ui. I have not used parse yet so i dont know. Or you can set up something like below. Remove the outer and check conditions in your callback to determine when to launch the next query.
private int j = 0;
private int loopnumber = temp.size();
ArrayList<TempGroupClass> temp; //setup temp somewhere else
private void doQuery() {
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereContainedIn("objectId",temp.get(i).getFriendObjectIdList());
query.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> arg0,
ParseException arg1) {
// TODO Auto-generated method stub
if(arg1 == null)
{
...
...
else
{
Log.d(TAG,"arg1 != null:"+arg1.getMessage());
}
//at the end call the same method to start a query if the loop conditions have not been reached.
if(++i < loopnumber) {
doQuery();
}
}
});
}
}
i have around 13000 records on one table(HashTag -classname) . i want to retrieve all of them on a single query. but parse allows only 1000 per query. any other ways get the all the records..
ParseQuery<ParseObject> query = ParseQuery.getQuery("HashTag");
query.whereExists("Tag"); query.orderByAscending("Type"); query.setLimit(1000);
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> list,
ParseException e) {
// TODO Auto-generated method stub
if (e == null)
{
if (list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
ParseObject p = list.get(i);
String tagid = p.getString("Tag");
String Type = p.getString("Type");
class2 c2 = new class2();
c2.type = "" + Type;
c2.tag = "" + tagid;
listClass2.add(c2);
}
}
Sure, you can run multiple queries on the same table, with query's skip property incremented by 1000 each time:
Get the total number of records via query.count(), and use it to set a 'skip' variable
Run a new query for each 1000 records, updating your skip property accordingly
Process records as normal when each query returns
Something like this:
ParseQuery<ParseObject> query = ParseQuery.getQuery("HashTag");
query.whereExists("Tag");
query.countInBackground(new CountCallback() {
public void done(int count, ParseException e) {
if (e == null) {
// The count request succeeded. Run the query multiple times using the query count
int numQueries = Math.ceil(count / 1000); //Gives you how many queries to run
for(int skipNum = 0; l < numQueries; l++){
ParseQuery<ParseObject> query = ParseQuery.getQuery("HashTag");
query.whereExists("Tag"); query.orderByAscending("Type");
query.setLimit(skipNum * 1000);
query.findInBackground(new FindCallback<ParseObject>() {
//Run your query as normal here
}
}
} else {
// The request failed
}
}
//Declare a global variable for storing the complete data
private static List<ParseObject>allObjects;
allObjects=new ArrayList<ParseObject>();
ParseQuery<ParseObject>query3=ParseQuery.getQuery("HashTag");
query3.whereExists("Tag");
query3.setLimit(1000);
query3.findInBackground(getallobjects());
int limit=1000;
int skip=0;
//callback method:
private FindCallback<ParseObject>getallobjects(){
return new FindCallback<ParseObject>(){
#Override
public void done(List<ParseObject>list,ParseException e){
allObjects.addAll(list);
if(list.size()==limit){
skip=skip+limit;
ParseQuery<ParseObject>query=ParseQuery.getQuery("HashTag");
query.setSkip(skip);
query.setLimit(limit);
query.findInBackground(getallobjects());
}else{
//you have full data in allobjects
for(int i=0;i<allObjects.size();i++){}
}
}}}
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>("TestObject");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> list, ParseException e) {
for(ParseObject p : list){
Log.d("--", (String) p.get("foo")+p.getCreatedAt());
}
}
});
So I have a listview where I wanted to sort the NumberOfRecords in descending order. I have a custom array adapter but I called my sorting class before I place a data in my ArrayList, this my Asynctask receiving JSON:
public class SampleListTask extends AsyncTask<String, Void, String> {
public ProgressDialog pDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(SampleActivity.this);
pDialog.setMessage("Loading...");
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected String doInBackground(String... path) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Log.d(Constant.TAG_RANKING, path[0]);
String apiRequestReturn = UtilWebService.getRequest(path[0]);
if (apiRequestReturn.equals("")) {
Log.d(Constant.TAG_SAMPLE, "WebService request is null");
return null;
} else {
Log.d(Constant.TAG_SAMPLE, "WebService request has data");
return apiRequestReturn;
}
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (null != pDialog && pDialog.isShowing()) {
pDialog.dismiss();
}
if (null == result || result.length() == 0) {
application.shortToast("No data found from server");
} else {
try {
JSONObject sampleObject = new JSONObject(result);
JSONArray jsonArray = sampleObject
.getJSONArray(Constant.TAG_SAMPLE);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject objJson = jsonArray.getJSONObject(i);
sample = new ArraySample();
sample.setId(objJson.getInt(Constant.TAG_SONGID));
sample.setThumbUrl(objJson
.getString(Constant.TAG_IMAGEURL));
sample.setTitle(objJson
.getString(Constant.TAG_NAME));
sample.setArtist(objJson
.getString(Constant.TAG_ARTIST));
sample.setDuration(Utility
.changeStringTimeFormat(objJson
.getString(Constant.TAG_MUSICLENGTH)));
sample.setNumberOfRecords(objJson
.getString(Constant.TAG_NUMBEROFRECORDS));
Collections.sort(sampleList, new SortByRecordNumber()); // This where I call the class
sampleList.add(sample);
}
} catch (JSONException e) {
e.printStackTrace();
}
setAdapterToListview();
}
}
public void setAdapterToListview() {
objRowAdapter = new RowAdapterSample(getApplicationContext(),
R.layout.item_sample, sampleList);
sampleListView.setAdapter(objRowAdapter);
}
}
And here's my sorting class:
public class SortByRecordNumber implements Comparator {
public int compare(Object o1, Object o2) {
ArraySample p1 = (ArraySample) o1;
ArraySample p2 = (ArraySample) o2;
return p2.getNumberOfRecords().compareTo(p1.getNumberOfRecords());
}
}
But the result I'm getting is:
5
15
14
0
0
Is my sorting implementation wrong? Or should I parse it to Integer before return?
You can use the following code to sort your integer list is descending order.Here we are overriding compare() so that it sorts in descending order.
//sort list in desc order
Collections.sort(myIntegerList, new Comparator<Integer>() {
public int compare(Integer one, Integer other) {
if (one >= other) {
return -1;
} else {
return 1;
}
}
});
Hope it helps.
Try with this Comparator.
Comparator objComparator = new Comparator() {
public int compare(Object o1, Object o2) {
int no1 = Integer.parseInt((String) o1);
int no2 = Integer.parseInt((String) o2);
return no1 < no2 ? -1 : no1 == no2 ? 0 : 1;
}
};
Collections.sort(myIntegerList, objComparator);
Okay, so I solved this by replacing the:
p2.getNumberOfRecords().compareTo(p1.getNumberOfRecords())
to:
(int) Integer.parseInt(p2.getNumberOfRecords()) - Integer.parseInt(p1.getNumberOfRecords())
So the simple compare of an integer in a String data type would not result correctly but to parse the string first by:
Integer.parseInt(string)
and get the true value of the number string.