Qt/QML Android best practice to send a custom Intent (share URL) - android

I was wondering if there are any best practice tips for sending custom android intents from QML (or c++ for that matter).
should I create a custom android activity and use the QAndroidJniObject class to call it or are there any better ways?
My intention is to create a simple share URL function from QML to other android apps.
thanks

Extend QtActivity with additional static method:
package org.whatever
public class YourActivity extends org.qtproject.qt5.android.bindings.QtActivity
{
private static YourActivity instance;
YourActivity() {
instance = this;
}
public static void shareUrl(QString url) {
//create intent here
//can use instance object
}
}
On c++ side call shareUrl method using QAndroidJniObject
class QmlInterface : public QObject
{
Q_OBJECT
public:
QmlInterface();
Q_INVOKABLE void shareUrl( QString url );
};
and implementation:
void QmlInterface:: shareUrl( QString url )
{
#ifdef Q_OS_ANDROID
QAndroidJniObject::callStaticMethod( "org/whatever/YourActivity",
"shareUrl",
"(Ljava/lang/String;)V",
QAndroidJniObject::fromString( url ));
#endif
}
Using static method on java side simplifies jni call significantly because you don't have to get Activity instance. Because Activity context is needed to send Intent static instance member object is used on java side.

Related

How to getContext() in LIBGDX android app

I need to get the Context of my app but in my main Class extends from Game so I can not extends from Activity. Does anybody know how to do it?
Thank you!
LibGDX is a cross-platform game engine, so your application can be executed on multiple platforms. Only Android, which is just one supported platform, can provide a Context object.
To get around this issue, you'll need to create an Interface in the core module of your LibGDX project. That Interface can, for example, contain a getContext() method. Add the interface as an argument in the constructor of your main LibGDX class. In every platform-specific module, you should then implement this Interface , override the getContext() method (by returning a Context object in the android module and null in every other module) and pass it with the constructor for the main LibGDX class in the Launcher class for that module.
For more information about the topic, read the LibGDX Wiki: https://github.com/libgdx/libgdx/wiki/Interfacing-with-platform-specific-code
EDIT:
LibGDX isn't able to handle the Context object, you'll need to manipulate the Context object in the Android module, instead of passing it to the core module! Thanks to #Nicolas and #Luis Fernando Frontanilla for mentioning this.
Interfacing is the way to go since you can't access Android specific code from Core module.
Step 1: Create the interface (CORE MODULE)
public interface MyInterface {
void manipulateContext();
void manipulateContextWithExtraParams(String example, int example2);
}
Step 2: Implement the interface (ANDROID MODULE)
import android.content.Context;
public class InterfaceImplementation implements MyInterface {
private Context context;
public InterfaceImplementation(Context context) {
// Store the context for later use
this.context = context;
}
#Override
public void manipulateContext() {
// Do something with the context, this is called on the core module
System.out.println(context);
}
#Override
public void manipulateContextWithExtraParams(String example, int example2) {
if (example2 == 1) {
System.out.println(example + context);
} else {
System.out.println(example);
}
}
}
Step 3: Send the implemented interface your game (ANDROID MODULE)
import android.os.Bundle;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.frontanilla.helping.getcontext.InterfaceImplementation;
import com.frontanilla.helping.getcontext.MyGame;
public class AndroidLauncher extends AndroidApplication {
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
InterfaceImplementation interfaceImplementation = new InterfaceImplementation(this);
// Here we send the implementation to our Game in Core module
initialize(new MyGame(interfaceImplementation), config);
}
}
Step 4: Store and use the methods you defined on your interface (CORE MODULE)
import com.badlogic.gdx.Game;
public class MyGame extends Game {
private MyInterface myInterface;
public MyGame(MyInterface myInterface) {
// Store for later use
this.myInterface = myInterface;
}
#Override
public void create() {
// Example of manipulating the Android Context indirectly from Core module
myInterface.manipulateContext();
myInterface.manipulateContextWithExtraParams("Hello", 2);
}
}
As you can see, you will not be manipulating the Context from the core module directly, instead, place that logic on the InterfaceImplementation class
What I have tried is:
scoreHelper = new ScoreSQLiteHelper(context,"dbtest",null,1);
db = scoreHelper.getWritableDatabase();
but I don't have any context to feed that method.
It would be usefull any other way to get a path to create the db with:
db = SQLiteDatabase.openOrCreateDatabase(path,null);

Android NDK making library available all through the app

I am diving into the ndk stuff and I've managed to make a simple library and call it from my activity.
In order to test it, in my Activity I have used:
static {
System.loadLibrary("my-lib");
}
public native static String callNativeFunction(Context context);
This means that calling MyActivity.callNativeFunction(context) does return the String value from my Cpp function.
I have 2 questions:
The loadLibrary is made in my main activity, however I want to be able for instance, to call the callNativeFunction function from an IntentService when the activity may be closed or from other places of my app. How can I properly load the library and have it available from all places of the app?
Since this is a simple function that I'll use in my project, is there anything else specific to do on release? From https://developer.android.com/studio/projects/add-native-code.html it seems that Gradle builds for all supported abis and adds them into the apk.
You need to load the library once. This can also be done in your Application class. Once the library is loaded, you can call the defined native methods from the appropriate classes defined in your cpp class
Application class :
public class SRApplication extends Application {
static {
System.loadLibrary("my-lib");
}
#Override
public void onCreate() {
super.onCreate();
}
}
CPP :
extern "C"
jstring
Java_com_example_service_ExampleService_getNativeString (
JNIEnv* env,
jobject /* this */) {
return env->NewStringUTF("yo");
}
Your Service :
package com.example.service.ExampleService;
public class ExampleService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
String nativeString = getNativeString();
return null;
}
public native String getNativeString();
}
If you don't have specific code for different cpu variants, you don't need to explicitly handle anything, the default
externalNativeBuild {
cmake {
cppFlags ""
}
}
is sufficient.

Error: allocating an object of abstract class type 'JIntent'

How fix this error?
Code:
Intent *JIntent; //main.h
//menu.cpp
Intent = new JIntent(this); //Error
and Create Class:
class TestClass
{
public:
JIntent *MyIntent;
JService *MyService;
virtual int FuncClass() = 0;
};
int TestClass::FuncClass() {
MyIntent = new JIntent(this);
MyService = new JService(this);
}
Does not work. I don't understand this.
JIntent and JService are abstract interfaces, you cannot instantiate them directly. For JIntent, you must instantiate the TJIntent class instead, and assign it to a _di_JIntent variable (which wraps the interface to handle reference counting for you);
#include <Androidapi.JNI.App.hpp>
#include <Androidapi.JNI.GraphicsContentViewText.hpp>
class TestClass
{
public:
_di_JIntent MyIntent;
_di_JService MyService;
virtual int FuncClass() = 0;
};
int TestClass::FuncClass() {
MyIntent = new TJIntent;
MyService = ...;
}
That being said, JService represents Android's Service class. There is an accompanied TJService class, but it is meant to be derived from, not instantiated. Delphi/C++Builder do not natively support implementing Android services yet, though it is technically possible with some extra work (involving a Java stub):
Delphi and Android services
Delphi and Android services (part 2)
How this fix? This error..
JIntent - class
#include<Androidapi.JNI.App.hpp> //JService
#include<Androidapi.JNI.GraphicsContentViewText.hpp> //JIntent
It's FireMonkey

The base class member function access child class member function directly?

Is it possible that the base class member function can access child class member function directly?
I found the code from Androind, the BufferQueue inherits BnSurfaceTexture, and has one member function "requestBuffer".
In the base class BnSurfaceTexture, I found it just call requestBuffer directly.
How does the base class BnSurfaceTexture know the function "requestBuffer"?
Thanks
The base class member function:
status_t BnSurfaceTexture::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case REQUEST_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int bufferIdx = data.readInt32();
sp<GraphicBuffer> buffer;
/* it call requestBuffer directly */ <--------
int result = requestBuffer(bufferIdx, &buffer);
reply->writeInt32(buffer != 0);
The child class declaration & implementation:
class BufferQueue : public BnSurfaceTexture {
private:
virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ATRACE_CALL();
ST_LOGV("requestBuffer: slot=%d", slot);
Mutex::Autolock lock(mMutex);
...
return NO_ERROR;
}
How does the base class BnSurfaceTexture know the function "requestBuffer"?
This function must have been at least declared (it could have been defined with some default implementation) in the base class and it must be virtual.
So, at compile time, the compiler sees that such function exists.
The function call is resolved run-time. This is polymorphism.
Tiny example:
class Base
{
public:
virtual void f() { /* Base */ } // could be pure virtual
virtual void g() { f(); };
};
class Derived: public Base
{
public:
virtual void f() { /* derived */ }
};
When you have
Base* pB = new Derived;
pB->g();
g() will call Derived::f;
Just make sure the base class function is declared, and the derived class is define before definition of base class function definition. Here is an example
#include <iostream>
class Base
{
public :
void call_derived ();
};
class Derived : public Base
{
public :
void derived_fun ()
{
std::cout << "Derived class member function called!" << std::endl;
}
};
void Base::call_derived ()
{
static_cast<Derived *>(this)->derived_fun();
}
int main ()
{
Derived dobj;
dobj.call_derived();
return 0;
}
However, this use of static_cast is unsafe, compiler won't complain if you try call_derived on an incomplete object. However, you can add an assertion assert(dynamic_cast<Derived *>(this), at least in debug mode, for debugging purpose. Alternatively, you can declare Base class' constructor, destructor protected, to prevent creation of incomplete object, or attempting to destroy a derived object while the base is not polymorphic
However, the above code are not really common in real world. Other more advanced techniques exists, like CRTP, which also use static_cast and provide static polymorphism without virtual functions.
This answer may not be exactly what you want. It only shows that it is possible to call derived class members in base class even it is not defined in base at all. But to call it directly without any cast, you still need virtual functions.

android - how to create a reusable function?

In my android project, I have many activities and some of them already extend other stuff like map activity or BroadcastReceiver.
How do I create a function that I can call from any activity, because I don't want to have to repeat any code in multiple activities.
thanks.
If I have useful functions that perform little helpful tasks that I want to invoke from several Activities, I create a class called Util and park them in there. I make them static so that I don't need to allocate any objects.
Here is an example of part of one such class I wrote:
public final class Util {
public final static int KIBI = 1024;
public final static int BYTE = 1;
public final static int KIBIBYTE = KIBI * BYTE;
/**
* Private constructor to prevent instantiation
*/
private Util() {}
public static String getTimeStampNow() {
Time time = new Time();
time.setToNow();
return time.format3339(false);
}
}
To use these constants and methods, I can access them from the class name, rather than any object:
int fileSize = 10 * Util.KIBIBYTE;
String timestamp = Util.getTimeStampNow();
There's more to the class than this, but you get the idea.
You can extend the Application class, then in your activities call the getApplication method and cast it to your application class in order to call the method.
You do this by creating a class that extends android.app.Application:
package your.package.name.here;
import android.app.Application;
public class MyApplication extends Application {
public void doSomething(){
//Do something here
}
}
In your manifest you must then find the tag and add the android:name="MyApplication" attribute.
In your activity class you can then call the function by doing:
((MyApplication)getApplication()).doSomething();
There are other ways of doing something similar, but this is one of the ways. The documentation even states that a static singleton is a better choice in most cases. The Application documentation is available at: http://developer.android.com/reference/android/app/Application.html
You could create a static method or an object that contains this method.
You can create a class extending Activity, and then make sure your real activities are subclasses of that activity, instead of the usual built-in one. Simply define your common code in this parent activity.
Shachar
Create a new Java class BaseActivity with abstract Modifiers and extends it with AppCompatActivity.
Move all your methods under Java class BaseActivity.
package com.example.madbox;
public abstract class BaseActivity extends AppCompatActivity {
protected void YourClass() {
}
}
Extends your Activities with BaseActivity but not AppCompatActivity.

Categories

Resources