How to pass callback function from Java to Kotlin class - java

I have a Kotlin class as follows (this is a sample for ease, hence it doesn't 'do' anything useful)
class MyKotlinClass (private val handleSomeCallBack: (ByteArray) -> Unit) {
private val someBuffer = BytesBuilder()
fun myFunction(bytesList: List<Byte>) {
handleSomeCallBack(someBuffer.toArray())
}
}
I want to call this code from a java class, hence, in that class I have the following declared:
public MyJavaClass() {
messageParser = new MyClass(handleSomeCallback);
}
The callback method being passed is:
private void handleSomeCallback(byte[] dataBytes) {
}
(MyClass is correctly declared within the file)
The issue I'm having is that I can't figure out how to pass the callback to the constructor of MyKotlinClass.
I have tried a variety of things including
messageParser = new MyClass(handleSomeCallback(byte[] dataBytes));
messageParser = new MyClass(this::handleSomeCallback(byte[] dataBytes));
But no matter what I try I receive an error.
I believe the answer is to do with lambdas but I can't quite see what the syntax should be for calling this from Java.

You can go with something like this:
MyKotlinClass instance = new MyKotlinClass(byteArray -> {
// your code
return Unit.INSTANCE;
});
Or use Unit as return type of your separate method like suggested by #ADM here
You just need to add
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
to your android block in app build.gradle

Related

Kotlin android expose a class of one module in another?

the setup:
Module 1 an external dependency that has Class A
Module 2 depends on Class A but may in the future depends on another module/class entirely
an APP depends on Module 2
I tried to add a typealias in Module 2 to Class A. it exposes the class "correctly" (lets say it is com.moduleTwo.ClassA instead of com.moduleOne.ClassA) but it makes it so that APP also needs to have a dependency on Module 1 or it doesn't compile with:
Cannot access class 'com.moduleOne.ClassA'. Check your module classpath for missing or conflicting dependencies
How can one make Module 2 expose an alias to Class A without adding Module 1 to APP build.gradle? Is there a way to "inject" the dependency to APP?
If I understood correctly you would like to replace a module without having app's code depending on external libraries.
When your app's code depends on only the abstraction and not concrete implementation you can replace those dependencies at any time.
The piece of code below shows that User in app module depends on interface A but the real implementation of A may vary.
// library module A
interface A {
fun doWork()
}
// library module B implements modules A & External
class B(private val external : External) : A {
override fun doWork() {
val result = external.getExternalStuff()
// more work with result
}
}
object Factory {
fun createB(params...): B {
val external = External(paramX)
// ...
return B(external)
}
}
// library module C implements module A
class C : A {
override fun doWork() {
println("C works")
}
}
// app
// User knows only 'A'
class User(private val a: A) {
fun help() {
a.doWork()
}
}
// Version 1: App implements modules A & B
// app module will know nothing about External
// but some factory or builder class to create B
fun appStarts() {
val a = Factory.createB(params...)
val user = User(a)
user.help()
}
// Version 2: App implements modules A & C
fun appStarts() {
val a = C()
val user = User(a)
user.help()
}
Hope this helps.

Is there a Simple Way to Take Screenshot in Espresso Android Studio for Every Test Case

Guys, I'm a beginner in Espresso and requesting for your valuable help, Can anyone share me the code with which I can take the screenshot for every tests which I executing ?
I'll try to guide based on the info you provided.
First you need to to know the name of your test case.
Second i will assume that you already have granted write/read external storage
Third i'll assume you also have UI Automator dependency added.
So the implementation would be something like this:
object ScreenshotUtil : TestWatcher() {
lateinit var description: Description
override fun starting(description: Description) {
super.starting(description)
this.description = description
}
fun captureScreenshot() {
val capture = Screenshot.capture()
capture.format = Bitmap.CompressFormat.PNG
capture.name = description.methodName
val processors = HashSet<ScreenCaptureProcessor>()
processors.add(BasicScreenCaptureProcessor())
try {
capture.process(processors)
} catch (e: IOException) {
throw IllegalStateException(e)
}
}
}
Then you could use it like this:
ScreenshotUtil.captureScreenshot()

AbstractMethodError when use java 8 default interface methods and implementation in different libs

I have an java interface with default method (ITest) and java implementation (Test) defined in 2 different libraries (aar). In app module I create instance of the Test and call Test.test(). AbstractMethodError occurs at this moment.
This happens only I use Java in the libraries (for Kotlin all ok) and build apk by Build - Generate Signed APK.
If application run with Run menu all work as expected.
lib1 (with interface):
public interface ITest {
default void test() {
}
}
lib2 (with implementation):
public class Test implements ITest {
}
app:
private fun runTest() {
try {
Test().test()
Log.d(TAG, "call success")
} catch (e: AbstractMethodError) {
Log.d(TAG, "call fail e = $e")
}
}
libraries and application build.config support Java8:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
Here is very simple demo project
How I must use Java default methods in my case?

Kotlin: Overload resolution ambiguity

Trying to execute the below code :
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Test().list.contains(1)
}
}
public class Test {
ArrayList<Integer> list;
public ArrayList<Integer> getList() {
return list;
}
}
and compilation fails at Test().list.contains(1) with message :
Task :app:compileDebugKotlin FAILED
e: /Users/sreejithcr/Documents/MyApplication/app/src/main/java/com/wxample/myapplication/MainActivity.kt: (13, 31): Overload resolution ambiguity:
public open fun contains(#Nullable element: Int!): Boolean defined in java.util.ArrayList
public open fun contains(#Nullable element: Int!): Boolean defined in java.util.ArrayList
What i understand is compiler finds 2 contains() with exact same signature and not sure which one to call.
gradle config :
ext.kotlin_version = '1.3.41'
classpath 'com.android.tools.build:gradle:3.4.2'
It is an issue with Android Studios API 29 R2
https://issuetracker.google.com/issues/139041608#comment3
Go Tools -> SDK Manager -> Uninstall Android 9.+, then install it again as Google rolled back R2 so you'll be back to R1
As I read through your code I noticed some conflicts:
First, Test needs a public constructor, which creates the ArrayList, sth. like:
public Test(){
list = new ArrayList<>();
}
Second, make the variable list private, access should only be granted through getter/setter.
Third, in method onCreate() try:
new Test().getList().contains(1);

Dagger 2 Good practices to build components in Application class

I know probably there is no clear answer for this question.
But I would like to know Your opinions and maybe new ideas.
I'm wondering which of the following options is the best/right/correct way to build the app-level Dagger Component in Application class.
Example 1:
public class MyApp extends Application {
private NetComponent mNetComponent;
#Override
public void onCreate() {
super.onCreate();
mNetComponent = DaggerNetComponent.builder()
.appModule(new AppModule(this))
.netModule(new NetModule("https://api.github.com"))
.build();
}
public NetComponent getNetComponent() {
return mNetComponent;
}
}
Usage:
((MyApp) getApplication()).getNetComponent().inject(this);
Example 2:
class MyApplication extends Application {
private static MyComponent component;
#Override
void onCreate() {
component = DaggerMyComponent.builder()
.contextModule(new ContextModule(getApplicationContext()))
.build();
}
public static MyComponent getMyComponent() {
return component;
}
}
Usage:
MyApplication.getMyComponent().inject(this)
Example 3:
class CustomApplication: Application() {
lateinit var component: SingletonComponent
private set
override fun onCreate() {
super.onCreate()
INSTANCE = this
component = DaggerSingletonComponent.builder()
.contextModule(ContextModule(this))
.build()
}
companion object {
private var INSTANCE: CustomApplication? = null
#JvmStatic
fun get(): CustomApplication = INSTANCE!!
}
}
Then:
class Injector private constructor() {
companion object {
#JvmStatic
fun get() : SingletonComponent = CustomApplication.get().component
}
}
Usage:
Injector.get().catRepository()
Example 4:
class App : Application() {
var repositoryComponent: RepositoryComponent? = null
var appComponent: AppComponent? = null
override fun onCreate() {
super.onCreate()
instance = this
appComponent = DaggerAppComponent.builder().application(this).build()
repositoryComponent = DaggerRepositoryComponent.builder().build()
}
companion object {
private var instance: App? = null
fun get(): App {
return instance!!
}
}
}
Usage:
App.get().repositoryComponent!!.inject(this)
What do you think about this? Is there any better / cleaner way to do this? Maybe provided examples are fine? Or maybe just one of them?
I will be grateful for any good examples / tips / advices.
Thanks!
Okay, no one answered in 5 days so it's my turn, despite my bias :p
Option #1
((MyApp) getApplication()).getNetComponent().inject(this);
It's an "ok" version of doing things, except for two things.
First, the name. NetComponent isn't really for networking, it's the app-global singleton component, so it should be either called SingletonComponent or AppComponent. But naming it NetComponent is disingenuous, it's typically responsible for everything else too.
Second problem is that you need a reference to Context to access your dependency graph, making Context actually be a dependency rather than it being provided to you.
Option #2
MyApplication.getMyComponent().inject(this)
This is a perfectly fine way of doing things, but you need to know that to reach your object graph, you need to access the static method of MyApplication.
Option #3
Injector.get().inject(this)
Internally, this solution actually just calls over to get the app component, public static AppComponent get() { return MyApplication.getInstance().getComponent(); }
The benefit is that getComponent() is exposed via an instance method of Application, so it could be theoretically swapped out.
Also, invoking a method on something called Injector.get() is more obviously an "injector" than, well, an application class.
As for whether you use .catRepository() or .inject(this), it's up to you; but I personally prefer calling the provision methods to get the deps in Activity/Fragment, because listing the member-injection targets adds a lot of clutter to the component over time.
4.)
App.get().repositoryComponent!!.inject(this)
You can ditch the !! if repositoryComponent is a lateinit var.
Having two components for the same scope (and therefore two different object graphs) will only cause trouble, out of all of the options, this is the worst.
In my opinion, the 3rd option is the best. Technically it's the same as option #2 with an additional "indirection" through the instance method of Application that actually returns the component.

Categories