16

I'm following this article https://proandroiddev.com/detecting-when-an-android-app-backgrounds-in-2018-4b5a94977d5c to implement android lifecycle but on a legacy app that has the Application class on java.

How can I implement this kotlin code in java?

private val lifecycleListener: SampleLifecycleListener by lazy {
    SampleLifecycleListener()
}

I feel that is a dumb question, but I'm not familiar with lazy initialization and I'm not sure how to search this question, any "lazy theory link" will be welcome also.

mkobit
  • 43,979
  • 12
  • 156
  • 150
rubdottocom
  • 8,110
  • 10
  • 39
  • 59
  • 3
    [Lazy Initialization in Kotlin](http://www.baeldung.com/kotlin-lazy-initialization) compares Java and Kotlin. *(A simple web search for [`kotlin lazy`](https://www.google.com/search?q=kotlin+lazy) found that easily enough, so "not sure how to search" sounds like "too lazy to bother searching myself", no pun intended)* – Andreas Apr 19 '18 at 16:24
  • take a look at this question: [Lazy field initialization with lambdas](https://stackoverflow.com/q/29132884/1429387) (java 8) – naXa stands with Ukraine Apr 19 '18 at 16:47
  • Lazy loading is not built into Java. You must either implement it yourself (as in the answers below) or use a library that does it for you (for example, Spring). It seems likely that there is an Android lazy initialization library since it is a fairly straight forward proxy technique. – DwB Apr 19 '18 at 16:48
  • 1
    @Andreas your link is gold, thank you, I really did my searches, but the main results are about lateinit vs lazy, etc. Probably I didn't enter on your suggestion because I thought it was another explanation for how and when to use lazy initialization so probably I ignored it. Maybe you're true about how sounds "not sure how to search", I try to avoid answers about "search before ask!" without useful content. Not your case, now I learned a bit more about laziness :) – rubdottocom Apr 20 '18 at 06:45

3 Answers3

12
private SampleLifecycleListener sll;

public synchronized SampleLifecycleListener getSampleLifecycleListener() {
    if (sll == null) {
        sll = new SampleLifecycleListener();
    }
    return sll;
}

That way it isn't initialized until the getter is called.

Bakon Jarser
  • 703
  • 6
  • 20
  • 1
    how about `synchronize` in get function? – Kingfisher Phuoc Apr 19 '18 at 16:23
  • 1
    @KingfisherPhuoc For multi-threaded support, `synchronized` may be too costly, so holder pattern is better. See example in [Lazy Initialization in Kotlin](http://www.baeldung.com/kotlin-lazy-initialization), which shows Java example too. – Andreas Apr 19 '18 at 16:26
  • 1
    @KingfisherPhuoc Is there a need for that? This method will be called only in onCreate() and since it runs only on UI thread, it doesn't need any synchronization. – jelic98 Apr 19 '18 at 16:27
  • Thanks, forgot to add the synchronize. – Bakon Jarser Apr 19 '18 at 16:27
  • 1
    One benefit Kotlin has over Java is that it allows you to lazily compute while still allowing nullability. – user221256 Apr 19 '18 at 20:09
9

You can call Kotlin lazy from Java if you want to:

import kotlin.Lazy;

Lazy<SampleLifecycleListener> lazyListener = kotlin.LazyKt.lazy(() -> new SampleLifecycleListener()));
SampleLifecycleListener realListener = lazyListener.getValue();
David Rawson
  • 20,912
  • 7
  • 88
  • 124
1

Beginning with Java 8, you can use ConcurrentHashMap#computeIfAbsent() to achieve laziness. ConcurrentHashMap is thread-safe.

class Lazy {
    private final ConcurrentHashMap<String, SampleLifecycleListener> instance = new ConcurrentHashMap<>(1);

    public SampleLifecycleListener getSampleLifecycleListener() {
        return instance.computeIfAbsent("KEY", k -> new SampleLifecycleListener()); // use whatever constant key
    }
}

You can use this like

SampleLifecycleListener sll = lazy.getSampleLifecycleListener();
naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
  • 2
    Couldn't you just use a lock with the other solution? I feel like a map adds a bit of an overhead. – Salem Apr 19 '18 at 16:35
  • @Salem `ConcurrentHashMap` provides a high-performance, scalable, and thread-safe implementation of the `Map` interface. It uses fine-grained locking, called lock striping, to minimize contention and improve performance compared to using a synchronized code. The "Java Concurrency in Practice" book discusses `ConcurrentHashMap` as a preferred alternative to using `Collections.synchronizedMap()` or manually synchronizing `HashMap` operations (`synchronized` or locks). – naXa stands with Ukraine Apr 03 '23 at 14:24