I have a JNI library that I've written to capture sensor (mostly accelerometer and gyro) data and do some feature detection algorithms on said data. The features detected are configurable via a few configuration files. When the features are detected, the JNI uses a callback to notify the java side of the application. All this works great.
Now I want to be able to have multiple instances of the same JNI library running simultaneously (so I can recognize features from multiple configuration files at once). To do this, I wrote a 'wrapper' class that implements the callbacks for the JNI library and takes care of all the initialization of the library as well. I was planning on simply instantiating this class and using each instance separately. What I've found is that while each wrapper instance is distinct, the library is reused across instances almost like it was statically declared. When I try to initialize the library from the second instance of the Wrapper class, I find it has already been initialized.
Here is a wrapper class similar to the code I've written:
public class JNIWrapper {
public native int initializeJNI(String configPath);
public native void endProcessing();
public native int getInstanceIdFromJNI();
public JNIWrapper(){
try {
System.loadLibrary("libjnicode.so");
}
catch (Exception e) {
Log.e("JNI", "WARNING: Could not load libjnicode.so: " + e.getMessage());
}
}
public int initialize(String configPath){
return initializeJNI(configPath);
}
public void stop(){
endProcessing();
}
public void callbackFromJNI(int output, int instanceId){
//notify the subscribed application(s) of the feature detection
//via message passing.
}
}
Does anyone know how I can instantiate multiple copies of a JNI library?
Thanks!
You can't do that. The dynamic linker will only load a given .so file into a process once.
Ideally you would modify the library to give it a light object-oriented style, allowing you to create instances and initialize those (rather than process-level static state) from your configuration files or calls. This isn't necessarily as complicated as it seems - basically put all your state in a struct and pass the pointer to it through all your calls. You'll have one marathon editor session resulting in a tired "paste" finger, and then some mistake cleanup. Fortunately once you remove the static variables you'll get compile errors on all remaining attempts to use them.
A very hacky alternative might be to declare some remote-process services in your AndroidManifest.xml and load the library into each of those. Or, really breaking the android model (and at theoretical risk of random killing), load the library into multiple created-on-demand native executables.
Related
I'm kinda new to Android development so my question might be weird or not even possible. I wouldn't know!
Anyway, I'm building multiple apps that will have a lot of shared elements, so I decided to build a library with those components and use it in all of the apps, rather than stupid copying and pasting code.
For example, the library handles the welcome screen and login/signup flow activities, among other things. So here are the problems this approach might cause:
While the behavior is the same across the apps, but the logo that I show at the welcome screen is different. Right now I populate it with an image resource from the library resources (R class) which will be the same for all apps and is obviously not correct.
The login/signup process is based on Firebase, which will require the app to have a key to be able to use them. Right now I also populate it with a dummy string resource from the library resources.
So my question really boils down to 3 parts:
Is there anyway I could pass this info from the app to the library? can I somehow modify the R class of the library? Or can I use the app's R class from the library? I can also call this part of the library as a function passing the parameters I need. But the first solution looks maybe more clean to me?
Whatever the answer to Q1 is. Where would I do this and how? The library has the welcome activity itself which is supposed to be the first activity in the app. How and where do I do this once the app starts and before the first activity starts?
If what I'm doing is wrong or impossible, is there any other way to achieve it?
Is there anyway I could pass this info from the app to the library?
can I somehow modify the R class of the library? Or can I use the
app's R class from the library? I can also call this part of the
library as a function passing the parameters I need. But the first
solution looks maybe more clean to me?
You don't need to modify the R class because you can override the resource file by creating a file with the same name. But it's not a clean solution because you constantly need to ensure your project and library resources name are the same.
Whatever the answer to Q1 is. Where would I do this and how? The
library has the welcome activity itself which is supposed to be the
first activity in the app. How and where do I do this once the app
starts and before the first activity starts?
Instead of overriding the resources name, you're better to modify your library to receive a configuration as a contract to use the library. Here the sample:
First, create the class for holding the configuration:
public class Configuration {
private int welcomeImageDrawableId;
private int logoDrawableId;
// constructor
public Configuration(int welcomeImageDrawableId, int logoDrawableId) {
this.welcomeImageDrawableId = welcomeImageDrawableId;
this.logoDrawableId = logoDrawableId;
}
// setter and getter.
public int getLogoDrawableId() {
return logoDrawableId;
}
}
Second, use the configuration class for the library by creating a Singleton class which will be used internally by the library:
public class MyLibrary {
private static MyLibrary myLibrary;
private Configuration configuration;
private MyLibrary(){}
private MyLibrary(Configuration configuration) {
this.configuration = configuration;
}
public static MyLibrary getInstance() {
if(myLibrary == null) {
throw new RuntimeException("Need call createInstanceWith method first!!");
}
return myLibrary;
}
public static MyLibrary createInstanceWith(Configuration configuration) {
if(myLibrary == null) {
synchronized(MyLibrary.class) {
if (myLibrary == null) {
myLibrary = new MyLibrary(configuration);
}
}
}
return test;
}
public Configuration getConfiguration() {
return configuration;
}
}
Third, use the configuration class in your library via the singleton class. something like this:
// assume imvLogo is an existing ImageView
Configuration configuration = MyLibrary.getInstance().getConfiguration();
imvLogo.setImageResource(configuration.getLogoDrawableId());
Last, register the contract when the library is used with:
Configuration configuration = new Configuration(R.drawable.welcome, R.drawable.logo);
MyLibrary.createInstanceWith(configuration);
Note: all the code isn't tested yet, error is to be expected.
Apart from the solution above, I also found another way to achieve this whole thing without having to initialize libraries and whatnot.
I think the correct way to do this is to use productFlavors in the library. This allows the library to share the one main set of source code, one main set of resources, then an extra set of resource per app/flavors. This is very sufficient for my purposes.
For more info about build variants and flavors:
https://developer.android.com/studio/build/build-variants
I'm developing an android app implementing MVP and clean architecture. I have the following scenario:
One core module with presenters and view interfaces,...
One domain module with repositories, data sources,..
App module with the core implementation (so the Fragment/Activities).
Currently the strings.xml file is in the app module, but I'm thinking whether it should be in a commons module or not. The problem is that, sometimes, the presenter must set the text to the view, so the presenter should need to access to the strings.xml. I've thought in two possible solutions:
1) Create a TextHelper interface on core module that will be implemented on the app module and injected to the presenter, so the presenter will use this helper to get the strings it requires. (This is the solution I have implemented).
2) Move the strings.xml file to a common module so the file can be accessed from core module. But this solution would have a problem: the presenter doesn't have a context.
What do you think? What is the best approach?
Thanks in advance
If your view has nested if/elses related to strings, then they should probably be unit-tested. Therefore, that logic should stay in presenters or use-cases, where can be tested more quickly.
Your question is about how to retrieve the actual strings, given that they reside in the "outer layers" of the Clean Architecture scheme, i.e. in the Context object. IMHO your TextHelper is the right approach, as it allows to inject a mock when writing unit tests: you're interested in how the strings are processed, rather than how the strings actually look. I'm trying a very similar approach and calling it StringsRepository.
A point of uncertainty is how the the repository API should look like:
A single method like getString(#StringRes int stringResId, Object... formatArgs) that simply wraps Context.getString(): very simple to implement, but will make the presenters depend on your R.string class, which in turns requires strings.xml to be in the same module as your code under test;
One method per string with optional arguments, each one containing the reference to the appropriate string ID. This solution allows for best abstraction, but may become big (both the interface and the implementation...) and many domain classes may depend upon it. Handle with care.
Like (2), but with several classes, one per each part of your app. Each class may have a base class similar to (1) but with that method with protected visibility.
The best options for your case would be (2) or (3), but your mileage may vary.
You can use Application class to get the context any where from the app.
public class MVPApplication extends Application {
private static Context context;
public static Context getContext() {
return context;
}
#Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
}
#SuppressWarnings("unsued")
#Override
#SuppressLint({ "InflateParams", "SimpleDateFormat" })
I don't get why we need to declare annotations.
We want to facilitate the writing and the maintenance of Android applications.
We believe that simple code with clear intents is the best way to achieve those goals.
Robert C. Martin wrote:
The ratio of time spent reading [code] versus writing is well over 10 to 1 [therefore] making it easy to read makes it easier to write.
While we all enjoy developing Android applications, we often wonder: Why do we always need to write the same code over and over? Why are our apps harder and harder to maintain? Context and Activity god objects, complexity of juggling with threads, hard to discover API, loads of anonymous listener classes, tons of unneeded casts... can't we improve that?
How?
Using Java annotations, developers can show their intent and let AndroidAnnotations generate the plumbing code at compile time.
Features
Dependency injection: inject views, extras, system services, resources, ...
Simplified threading model: annotate your methods so that they execute on the UI thread or on a background thread.
Event binding: annotate methods to handle events on views, no more ugly anonymous listener classes!
REST client: create a client interface, AndroidAnnotations generates the implementation.
No magic: As AndroidAnnotations generate subclasses at compile time, you can check the code to see how it works.
AndroidAnnotations provide those good things and even more for less than 50kb, without any runtime perf impact!
Is your Android code easy to write, read, and maintain?
Look at that:
#EActivity(R.layout.translate) // Sets content view to R.layout.translate
public class TranslateActivity extends Activity {
#ViewById // Injects R.id.textInput
EditText textInput;
#ViewById(R.id.myTextView) // Injects R.id.myTextView
TextView result;
#AnimationRes // Injects android.R.anim.fade_in
Animation fadeIn;
#Click // When R.id.doTranslate button is clicked
void doTranslate() {
translateInBackground(textInput.getText().toString());
}
#Background // Executed in a background thread
void translateInBackground(String textToTranslate) {
String translatedText = callGoogleTranslate(textToTranslate);
showResult(translatedText);
}
#UiThread // Executed in the ui thread
void showResult(String translatedText) {
result.setText(translatedText);
result.startAnimation(fadeIn);
}
// [...]
}
Java annotations bind specific conditions to be satisfied with code. Consider a scenario where we think we are overriding a method from anther class and we implemented code that (we think) is overriding the method. But if we somehow missed to exactly override one (e.g. we misspelled name. In superclass it was "mMethodOverridden" and we typed "mMethodoverridden"). The method will still compile and execute but it will not be doing what it should do.
So #Override is our way of telling Java to let us know if we are doing right thing. If we annotate a method with #override and it is not overriding anything, compiler will give us an error.
Other annotations work in a very similar way.
For more information, read docs Lesson: annotations
Annotations are basically syntactic metadata that can be added to Java source code.Classes, methods, variables, parameters and packages may be annotated .
Metadata is data about data
Why Were Annotations Introduced?
Prior to annotation (and even after) XML were extensively used for metadata and somehow a particular set of Application Developers and Architects thought XML maintenance was getting troublesome. They wanted something which could be coupled closely with code instead of XML which is very loosely coupled (in some cases almost separate) from code. If you google “XML vs. annotations”, you will find a lot of interesting debates. Interesting point is XML configurations were introduced to separate configuration from code. Last two statements might create a doubt in your mind that these two are creating a cycle, but both have their pros and cons.
For eg:
#Override
It instructs the compiler to check parent classes for matching methods.
I was studying the android source code and I found that there are many places in framework that use native code without using static{System.loadLibrary()}.
For example, in SystemServer.java, native method "init1(args)" is called but there is no static{System.loadLibrary()} in the file. How native code is loaded without static{System.loadLibrary()}? thanks.
The native library has to be loaded only once for the whole application, so it has probably already been loaded by another class which has been instantiated before. Note that this is not a best practice as it makes assumptions on the order by which the classes are called!
A commonly used technic to avoid this is to create a Loader class like this:
class Loader {
private static boolean done = false;
protected static synchronized void load() {
if (done)
return;
System.loadLibrary("library_name");
done = true;
}
}
This way, if you call static{Loader.load();} on every class that requires the use of native functions, you ensure that the library has been loaded (and only once).
I have the follow scenario to work on. I was given a shared library (libeffect.so) to use in a Android project i am working for a client. I dont have the shared library source code, i have just the .so file with me. The library is pre-compiled to work on android devices. Along with the shared library I have the method signature
public static native void doEffect(int param1, IntBuffer intBuffer);
So now I have some questiosn on how to make the call to this native method, of source, if this is possible having just the .so file, so there they are:
Do I need to place the native method signature in the same package/class as those defined when the .so was or I can use this signature in any package/class in my project that during runtime the jvm will be able to find the method in the shared library? For example, if this shared library was firstly used in a class mypackage.MyClass, do I need to create the same package, class and then put the method signature there?
Where do I need to place this .so file inside my eclipse android project to get this file deployed inside my apk file?
These question might sound noob, but I have never worked with jndi before so I am a bit concerned if calling the method doEffect without any error can be achieve. Any answer that can guide me is very welcome.
Many Thanks
Thiago
Do I need to place the native method signature in the same package/class as
those defined when the .so was or I
can use this signature in any
package/class in my project that
during runtime the jvm will be able to
find the method in the shared library?
For example, if this shared library
was firstly used in a class
mypackage.MyClass, do I need to create
the same package, class and then put
the method signature there?
No need to create same package/class. You can put the method signature in any package.
public class NativeLib {
static {
System.loadLibrary("so_file");
}
public static native void doEffect(int param1, IntBuffer intBuffer);
}
2.Where do I need to place this .so file inside my eclipse android project
to get this file deployed inside my apk file?
You have put this .so file in lib folder of your application . IF lib folder is not there then you can create a lib folder and put the .so file. you can call it by using System.loadLibrary("so_ file");
1 Do I need to place the native method signature in the same
package/class as those defined when the .so was or I can use this
signature in any package/class in my project that during runtime the
jvm will be able to find the method in the shared library?
According to http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html you have to use a matching package and class name.
I've only observed JNI methods where the C side functions are called things like Java_com_company_whatever_SomeClass_someMethod, which means that you have to put the 'native' declarations in a similarly-named Java class.
Use the tool 'nm' or 'nm++' (they're in the precompiled folders in the NDK) to look at the .so file and see what the functions defined in it are called. If you see any starting Java_, those're what you want.
I'm sceptical of the preceding claim that you can call functions which aren't named in the Java_PACKAGE_CLASS_METHOD format; it may be a legacy behaviour if it actually works, but even if you can, it seems dangerous - you might get the wrong one.
2 Where do I need to place this .so file inside my eclipse android
project to get this file deployed inside my apk file?
Your .so lives in libs/armeabi, libs/armeabi-v7a, libs/x86, and/or libs/mips depending on how many platforms you're working with, where 'libs' is a peer of 'src' and 'res'. I don't know whether Android looks in libs/ without the platform qualifier, but there's no evident benefit in that. The situation is slightly complicated by most/all Intel devices including fancy technology allowing them to execute most ARM libraries on x86 hardware.
Further, I like to declare an interface of a JNI class and provide a factory (it's a method here for brevity, but I prefer a factory class) that supplies a no-op implementation of the interface if things go wrong: it facilitates unit testing and also avoids having to mess about testing for null values before calling its methods (assuming you're comfortable that your shipped library will never have missing or changed method signatures - your integration tests should check that):
public interface YourLibI {
#Override
public native yourMethod();
public static final NO_OP = new YourLibI() {
#Override
public void yourMethod(){}
}
}
public class YourLib extends YourLibI {
public newYourLibI() {
try {
return new YourLib();
}
catch (UnsatisfiedLinkError e) {
Log.e("YourLibJNI", "Load failed, returning NO-OP dummy", e);
return YourLibI.NO_OP;
}
}
static {
System.loadLibrary("arbitronSDK");
}
private YourLib() {
}
#Override
public native void yourMethod();
}
I don't normally call interfaces 'xxxI' but I'm assuming your library's JNI class isn't called something nice like UtilityJNI (whereupon I'd call the interface 'Utility').