Recently I started playing with a few Kontakt beacons and my Android phone (LG L30).
I added a default region to detect all beacons:
private static final Region ALL_BEACONS_REGION = Region.EVERYWHERE;
And I initialized a new monitoringListener. The relevant code:
#Override
public void onBeaconsUpdated(Region region, List<BeaconDevice> list) {
List<BeaconDevice> beacons = new ArrayList<BeaconDevice>();
Iterator i = list.iterator();
while (i.hasNext()){
BeaconDevice beacon = (BeaconDevice)i.next();
if(beacon.getUniqueId() != null) {
beacons.add(beacon);
}
}
}
While debugging I noticed, that sometimes the uniqueId is null. That's why I am checking if it is null, but I still find it very strange. Is that common or is there a mistake in my code? And how can I uniquely identify a beacon if the name is null?
Hmm to check why getUniqueId() return NULL, we must see how you set this value.
An object you can identify uniquely by using his hashCode(). Override this method in the object to generate something uniquely.
see: overriding equals and hashCode in Java
Or if you want only prevent multiple-entries in the list, you could us a Set, which not add duplicates (compared to the your ArrayList).
see: Java - Set
Related
In order to reduce the number of API calls, I'm trying to query place details by passing several place_ids at a time (up to 10). I haven't found any useful information beyond the docs.
https://developers.google.com/android/reference/com/google/android/gms/location/places/GeoDataApi.html#getPlaceById(com.google.android.gms.common.api.GoogleApiClient, java.lang.String...)
Notably, the constructor is:
public abstract PendingResult<PlaceBuffer> getPlaceById (GoogleApiClient client, **String... placeIds**)
and the doc says: Returns Place objects for each of the given place IDs.
I don't have any problem when passing a single place_id, but when I pass a comma delimted string of id's, all of which are known to be good, I get a status = "SUCCESS" but a buffer count of 0.
Does anyone know the correct way to pass multiple id's to getPlaceById()?
Here's my code if that helps at all:
Places.GeoDataApi.getPlaceById(mGoogleApiClient, searchIds)
.setResultCallback(new ResultCallback<PlaceBuffer>() {
#Override
public void onResult(PlaceBuffer places) {
int cnt = places.getCount();
if (places.getStatus().isSuccess() && places.getCount() > 0) {
for (int i=0; i < places.getCount(); i++) {
final Place myPlace = places.get(i);
Log.d("<< cache >> ", "Place found: " + myPlace.getName());
}
} else {
Log.d("<< cache >> ", "Place not found");
}
places.release();
}
});
It's a varargs argument. You call it like this:
Places.GeoDataApi.getPlaceById(mGoogleApiClient,
"placeId1", "placeId2", "placeId3");
More detail in this SO question: How does the Java array argument declaration syntax "..." work?
Although I've read that String... can be passed as either a comma delimited string or a string array, for one reason or other, getPlaceById appears to require an array. When I use this code to prepare the place id parameter, it works fine:
String search[] = new String[idsToSearch.size()];
search = idsToSearch.toArray(search);
hi i'm wonder why my if always Toast me : "names Successfully saved!"
i'm try every thing.
public void btnSave_Clicked(View view) {
TextView txtOname = (TextView)findViewById(R.id.txtOname);
TextView txtXname = (TextView)findViewById(R.id.txtXname);
String X = txtXname.getText().toString();
String O = txtOname.getText().toString();
if((X!="") && (O!="")){
DatabaseHelper.insertName(getBaseContext(),((TextView)findViewById(R.id.txtOname))
.getText().toString());
DatabaseHelper.insertName(getBaseContext(),((TextView)findViewById(R.id.txtXname))
.getText().toString());
Toast.makeText(this,"names Successfully saved!",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this,"E",Toast.LENGTH_SHORT).show();
}
}
}
Strings are reference types in Java, and thus the reference of a dynamically created empty string will be different from your variables. Another option to isEmpty is equals.
if (!x.equals("") && !o.equals(")) {
//code
}
Though I'd probably go with isEmpty
Replace your if statement with:
if (!x.isEmpty() && !o.isEmpty()) {
//code
}
operator == compares Object reference.
.equals() compares String value.
.isEmpty() return true if String length is 0.
Strings are objects. Object instances (the value behind them) have to be compared manually with a method to assure that the content is the same.
The == operator just compares the string references ("adresses"). So when you create 2 object instances at runtime, they have different adresses even if the content is the same. Compile-time strings on the other hand are internalized, they are put into special memory and duplicates are sorted out.
System.out.println(new String("test") == new String("test"));
This will print false, because those 2 objects get created at runtime. The new keyword in the first example mandates that a new object with a new adress is created.
System.out.println("test" == "test");
This will print true, because they are String literals, which are known at runtime, you are not explicitly stating the new keyword here either. You are simply specifying that you want those literals represented in the code somehow, so the compiler internalizes them.
Good day all, I have a list of Objects (Let's call them ContactObject for simplicity). This object contains 2 Strings, Name and Email.
This list of objects will number somewhere around 2000 in size. The goal here is to filter that list as the user types letters and display it on the screen (IE in a recyclerview) if they match. Ideally, It would filter where the objects with a not-null name would be above an object with a null name.
As of right now, the steps I am taking are:
1) Create 2 lists to start and get the String the user is typing to compare to
List<ContactObject> nameContactList = new ArrayList<>();
List<ContactObject> emailContactList = new ArrayList<>();
String compareTo; //Passed in as an argument
2) Loop though the master list of ContactObjects via an enhanced for loop
3) Get the name and email Strings
String name = contactObject.getName();
String email = contactObject.getEmail();
4) If the name matches, add it to the list. Intentionally skip this loop if the name is not null and it gets added to the list to prevent doubling.
if(name != null){
if(name.toLowerCase().contains(compareTo)){
nameContactList.add(contactObject);
continue;
}
}
if(email != null){
if(email.toLowerCase().contains(compareTo)){
emailContactList.add(contactObject);
}
}
5) Outside of the for loop now as the object lists are build, use a comparator to sort the ones with names (I do not care about sorting the ones with emails at the moment)
Collections.sort(nameContactList, new Comparator<ContactObject>() {
public int compare(ContactObject v1, ContactObject v2) {
String fName1, fName2;
try {
fName1 = v1.getName();
fName2 = v2.getName();
return fName1.compareTo(fName2);
} catch (Exception e) {
return -1;
}
}
});
6) Loop through the built lists (one sorted) and then add them to the master list that will be used to set into the adapter for the recyclerview:
for(ContactObject contactObject: nameContactList){
masterList.add(contactObject);
}
for(ContactObject contactObject: emailContactList){
masterList.add(contactObject);
}
7) And then we are all done.
Herein lies the problem, this code works just fine, but it is quite slow. When I am filtering through the list of 2000 in size, it can take 1-3 seconds each time the user types a letter.
My goal here is to emulate apps that allow you to search the contact list of the phone, but seem to always to it quicker than I am able to replicate.
Does anyone have any recommendations as to how I can speed this process up at all?
Is there some hidden Android secret I don't know of that only allows you to query a small section of the contacts in quicker succession?
From this thread, it can say that Settings.Secure#ANDROID_ID can be null sometimes. On the other hand, the telephony-based ID can be null too in tablet devices and can be changed if user change the SIM card or flight mode.
Thinking of getting mac address, from this thread, sometimes the mac address cannot be got too.
Is there any solution that I can get Android unique ID that won't change in any condition?
Rendy, the code I used for that is the above (from emmby answer (with minimal modifications) of question Is there a unique Android device ID?):
public class DeviceUuidFactory {
protected static final String PREFS_FILE = "device_id.xml";
protected static final String PREFS_DEVICE_ID = "device_id";
protected volatile static UUID uuid;
public DeviceUuidFactory(Context context) {
if (uuid == null) {
synchronized (DeviceUuidFactory.class) {
if (uuid == null) {
final SharedPreferences prefs = context.getSharedPreferences(PREFS_FILE, 0);
final String id = prefs.getString(PREFS_DEVICE_ID, null);
if (id != null) {
// Use the ids previously computed and stored in the
// prefs file
uuid = UUID.fromString(id);
} else {
final String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
// Use the Android ID unless it's broken, in which case
// fallback on deviceId,
// unless it's not available, then fallback on a random
// number which we store
// to a prefs file
try {
if (!"9774d56d682e549c".equals(androidId)) {
uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
} else {
final String deviceId = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
uuid = (deviceId != null ? UUID.nameUUIDFromBytes(deviceId.getBytes("utf8")) : UUID.randomUUID());
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
// Write the value out to the prefs file
prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString()).commit();
}
}
}
}
}
/**
* Returns a unique UUID for the current android device. As with all UUIDs,
* this unique ID is "very highly likely" to be unique across all Android
* devices. Much more so than ANDROID_ID is.
*
* The UUID is generated by using ANDROID_ID as the base key if appropriate,
* falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
* be incorrect, and finally falling back on a random UUID that's persisted
* to SharedPreferences if getDeviceID() does not return a usable value.
*
* In some rare circumstances, this ID may change. In particular, if the
* device is factory reset a new device ID may be generated. In addition, if
* a user upgrades their phone from certain buggy implementations of Android
* 2.2 to a newer, non-buggy version of Android, the device ID may change.
* Or, if a user uninstalls your app on a device that has neither a proper
* Android ID nor a Device ID, this ID may change on reinstallation.
*
* Note that if the code falls back on using TelephonyManager.getDeviceId(),
* the resulting ID will NOT change after a factory reset. Something to be
* aware of.
*
* Works around a bug in Android 2.2 for many devices when using ANDROID_ID
* directly.
*
* #see http://code.google.com/p/android/issues/detail?id=10603
*
* #return a UUID that may be used to uniquely identify your device for most
* purposes.
*/
public UUID getDeviceUuid() {
return uuid;
}
}
To use that in an Activity, do the following:
UUID identifier = new DeviceUuidFactory(this).getDeviceUuid();
The options you mentioned cover pretty much all the different scenarios to get a unique ID, there's also a unique ID value provided by the OS which has been proved was incorrectly implemented by some vendors and it returns the same value for all the devices of that specific vendor, so No, there's no 1 and only best way to do it, usually you need to combine and validate if one or another exist, for example in our project:
First we go for TelephonyManager and if it exist we take it from there
If not( as is the case in most tablets), then we go for MAC address
If not, then we use the Android unique ID provided in Settings.
Hope it helps!
Regards!
I currently have a statement which reads
if(Arrays.asList(results).contains("Word"));
and I want to add at least several more terms to the .contains parameter however I am under the impression that it is bad programming practice to have a large number of terms on one line..
My question is, is there a more suitable way to store all the values I want to have in the .contains parameters?
Thanks
You can use intersection of two lists:
String[] terms = {"Word", "Foo", "Bar"};
List<String> resultList = Arrays.asList(results);
resultList.retainAll(Arrays.asList(terms))
if(resultList.size() > 0)
{
/// Do something
}
To improve performance though, it's better to use the intersection of two HashSets:
String[] terms = {"Word", "Foo", "Bar"};
Set<String> termSet = new HashSet<String>(Arrays.asList(terms));
Set<String> resultsSet = new HashSet<String>(Arrays.asList(results));
resultsSet.retainAll(termSet);
if(resultsSet.size() > 0)
{
/// Do something
}
As a side note, the above code checks whether ANY of the terms appear in results. To check that ALL the terms appear in results, you simply make sure the intersection is the same size as your term list:
resultsSet.retainAll(termSet);
if(resultSet.size() == termSet.size())
You can utilize Android's java.util.Collections
class to help you with this. In particular, disjoint will be useful:
Returns whether the specified collections have no elements in common.
Here's a code sample that should get you started.
In your Activity or wherever you are checking to see if your results contain a word that you are looking for:
String[] results = {"dog", "cat"};
String[] wordsWeAreLookingFor = {"foo", "dog"};
boolean foundWordInResults = this.checkIfArrayContainsAnyStringsInAnotherArray(results, wordsWeAreLookingFor);
Log.d("MyActivity", "foundWordInResults:" + foundWordInResults);
Also in your the same class, or perhaps a utility class:
private boolean checkIfArrayContainsAnyStringsInAnotherArray(String[] results, String[] wordsWeAreLookingFor) {
List<String> resultsList = Arrays.asList(results);
List<String> wordsWeAreLookingForList = Arrays.asList(wordsWeAreLookingFor);
return !Collections.disjoint(resultsList, wordsWeAreLookingForList);
}
Note that this particular code sample will have contain true in foundWordInResults since "dog" is in both results and wordsWeAreLookingFor.
Why don't you just store your results in a HashSet? With a HashSet, you can benefit from hashing of the keys, and it will make your assertion much faster.
Arrays.asList(results).contains("Word") creates a temporary List object each time just to do linear search, it is not efficient use of memory and it's slow.
There's HashSet.containsAll(Collection collection) method you can use to do what you want, but again, it's not efficient use of memory if you want to create a temporary List of the parameters just to do an assertion.
I suggest the following:
HashSet hashSet = ....
public assertSomething(String[] params) {
for(String s : params) {
if(hashSet.contains(s)) {
// do something
break;
}
}
}