I'm trying to figure out the difference between accessing android string resources. The following quote is not clear to me:
Access by referene is fast
Direct access is slow
access by reference means: setTitle(R.string.title)
direct access means: setTitle(getResources().getString(R.string.title))
Now I've run some speed tests on the android emulator:
access by reference:
for(int i = 0; i< 100000; i++) {
setTitle(R.string.app_name);
}
This took 5090 milliseconds. In contrast I run the same code, using direct access:
for(int i = 0; i< 100000; i++) {
setTitle(getResources().getString(R.string.app_name));
}
This took 5191 milliseconds. I tested this with Android 4.2.2.
So for me it looks a lot like it doesn't matter which way I use the resources. Did this matter in earlier android versions? Does this matter on real devices? In other words: Does it matter which access I choose?
If more parameters of my testing are needed, I'm happy to give them. Thank you for taking the time, appreciate it a lot.
Just look at the code :
(in Activity)
public void setTitle(int titleId) {
setTitle(getText(titleId));
}
(in Context)
public final CharSequence getText(int resId) {
return getResources().getText(resId);
}
So basically, it is exactly the same thing.
What is much slower, however, is if you use Resource.getIdentifier(String, String, String) to find the ids of your resources.
Related
I created an app. I want my one app only per mobile but i can create clone of my app using Parallel Spaceļ¼Multi Accounts. So my question is how to stop to making clone of my app. Is android have any unique identifier, which is not alterable even if user reset the phone?
I think there is not a way to prevent "Parallel Space" to clone your app, that is something related with android system.
A simple workaround I use is to check whether the Parallel Space app is installed(ps package name: com.lbe.parallel.intl).
public boolean isAppInstalled(String packageName) {
try {
getPackageManager().getApplicationInfo(packageName, 0);
return true;
}
catch (PackageManager.NameNotFoundException e) {
return false;
}
}
As you can guess it is not reliable since many different apps can be used for this purpose. I didn't go further for my case but one thing that comes to my mind; if you have file write permission you can create a global file and put something there to check while opening your app.
Someone who knows how such apps work can provide better answers. If they are changing something in your apk while copying, then you can check those changes or hashcode of the apk, but it seems that they run your app in a virtual os, so this may not lead to a solution.
And there is not a successful unique id on android unfortunately. That is something I hate about android. I check different identifiers like deviceid, imei, mac address etc.. but parallel space creates new values for all of them.
After I searched a lot for a solution to stop the app cloning, I came across this idea, which is to check the path in which the app data is installed on the phone.
The following code explains the idea further:
int APP_PACKAGE_COUNT = 2; //----> my app package name is com.test.app the number is count of dots in package name
private void checkClonner() {
String path = this.getFilesDir().getAbsolutePath();
int count = getDotCount(path);
if (count > APP_PACKAGE_COUNT) {
throw new RuntimeException("This app does not work in a cloning environment");
}
}
private int getDotCount(String path) {
int count = 0;
for (int i = 0; i < path.length(); i++) {
if (count > APP_PACKAGE_COUNT) {
break;
}
if (path.charAt(i) == '.') {
count++;
}
}
return count;
}
So I'm porting my Android app over to Kindle, and expected some tweaks for compatibility, but this is getting ridiculous.
The first thing I found out was that apparently running an AsyncTask from onCreate() can cause some problems if you are also initializing your layout from onCreate() as well. That's definitely not the case in regular Android, but the end result I was getting on Kindle was parts of my layout not being displayed at all. Moving the AsyncTask to onStart solved the problem, but this was a bit surprising. I still have a problem invovling this AsyncTask though.
The purpose of this AsyncTask is to load data from online and display the result in the activity's layout. Pretty straightforward, at least on regular Android devices. Just load the data in doInBackground, then in onPostExecute apply the data to the UI to build the page.
However it seems that in some cases (not all) the data from the AsyncTask won't display on screen. for instance, some data is displayed in a GridView. I update the GridView adapter, use the adapter's notifyDataSetChanged() method, and what should happen is that the view is changed to display the data from the adapter. This process on a normal Android device works fine.
On this Kindle however the data doesn't load (again in some cases, not all, which makes this even more frustrating). I've found that if you press the Back button on the Kindle, then drag your finger off of it (so finish() isn't called), the data will sometimes show up! I get the feeling the normal behavior of notifyDataSetChanged() has been altered for Kindle's version of Android, but I'm not sure what else I'm expected to do to show data loaded into an adapter.
Has anyone run into this issue?
Also, I should note in the case of it only happening sometimes, the actual data structure remains constant, but for certain pages it works and others it does not (the app pertains to music, so for example one artist's page loads properly while the other's does not).
I've included the AsyncTask in question, it works perfectly on any Android device so I don't know what use it will be, but here it goes anyway:
private class GetAttendees extends AsyncTask<Void, Void, AttendeesSectionData> {
#Override
protected AttendeesSectionData doInBackground(Void... params) {
JsonHandler jsonHandler = new JsonHandler(getApplicationContext());
return jsonHandler.getEventAttendeesFromFb(mEvent.getFacebookEventId(), JsonHandler.FACEBOOK_FRIENDS_NO_LIKES);
}
#Override
protected void onPostExecute(AttendeesSectionData data) {
if(data != null && !data.isEmpty()) {
if(data.size() > 18) {
ArrayList<String> toShow = new ArrayList<String>();
int friendLimit = data.getFriendsAttendingIds().size();
if(friendLimit > 18)
friendLimit = 18;
for(int i = 0; i < friendLimit; i++)
toShow.add(data.getFriendsAttendingIds().get(i).getImageURL());
int toShowSizeAfterFriends = toShow.size();
if(toShowSizeAfterFriends < 18) {
int othersLimit = data.getNonFriendsAttendingIds().size();
if(othersLimit > 18 - toShowSizeAfterFriends)
othersLimit = 18 - toShowSizeAfterFriends;
for (int i = 0; i < othersLimit; i++)
toShow.add(data.getNonFriendsAttendingIds().get(i).getImageURL());
}
mFbImagesAdapter.setItems(toShow);
}
else
mFbImagesAdapter.setItems(data.unloadIntoOneArrayList());
String caption = String.format(AppSettings.ATTENDEE_HEADER_CAPTION,
//fill in the %s with:
data.getFriendsAttendingIds().size(),
data.getNonFriendsAttendingIds().size());
caption = caption.replace("*", "<b>");
caption = caption.replace("?", "</b>");
mAttendeesCaption.setText(Html.fromHtml(caption));
calculateGridSize(data.size());
}
else {
Print.log("no attendees for event " + mEvent.getVenue_FormattedLocation());
mAttendeesGrid.setVisibility(View.GONE);
mAttendeesHeaderContainer.setVisibility(View.GONE);
}
loadFacebookImages();
}
}
Thanks!
I found the solution. Oh man that took a LONG time, but I finally got it.
It's really dumb. Basically, the xml attribute android:animateLayoutChanges will totally break your layouts. I guess Kindle will attempt to animate, but fail, so the end result is nothing happening. Removing all instances of android:animateLayoutChanges from my app fixed the problem.
I hope someone else who has this issue in the future can save a ton of time by stumbling across this answer.
Does anyone know what the method hasClients does in the android sdk?
boolean com.android.ddmlib.IDevice.hasClients()
It doesn't look like its documented.
I am trying to find a way to see if an emulator is being used. Any good way to do this?
for(int i =0; i < devices.length; i++){
if(!devices[i].hasClients()){
monkeyDevice = devices[i];
}
}
When I say is being used, I mean if there is currently an application running on the device or if its receiving commands from anything.
Update
I should of mentioned that I want to test for these conditions outside from my application. I have a seperate class running outside the application that starts the application within an available emulator. I want this monkey class to know if an existing emulator is already being used for testing.
Have a look at this question to figure out if you are running in the emulator:
How can I detect when an Android application is running in the emulator?
On a monkey-related point, you might want to have a look at Activity.isUserAMonkey() method (since API level 8, OS 2.2). The Google DeviceAdminSample code gives a brief explanation:
/**
* If the "user" is a monkey, post an alert and notify the caller. This prevents automated
* test frameworks from stumbling into annoying or dangerous operations.
*/
private static boolean alertIfMonkey(Context context, int stringId) {
if (ActivityManager.isUserAMonkey()) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(stringId);
builder.setPositiveButton(R.string.monkey_ok, null);
builder.show();
return true;
} else {
return false;
}
}
I doubt if there is a way to make compile-time conditions in Java like #ifdef #ifndef in C++.
My problem is that have an algorithm written in Java, and I have different running time improves to that algorithm. So I want to measure how much time I save when each improve is used.
Right now I have a set of boolean variables that are used to decide during the running time which improve should be used and which not. But even testing those variables influences the total running time.
So I want to find out a way to decide during the compilation time which parts of the program should be compiled and used.
Does someone knows a way to do it in Java. Or maybe someone knows that there is no such way (it also would be useful).
private static final boolean enableFast = false;
// ...
if (enableFast) {
// This is removed at compile time
}
Conditionals like that shown above are evaluated at compile time. If instead you use this
private static final boolean enableFast = "true".equals(System.getProperty("fast"));
Then any conditions dependent on enableFast will be evaluated by the JIT compiler. The overhead for this is negligible.
javac will not output compiled code that is unreachable. Use a final variable set to a constant value for your #define and a normal if statement for the #ifdef.
You can use javap to prove that the unreachable code isn't included in the output class file. For example, consider the following code:
public class Test
{
private static final boolean debug = false;
public static void main(String[] args)
{
if (debug)
{
System.out.println("debug was enabled");
}
else
{
System.out.println("debug was not enabled");
}
}
}
javap -c Test gives the following output, indicating that only one of the two paths was compiled in (and the if statement wasn't):
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String debug was not enabled
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
I think that I've found the solution, It's much simpler.
If I define the boolean variables with "final" modifier Java compiler itself solves the problem. Because it knows in advance what would be the result of testing this condition.
For example this code:
boolean flag1 = true;
boolean flag2 = false;
int j=0;
for(int i=0;i<1000000000;i++){
if(flag1)
if(flag2)
j++;
else
j++;
else
if(flag2)
j++;
else
j++;
}
runs about 3 seconds on my computer.
And this one
final boolean flag1 = true;
final boolean flag2 = false;
int j=0;
for(int i=0;i<1000000000;i++){
if(flag1)
if(flag2)
j++;
else
j++;
else
if(flag2)
j++;
else
j++;
}
runs about 1 second. The same time this code takes
int j=0;
for(int i=0;i<1000000000;i++){
j++;
}
Never used it, but this exists
JCPP is a complete, compliant,
standalone, pure Java implementation
of the C preprocessor. It is intended
to be of use to people writing C-style
compilers in Java using tools like
sablecc, antlr, JLex, CUP and so
forth. This project has has been used
to successfully preprocess much of the
source code of the GNU C library. As
of version 1.2.5, it can also
preprocess the Apple Objective C
library.
http://www.anarres.org/projects/jcpp/
If you really need conditional compilation and you use Ant, you might be able to filter your code and do a search-and-replace in it.
For example: http://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html
In the same manner you can, for example, write a filter to replace LOG.debug(...); with /*LOG.debug(...);*/. This would still execute faster than if (LOG.isDebugEnabled()) { ... } stuff, not to mention being more concise at the same time.
If you use Maven, there is a similar feature described here.
If you use IntelliJ there is a plugin called Manifold, that - along with many other features - allows one to use #ifdef and #define in Java.
Plugin url:
https://manifold.systems/
Preprocessor information:
https://github.com/manifold-systems/manifold/tree/master/manifold-deps-parent/manifold-preprocessor
PS: I am not affiliated with them, we just happen to use it, and it helps a lot with out workflow (which is likely NOT typical for Java development)
Use the Factory Pattern to switch between implementations of a class?
The object creation time can't be a concern now could it? When averaged over a long running time period, the biggest component of time spent should be in the main algorithm now wouldn't it?
Strictly speaking, you don't really need a preprocessor to do what you seek to achieve. There are most probably other ways of meeting your requirement than the one I have proposed of course.
final static int appFlags = context.getApplicationInfo().flags;
final static boolean isDebug = (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
I searched in the web but i couldn find a single article dealing in a straight forward way on how to find the vibrate on/off logs in logcat. If anybody who is aware of the procedure, please enlighten me. Once again i need it specifically to check if my app triggers vibrator or not...
Vibration data is not logged by default. Fortunately, there is some code in HardwareServices.java that can be enabled to provide exactly what you want. Keep in mind that since this is part of the framework, changing it will require you to rebuild and reflash your device. If you are running on an ADP or the emulator this should be easy. It might be a bit more challenging if you are doing this on another device.
Locate the following code and replace false with true and you should be all set.
if (false) {
String s = "";
int N = pattern.length;
for (int i=0; i<N; i++) {
s += " " + pattern[i];
}
Log.i(TAG, "vibrating with pattern: " + s);
}