The count down timer class in Kotlin / Java is an abstract class hence we can't create an instance of it , but while viewing a tutorial of count down timer in Kotlin , this code went straight over my head
private var restTimer : CountDownTimer ? = null
restTimer = object:CountDownTimer(10000,1000){
override fun onTick(millisUntilFinished: Long) {
// some code
}
override fun onFinish() {
// some code
}.start()
Are we creating an object of this abstract class and why is "object" keyword mentioned here ?
I recommend you to look at Object expressions and declarations.
If you check the CountDownTimer class is :
public abstract class CountDownTimer {
....
/**
* #param millisInFuture The number of millis in the future from the call
* to {#link #start()} until the countdown is done and {#link #onFinish()}
* is called.
* #param countDownInterval The interval along the way to receive
* {#link #onTick(long)} callbacks.
*/
public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
}
So it is using this constructor to create an anonymous implementation. It is not creating an instance but object can access members, methods without create an instance.
This is what you do in Java
CountDownTimer countDownTimer = new CountDownTimer(long duration, long interval) {
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
}
};
countDownTimer.start();
So what you are doing is create an anonymous class and implement the necessary methods.
Object Expressions
Object expressions create objects of anonymous classes, that is, classes that aren't explicitly declared with the class declaration. Such classes are handy for one-time use. You can define them from scratch, inherit from existing classes, or implement interfaces. Instances of anonymous classes are also called anonymous objects because they are defined by an expression, not a name.
Object Declarations
Singleton can be useful in several cases, and Kotlin (after Scala) makes it easy to declare singletons.
This is called an object declaration, and it always has a name following the object keyword. Just like a variable declaration, an object declaration is not an expression, and cannot be used on the right-hand side of an assignment statement.
Object declaration's initialization is thread-safe and done at first access
Like yours:
restTimer = object:CountDownTimer(10000,1000){
override fun onTick(millisUntilFinished: Long) {
// some code
}
override fun onFinish() {
// some code
}.start()
source: https://kotlinlang.org/docs/object-declarations.html#object-declarations
Related
So I'm writing a piece of code to add a pause and resume functionality into the abstract class CountDownTimer (Android.os.CountDownTimer). I'm using the functionality only within this one activity and therefore am just using an object expression to create an anonymous class called sequencetimer. The code looks something like this:
public var sequencetimer = object : CountDownTimer(30000, 1000) {
public var timeremaining : Long = 0
override fun onTick(millisUntilFinished: Long) {
findViewById<TextView>(R.id.textView8).apply {
text = ("seconds remaining: " + millisUntilFinished / 1000)
}
}
override fun onFinish() {
findViewById<TextView>(R.id.textView8).apply {
text = "done"
}
}
public fun pauseTimer() {
timeremaining = findViewById<TextView>(R.id.textView8).text as Long
cancel()
}
public fun resumeTimer() {
onTick(timeremaining)
start()
}
}
Now I want to call the pauseTimer and resumeTimer functions that I added whenever my activity pauses or resumes like so:
override fun onPause() {
super.onPause()
sequencetimer.pauseTimer()
}
override fun onResume() {
super.onResume()
sequencetimer.resumeTimer()
}
The code however keeps throwing me an unresolved reference error for the functions pauseTimer() and resumeTimer(), even though the sequencetimer object is declared within the activity class and I can execute all the other functions such as sequencetimer.onTick() and sequencetimer.start() (however I can also not acces the public var timeremaining). Does anyone have any idea what the issue here is? Or is it simply not possible to expand/extend an abstract class within an anonymous object expression (I would have expected android studio to then throw some type of error)?
As you said yourself: you create anonymous class. That means this class doesn't exists from the developer point of view and the type of sequencetimer is just CountDownTimer which doesn't have pauseTimer() and resumeTimer() functions. You need to create a regular, named class, so it can be referenced in the code.
Alternatively, you can make sequencetimer a private var. In this case Kotlin assumes this is internal stuff and provides some kind of a shortcut. It conditionally permits this kind of operation, even if normally it should not be possible. This behavior is described in the docs: https://kotlinlang.org/docs/object-declarations.html#using-anonymous-objects-as-return-and-value-types
There are some issues with your code.
First issue I see is that public var sequencetimer. With kotlin keywords public, protected, internal you declare to compiler that sequencetimer would be accessible outside of your android activity class's scope. But object created as anonymous class in your activity class. Kotlin compiler decides that the only solution is marking sequencetimer as CountDownTimer.
// byte code
public final getSequencetimer()Landroid/os/CountDownTimer;
#Lorg/jetbrains/annotations/NotNull;()
Secondly, resumeTimer() will call onTick(12345L) once and restart the timer from the millisInFuture 30_000L.
It would be better you create a new count down timer for the remaining time.
And please, decrease the count down interval or you will see the seconds inconsistent 30, 28, 27, 26, 26, 24, ...
Hope, it helps.
private val timer = object : CountDownTimer(result, 1000) {
override fun onFinish() {
//delete the database entry
}
override fun onTick(millisUntilFinished: Long) {
//more code
}
}
As far as my knowledge in kotlin, object gets called before the result gets assigned a value
Initially, the result value is 0, then it gets updated in another function, but the timer gets called with result value as 0.
So what should be the best replacement for object here?
You can keep object, you just need to change order of initialization. One way would be to use by lazy, like this:
var result = 0L
private val timer: CountDownTimer by lazy {
object : CountDownTimer(result, 1000) {
override fun onFinish() {
// delete the database entry
}
override fun onTick(millisUntilFinished: Long) {
// more code
}
}
}
// 'init' block just as an example; the below code works anywhere
// such as in onCreate(), onStart() or wherever
init {
result = 1000
// 'timer' is initialized with result=1000 and then started
timer.start()
}
lazy is a so called property delegate, you can read more about it in the official docs for example.
I don't see how this is related to Kotlin?
You have a member val: timer
It is initialized when the object, the val resides in, is created.
So the problem is not what syntax you are using. It is the time you create timer. If you know when you are going to use it, and you are sure that by this time the result will be intialized, you can use lazy initialization.
I am attempting to write a method to wait for a type of activity to be present for my Espresso tests. I've seen examples of trying to wait for objects to appear on separate activities than where the test begins, but none have worked for me so far and I'm not keen to modify my production code with idling resources.
In my method, I'd like to get the current activity, and then check if the activity is the specific type of class that I'm wanting. I'm basically modifying some code I found here to work with Kotlin and a generic class type. Unfortunately, I don't know how to either format the argument that is being passed in (currently Class<out Activity>) or I'm improperly using it in my if statement. What is written below doesn't compile.
Any pointers on how to pass my desired activity type as a parameter to the waitForActivity method and how to check against it?
fun waitForActivity(activityType: Class<out Activity>, timeout: Int = 10): Boolean {
val endTime = System.currentTimeMillis() + (timeout * 1000)
do {
val currentActivity = getActivityInstance()
// THIS LINE IS MY ISSUE **********************************************
if(currentActivity != null && currentActivity::class.java is activityType)
return true
// ********************************************************************
SystemClock.sleep(100)
} while (System.currentTimeMillis() < endTime)
return false
}
private fun getActivityInstance(): Activity? {
val activity = arrayOfNulls<Activity>(1)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
val currentActivity: Activity?
val resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED)
if (resumedActivities.iterator().hasNext()) {
currentActivity = resumedActivities.iterator().next() as Activity
activity[0] = currentActivity
}
}
return activity[0]
}
You can replace the entire line using Class.isInstance.
if (activityType.isInstance(currentActivity)) { ... }
In Kotlin, is requires a class name (at compile time, you can't use a String either) - instead of a Class instance. Class.isInstance is used to perform the same check using a Class instance.
I have a Simple DAO including CRUD function
FeedEntryDAO.java
#Dao
public interface FeedEntryDAO {
#Query("SELECT * FROM feedEntrys")
LiveData<List<FeedEntry>> getAll();
#Query("SELECT * FROM feedEntrys WHERE uid = :uid LIMIT 1")
LiveData<FeedEntry> findByUid(int uid);
#Insert
void insertAll(FeedEntry... feedEntries);
#Delete
void delete(FeedEntry feedEntry);
#Update
int update(FeedEntry feedEntry);
}
For the select , it is okay to return the LiveData type.
Inside the Activity the code is pretty for the selection
viewModel.getFeedEntrys().observe(this,entries -> {...});
However, when I try to insert, update , delete the data. The code seems a little bit ugly and also create a asynctask every time.
new AsyncTask<FeedEntry, Void, Void>() {
#Override
protected Void doInBackground(FeedEntry... feedEntries) {
viewModel.update(feedEntries[0]);
return null;
}
}.execute(feedEntry);
I have 2 question about it:
Can I use LiveData to wrap the delete, insert , update function ?
Better way to maintain such asynctask class for delete, insert , update?
Appreciate any suggestions and advices. Thank you.
Can i use LiveData to wrap Delete, Insert, Update calls?
No, you can't. I wrote an answer to the issue. The reason is, that LiveData is used to notify for changes. Insert, Update, Delete won't trigger a change. It will return the deleted rows, the inserted ID or the affected rows. Even if it looks horrible it makes sense not having LiveData wrapped around your stuff. Anyway, it would make sense to have something like Single around the calls to let the operation triggered and operated on a RX-Java operation.
If you want to trigger those calls, you observe on a selection query which notify your LiveData onec you have updated, inserted or deleted some/any data.
Better way to maintain such asynctask class for delete, insert , update?
After looking at your example it looks like that you misuse the (Model/View/)ViewModel-Pattern. You should never access your repository in your view. I'm not sure if you'r doing this because its not visible in your sample. Anyway, after observing your LiveData and getting a result, there's no need to wrap the updating of data inside your viewModel in an AsyncTask. That means, that you should alway take care of
a) view <-> viewmodel <-> repository and not view <-> repository and view <-> viewmodel
and
b) don't try to use threads which are not needed. You observe LiveData on a Background Thread (#WorkerThread) by default (if not annotated with #MainThread) and get the value in the ui-thread (#MainThread).
Concerning question 2:
For Kotlin users there is now a really nice way to achieve this,
because since Room 2.1 there is direct support for coroutines. A neat example is given here.
You can use a "suspend function" directly in the DAO, which takes care that nothing is executed on the main thread:
#Dao
interface BarDao {
#Query("SELECT * FROM bar WHERE groupId = 2")
fun getAllBars(): LiveData<MutableList<Bar>>
#Query( "SELECT * FROM bar WHERE groupId = 0 LIMIT 1")
fun getRecentBar(): LiveData<Bar>
#Insert
suspend fun insert(bar: Bar)
#Update
suspend fun update(bar: Bar)
#Delete
suspend fun delete(bar: Bar)
}
then in your viewModel you would just:
fun insert(bar: Bar) = viewModelScope.launch {
barDao.insert(bar)
}
fun update(bar: Bar) = viewModelScope.launch {
barDao.update(bar)
}
fun delete(bar: Bar)= viewModelScope.launch {
barDao.delete(bar)
}
For the second question, there is another neater alternative to AsyncTask; which is using java Executor, the good news is that you can use a single instance of Executor instead of multiple instances of the AsyncTask for all CRUD operations.
Demo Example
public class Repository {
private static Repository instance;
private MyDatabase mDatabase;
private Executor mExecutor = Executors.newSingleThreadExecutor();
private Repository(Application application) {
mDatabase = MyDatabase.getInstance(application.getApplicationContext());
}
public static Repository getInstance(Application application) {
if (instance == null) {
instance = new Repository(application);
}
return instance;
}
public void insert(final MyModel model) {
mExecutor.execute(new Runnable() {
#Override
public void run() {
mDatabase.getMyModelDAO().insert(model);
}
});
}
public void update(final MyModel model) {
mExecutor.execute(new Runnable() {
#Override
public void run() {
mDatabase.getMyModelDAO().update(model);
}
});
}
public void delete(final MyModel model) {
mExecutor.execute(new Runnable() {
#Override
public void run() {
mDatabase.getMyModelDAO().delete(model);
}
});
}
}
The supported return types for each of the supported libraries are listed here. I've included the table here for convenience.
Query type
Kotlin language features
RxJava
Guava
Jetpack Lifecycle
One-shot write
Coroutines (suspend)
Single<T>, Maybe<T>, Completable
ListenableFuture<T>
N/A
One-shot read
Coroutines (suspend)
Single<T>, Maybe<T>
ListenableFuture<T>
N/A
Observable read
Flow<T>
Flowable<T>, Publisher<T>, Observable<T>
N/A
LiveData<T>
(Web archive link)
To Address your 2nd Question:
Google has posted an Android Room Codelab here which has laid out a concise MVVM architecture for implementing Room in Android:
(source: google.com)
Here the recommendation is to have database operations handled by a public static ExecutorService within the Database class. The location of the ExecutorService class can vary, just remember the idea is in MVVM your view does not care about how data are actually CURD'ed, that's the responsibility of the ViewModel, not View.
github repository for this code lab
In short, to apply a similar idea to your code, it would be something like this:
class YourRepository {
private FeedEntryDAO mFeedEntryDAO;
YourRepository(Application application) {
YourDatabase db = YourDatabase.getDatabase(application);
mFeedEntryDAO = db.feedEntryDAO();
mAllWords = mWordDao.getAlphabetizedWords();
}
void update(FeedEntry feedEntry) {
Database.databaseExecutor.execute(() - > {
mFeedEntryDAO.update(feedEntry);
});
}
}
class YourViewModel extends ViewModel {
private YourRepository mRepository;
void update(FeedEntry feedEntry) {
mRepository.update(feedEntry)
}
}
By doing this, your View can directly call viewModel.update(feedEntries[0]).
One important thing to mention is the mFeedEntryDAO.update(feedEntry) will automatically trigger the onChanged callback of your observer on the getFeedEntrys LiveData.
This is quite handy in your case. You can read more about how the trigger happens here.
You can use #Dao annotation in abstract classes too, so:
Create an abstract #Dao BaseDao class with the abstract methods #Insert insert(entities) and with the concrete method insert(entities, callback) that do that ugly AsyncTask job, calling the abstract #Insert insert(entities) on onBackground and your callback on onPostExecute.
Make your FeedEntryDAO also abstract extend BaseDao and the #Query methods abstract.
The result usage in Kotlin is quite pretty:
database.entityDao().insert(entities) { ids ->
// success
}
To app's UI to update automatically when the data changes this, use a return value of type LiveData in your query method description. Room generates all necessary code to update the LiveData when the database is updated.
#Dao
interface MyDao {
#Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
fun loadUsersFromRegionsSync(regions: List<String>): LiveData<List<User>>
}
Note: As of version 1.0, Room uses the list of tables accessed in the
query to decide whether to update instances of LiveData.
I'm playing with Kotlin and found interesting behavior.
So lets say i want to have some kind of a Factory :
internal interface SomeStupidInterface {
companion object FACTORY {
fun createNew(): ChangeListener {
val time = System.currentTimeMillis()
return ChangeListener { element -> Log.e("J2KO", "time " + time) }
}
fun createTheSame(): ChangeListener {
return ChangeListener { element -> Log.e("J2KO", "time " + System.currentTimeMillis()) }
}
}
fun notifyChanged()
}
where ChangeListener defined in java file:
interface ChangeListener {
void notifyChange(Object element);
}
And then I try to use it from Java like so:
ChangeListener a = SomeStupidInterface.FACTORY.createNew();
ChangeListener b = SomeStupidInterface.FACTORY.createNew();
ChangeListener c = SomeStupidInterface.FACTORY.createTheSame();
ChangeListener d = SomeStupidInterface.FACTORY.createTheSame();
Log.e("J2KO", "createNew a == b -> " + (a == b));
Log.e("J2KO", "createTheSame c == d -> " + (c == d));
The results are:
createNew: a == b -> false
createTheSame: c == d -> true
I can understand why createNew returns new objects due to closure.
But why I'm receiving the same instance from createTheSame method?
P.S. I know that code above is not idiomatic :)
This has to do with performance. Creating less objects obviously is better for performance, so that is what Kotlin tries to do.
For each lambda, Kotlin generates a class that implements the proper interface. So for example the following Kotlin code:
fun create() : () -> Unit {
return { println("Hello, World!") }
}
corresponds with something like:
Function0 create() {
return create$1.INSTANCE;
}
final class create$1 implements Function0 {
static final create$1 INSTANCE = new create$1();
void invoke() {
System.out.println("Hello, World!");
}
}
You can see here that the same instance is always returned.
If you reference a variable that is outside of the lamdba scope however, this won't work: there is no way for the singleton instance to access that variable.
fun create(text: String) : () -> Unit {
return { println(text) }
}
Instead, for each invocation of create, a new instance of the class needs to be instantiated which has access to the text variable:
Function0 create(String text) {
return new create$1(text);
}
final class create$1 implements Function0 {
final String text;
create$1(String text) {
this.text = text;
}
void invoke() {
System.out.println(text);
}
}
That is why your a and b instances are the same, but c and d are not.
First note: your example code doesn't work as is: the interface has to be written in Java in order to be available for use with SAM constructors.
As for the actual question, you've already touched on why this behavior is happening. Lambdas (in this case, the SAM constructors) are compiled to anonymous classes (unless they're inlined). If they capture any outside variables, then for every invocation, a new instance of the anonymous class will be created. Otherwise, since they don't have to have any state, only a single instance will back every invocation of the lambda. I suppose this is for performance reasons, if nothing else. (Credit to the Kotlin in Action book for the information in this paragraph.)
If you want to return a new instance every time without capturing any variables, you can use the full object notation:
fun createNotQUiteTheSame(): ChangeListener {
return object : ChangeListener {
override fun notifyChanged(element: Any?) {
println("time " + System.currentTimeMillis())
}
}
}
Calling the above function multiple times will return different instances for each call. Interestingly, IntelliJ will suggest converting this to the original SAM conversion syntax instead:
fun createNotQUiteTheSame(): ChangeListener {
return ChangeListener { println("time " + System.currentTimeMillis()) }
}
Which, as you've already found out, returns the same instance every time.
I suppose this conversion is offered because comparing whether these stateless instances are equal is very much an edge case. If you need to be able to do comparison between the instances that are returned, you're probably best off with the full object notation. Then you can even add some additional state to each listener, in the form of an id for example.
it looks like you try to use SAM conversion with Kotlin interface.
Note that SAM conversions only work for interfaces, not for abstract classes, even if those also have just a single abstract method.
Also note that this feature works only for Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.
For implementing interface like you want, you need to use object expression.
Also look at high order functions - I think you need them for your solution.
internal interface SomeStupidInterface {
interface ChangeListener {
fun notifyChanged(element: Any)
}
companion object FACTORY {
fun createNew(): ChangeListener {
val time = System.currentTimeMillis()
return object : ChangeListener {
override fun notifyChanged(element: Any) {
println("J2KO" + "time " + time)
}
}
}
fun createTheSame(): ChangeListener {
return object : ChangeListener {
override fun notifyChanged(element: Any) {
println("J2KO" + "time " + System.currentTimeMillis())
}
}
}
}
fun notifyChanged()
}
Also In IntelliJ IDEA I can't compile your code.