Very strange error. I'm trying to implement a simple interface in a non-activity class within my android application. However, I get a run-time error. If I remove the implementation, the code works fine. I will let the code speak for itself, feel free to chime in. Thanks!
This throws a ClassNotFoundException when instantiating an instance of Globals
public class Globals implements IReceivable {
private volatile static Globals uniqueGlobal;
private static ClientSocket clientSocket;
private Globals()
{
}
public static Globals getInstance() {
synchronized (Globals.class) {
if (uniqueGlobal == null) {
uniqueGlobal = new Globals();
uniqueGlobal.InitializeClient();
}
}
return uniqueGlobal;
}
#Override
public void MessageReceived(UUID clientId, String message) {
// TODO Auto-generated method stub
}
}
When I remove it, everything works just fine
public class Globals {
private volatile static Globals uniqueGlobal;
private static ClientSocket clientSocket;
private Globals()
{
}
public static Globals getInstance() {
synchronized (Globals.class) {
if (uniqueGlobal == null) {
uniqueGlobal = new Globals();
uniqueGlobal.InitializeClient();
}
}
return uniqueGlobal;
}
}
EDIT
Here is the IReceivable interface
public interface IReceivable {
public void MessageReceived(UUID clientId, String message);
}
And the exact error:
12-02 10:14:15.859: E/AndroidRuntime(546):
java.lang.NoClassDefFoundError: com.example.utilities.Globals
The line that is throwing the error looks like this:
Globals global = Globals.getInstance();
Ok, solved the problem. What I didn't tell you is that the interface is within a jar file that I have added to my project.
I added the jar file to my project and correctly included it into the build path, however, I did not add the jar file to the 'libs' folder. Apparently, android at runtime will only include jar files that are within this folder.
Good learning experience for me. Thanks!
Related
I'm trying to create a Lint rule in my Android code that checks the number if injections in a constructor, so if I exceed a certain number for a view model, for example, I will raise a lint warning.
I know that I have to implement a UastScanner in my Lint Detector, but I am getting lost because I cannot find good documentation. Has someone else ever done something like this? Or where can I find good deocumentation about it?
Thanks!
* NOTE - Read entire answer for edited solution. *
I was able to write the UAST conversion like so:
public class NumberOfDependenciesInjectedDetector extends Detector implements Detector.UastScanner {
private static final int NUMBER_OF_INJECTIONS_ALLOWED = 5;
private static final Class<? extends Detector> DETECTOR = NumberOfDependenciesInjectedDetector.class;
private static final EnumSet<Scope> SCOPE = Scope.JAVA_FILE_SCOPE;
private static final Implementation IMPLEMENTATION = new Implementation(DETECTOR, SCOPE);
public static final Issue ISSUE = Issue.create(
"NumberOfDependenciesInjected",
"Limit number of injections in a class via constructor",
"A longer description here",
Category.CORRECTNESS,
10,
Severity.ERROR,
IMPLEMENTATION
);
#Override
public List<Class<? extends UElement>> getApplicableUastTypes() {
return Collections.<Class<? extends UElement>>singletonList(UClass.class);
}
#Override
public UElementHandler createUastHandler(JavaContext context) {
return new ConstructorVisitor(context);
}
private static class ConstructorVisitor extends UElementHandler {
private JavaContext javaContext;
private ConstructorVisitor(JavaContext javaContext) {
this.javaContext = javaContext;
}
#Override
public void visitClass(UClass clazz){
UMethod[] methods = clazz.getMethods();
for(UMethod method : methods){
if(!method.isConstructor()) continue;
if (method.getParameterList().getParametersCount() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, method, javaContext.getLocation(method), "Injections exceed allowed value of " + NUMBER_OF_INJECTIONS_ALLOWED);
}
}
}
}
}
However, it seems that this still doesn't pick up Kotlin source files... very confusing.
EDIT: 12/19/17 - FIXED
The problem was two-fold:
1) There was indeed a hidden usage of a Psi method that was blocking the check from working. The visitClass method should not use getParameterList() but instead, getUastParameters(). Replace visitclass above with:
#Override
public void visitClass(UClass clazz){
UMethod[] methods = clazz.getMethods();
for(UMethod method : methods){
if(!method.isConstructor()) continue;
if (method.getUastParameters().size() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, clazz, javaContext.getLocation(method), "Injections exceed allowed value of " + NUMBER_OF_INJECTIONS_ALLOWED);
}
}
}
2) After speaking with Tor Norbye directly on the lint-dev group, he pointed out that Android Studio 3.0 in fact lint does not work externally with kotlin and therefore was not expected to work as described here. Upgrading to Android Studio 3.1 Canary and running the linter produced the expected report.
So I was able to find a solution using JavaScanner, but I haven't found anything yet using UastScanner (which it is what I want to use, since we have Kotlin classes too):
public class NumberOfDependenciesInjectedDetector extends Detector implements Detector.JavaScanner {
private static final int NUMBER_OF_INJECTIONS_ALLOWED = 5;
private static final Class<? extends Detector> DETECTOR = NumberOfDependenciesInjectedDetector.class;
private static final EnumSet<Scope> SCOPE = Scope.JAVA_FILE_SCOPE;
private static final Implementation IMPLEMENTATION = new Implementation(DETECTOR, SCOPE);
public static final Issue ISSUE = Issue.create(
"NumberOfDependenciesInjected",
"Limit number of injections in a class via constructor",
"A longer description here",
Category.CORRECTNESS,
10,
Severity.ERROR,
IMPLEMENTATION
);
#Override
public boolean appliesTo(Context context, File file) {
return true;
}
#Override
public Speed getSpeed(Issue issue) {
return Speed.FAST;
}
#Override
public List<Class<? extends Node>> getApplicableNodeTypes() {
return Collections.<Class<? extends Node>>singletonList(ConstructorDeclaration.class);
}
#Override
public AstVisitor createJavaVisitor(JavaContext context) {
return new ConstructorVisitor(context);
}
private static class ConstructorVisitor extends ForwardingAstVisitor {
private JavaContext javaContext;
private ConstructorVisitor(JavaContext javaContext) {
this.javaContext = javaContext;
}
#Override
public boolean visitConstructorDeclaration(ConstructorDeclaration node) {
if (node.astParameters().size() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, node, javaContext.getLocation(node), "My message goes here");
return true;
}
return false;
}
}
}
I need to determine in runtime from code if the application is run under TestInstrumentation.
I could initialize the test environment with some env/system variable, but Eclipse ADK launch configuration would not allow me to do that.
Default Android system properties and environment do not to have any data about it. Moreover, they are identically same, whether the application is started regularly or under test.
This one could be a solution: Is it possible to find out if an Android application runs as part of an instrumentation test but since I do not test activities, all proposed methods there won't work. The ActivityManager.isRunningInTestHarness() method uses this under the hood:
SystemProperties.getBoolean("ro.test_harness")
which always returns false in my case. (To work with the hidden android.os.SystemProperties class I use reflection).
What else can I do to try to determine from inside the application if it's under test?
I have found one hacky solution: out of the application one can try to load a class from the testing package. The appication classloader surprisingly can load classes by name from the testing project if it was run under test. In other case the class is not found.
private static boolean isTestMode() {
boolean result;
try {
application.getClassLoader().loadClass("foo.bar.test.SomeTest");
// alternatively (see the comment below):
// Class.forName("foo.bar.test.SomeTest");
result = true;
} catch (final Exception e) {
result = false;
}
return result;
}
I admit this is not elegant but it works. Will be grateful for the proper solution.
The isTestMode() solution did not work for me on Android Studio 1.2.1.1. Almighty Krzysztof from our company tweaked your method by using:
Class.forName("foo.bar.test.SomeTest");
instead of getClassLoader(). Thanks for Krzysztof!
We created a solution to pass parameters to the MainActivity and use it inside the onCreate method, enabling you to define how the Activity will be created.
In MainActivity class, we created some constants, which could also be an enum. We created a static attribute too.
public class MainActivity {
public static final int APPLICATION_MODE = 5;
public static final int UNIT_TEST_MODE = 10;
public static final int OTHER_MODE = 15;
public static int activityMode = APPLICATION_MODE;
(...)
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
switch (activityMode) {
case OTHER_MODE:
(...)
break;
case UNIT_TEST_MODE:
Log.d(TAG, "Is in Test Mode!");
break;
case APPLICATION_MODE:
(...)
break;
}
(...)
}
(...)
}
We made MainActivityTest class abstract, created a setApplicationMode and called this method inside the setUp() method, before calling the super.setUp() method.
public abstract class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
protected void setUp() throws Exception {
setApplicationMode(); // <=====
super.setUp();
getActivity();
(...)
}
(...)
public void setApplicationMode() {
MainActivity.activityMode = MainActivity.UNIT_TEST_MODE;
}
}
All other test classes inherit from MainActivityTest, if we want it to have another behaviour, we can simply override the setApplicationMode method.
public class OtherMainActivityTest extends MainActivityTest {
(...)
#Override
public void setApplicationMode() {
MainActivity.activityMode = MainActivity.OTHER_MODE;
}
}
The user nathan-almeida is the friend that is co-author of this solution.
I have an app that uses custom Exceptions, such as this:
public class SomeException extends Exception{
private int iCode;
private String iMessage;
public SomeException(){
iCode = 201;
iMessage = **//Get the localized string R.string.error_201??**
}
#Override
public String getMessage() {
return iMessage;
}
#Override
public int getCode() {
return iCode;
}
}
Obviously, I want lo localize the error message. I have possible solutions but non of them satisfy me.
1) Pass "Context" to the constructor, and do ctx.getString(R.string.error_201)
--> Fail, as this Exceptions are sometimes thrown from MODEL classes, so they don't have a Context
2) Pass "Context" when retriveing the message in getMessage() function,
--> Fail, It's necesary to override the super method, to work as all other Exceptions.
Solution I have now: All activities in my app have this onCreate:
public void onCreate(...){
Utils.RESOURCES = getResources();
...
}
Very dirty code... I don't like the solution. My question is then,: is there a way to access the resources without the Context? And most important, How would an application such as mine solve this problem?
What about
public class MyException extends Exception {
private int iCode;
public MyException(int code) {
this.iCode = code;
}
#Override
public String getMessage() {
return "MyException code " + String.valueOf(iCode);
}
public String getLocalizedMessage(Context ctx) {
String message;
if (iCode == 201)
message = ctx.getString(R.string.error_201);
else if (iCode == 202)
message = ctx.getString(R.string.error_202);
// ...
}
}
Even if there was way to access context in different way, you should not do it. If you need to emit exceptions where you cannot pass Context, you should be able to access context before you display such error. I cannot see reason why you should create localized error messages from constructor. You can log to logcat not localized versions if you need. And where you want to display something in UI, you should have context at hand.
You can access only system wide resources without Context.
You need a Context, so I would suggest You to get it as soon as possible, and make it available through a static method or variable. You do the same thing in every Activity, but there is a cleaner method. You should make a custom Application, and override its onCreate() to make the resources public:
public class App extends Application {
private static Resources myResources;
#Override
public void onCreate() {
myResources = getBaseContext().getResources();
super.onCreate();
}
public static Resources getMyResources(){
return myResources;
}
}
The other thing you have to do is to set the Application in your manifest:
<application
android:name="{your_package}.App"
...
Now you can access the resources in all of your Activity without any preparation. Your custom Exception class could also use the externalized resources.
I have a library that I plan on using in dex form. I want to compile directly against this library, but not export it. Instead I want to drop it in my resources and use a class loader to actually instantiate it.
So here's my library:
public class Foo {
public doFoo(String message) {
}
public doFoo(int count, String message) {
}
}
Now I want to call doFoo(). A lot. More than it's probably reasonable to use reflection for. Right now it works with:
public class FooConsumer {
private final DexClassLoader fooLoader;
public FooConsumer(DexClassLoader fooLoader) {
this.fooLoader = fooLoader;
}
public void go() {
Class<?> fooClass = fooLoader.loadClass("com.library.Foo");
Object fooInstance = fooClass.newInstance();
Method fooMethodDoFoo = fooClass.getMethod("doFoo", String.class);
fooMethodDoFoo.invoke(fooInstance, "Hello World");
}
This is obviously fugly. Especially since I haven't included any of the exception handling, as there are half a dozen throwables to catch in there. I could cache a bunch of stuff, helping me with speed a bit, but not a lot.
Normally I'd have both aware of a third library that has an interface, but the library has some static methods and I can't edit it anyway. It'd be really nice if I could do something like:
public class FooConsumer {
private FooAccessor accessor;
public FooConsumer(DexClassLoader fooLoader) {
Object fooInstance = fooLoader.loadClass("com.library.Foo").newInstance();
Log.i("TEST", "fooInstance: " + fooInstance);
this.accessor = new FooAccessor(fooInstance);
}
public void go() {
accessor.doFoo("Hello World");
}
private static class FooAccessor {
private Foo fooInstance;
public FooAccessor(Object instance) {
fooInstance = (Foo)instance;
}
public void doFoo(String message) {
fooInstance.doFoo(message);
}
}
}
See what I did there? The inner class is just a wrapper around the Foo object, I've linked against it, but not exported it, and all is good in the world. But it doesn't work. In logcat I get
I/TEST: fooInstance: com.library.Foo#413b1b68
E/AndroidRuntime: java.lang.NoClassDefFoundError: com.library.Foo
...
Is there a way to have FooAccessor use the class loader I passed in? Or is the use of class loaders a damnation into reflection hell.
You might want to take a look at this gist.
https://gist.github.com/nickcaballero/7045993
It uses reflection to merge the new DexClassLoader to in-stock BaseDexClassLoader.
I am not sure I did the right thing. The main reason for my doubts is that I cannot find, in this or other forums, someone who has done a similar thing.
I created an abstract java class in my project. Named it lib. I put there several structures and methods used by all other classes in the project.
It works for me, but I want to know if there is a more accepted method of gathering all common methods and structures.
Note: All methods of course are declared as public static.
Note II: I did not know how to get the context within the abstract class, so if needed I had to pass it as argument to the method.
Is this wat you are looking for?
public abstract class AbstractActivity extends Activity{
public static synchronized boolean showAlertBox(Context ctx,final String title,final String message,final String okBtnTxt,final OnClickListener clickListener){
AlertDialog.Builder alertbox; alertbox = new AlertDialog.Builder(ctx);
this.runOnUiThread(new Runnable() {
#Override
public void run() {
alertbox.setTitle(title);
alertbox.setMessage(message);
if(okBtnTxt!=null || clickListener!=null)
alertbox.setNeutralButton(okBtnTxt,clickListener);
alertbox.show();
.....
}
});
return true;
}
}
In the class extending this abstract class you can just call it by using showAlertBox(this);
Other wise use AbstractActivity.showAlertBox(Context);
Well, thanks to #Matt Wolfe's comment I came to know that what I did is called "Utility class" and it is widely used to share common code in a project.
The general template is:
public abstract class lib {
public static final int ZERO = 0;
public static final int ONE = 1;
public static final int TWO = 2;
public static void func1(int i) {
}
public static void func2(int i, String s) {
}
}
and you can use it like this from any other code:
...;
lib.func1( lib.ZERO );
lib func2( lib.TWO, "sandwich" );
...;
Knowing that makes me confident that what I did is OK.
It would be perfect to find a way to avoid the prefix lib. and just have ECLIPSE, and the compiler, find the right import and recognize the function with just its name, like they do for global libraries.