I'm in the process of updating my Kotlin Android app to use Coroutines 1.5.2 (previously used 1.4.3).
In 1.5.2, any uses of GlobalScope.launch are now flagged with an inspection as "delicate":
https://blog.jetbrains.com/kotlin/2021/05/kotlin-coroutines-1-5-0-released/#globalscope
Let's say I know what I'm doing (in some cases I need a scope that won't go away with the containing activity / fragment).
How do I mark these uses so they don't get flagged? The following options are suggested, but none seem good.
Option 1 - Add #DecliateCoroutinesApi to the method. This makes the method also "delicate" and any call to that now get the inspection, so that achieves nothing.
Option 2 - Add #DecliateCoroutinesApi to the class. Seems like overkill.
Option 3 - Add #OptIn(DelicateCoroutinesApi::class) to the method. Almost good, but requires a special compiler switch -Xopt-in=kotlin.RequiresOptIn. Kind of messy.
Any suggestions?
If you really know what you're doing, option 3 should be the way to go. #OptIn is indeed experimental but that compiler flag is a small price to pay to use experimental features via #OptIn in general. You could also not use the compiler flag, and keep the warning about the #OptIn annotation itself, but that's even messier IMO.
That said, you should really think twice about using GlobalScope. Most of the time you can instead create a scope that you control yourself (with a dispatcher and maybe a Job/SupervisorJob as well, so you can cancel coroutines when appropriate).
You can even delete the GlobalScope, to keep just the async call (CoroutineScope.async).
Related
I am working on an Android project where MVVM is the architecture being used. There is a use case where a Flow in my Repository needs to be updated based on the results of a callback which is triggered when something in my Data Source changes. The most appropriate choice for this problem seems to be callbackFlow. However, it is still experimental. I am very tempted to use callbackFlow, however, I understand that any future changes might break some code and I don't want that to happen in a production app. Considering the above scenario, what should be a replacement for callbackFlow? Or should I consider going ahead with callbackFlow?
callbackFlow is runtime stable - it works just as it is supposed to and it exists exactly because it is exactly the right tool to use in many cases.
I understand that any future changes might break some code and I don't want that to happen in a production app"
The only change that would affect how it functions is when upgrading your version of coroutines. That has nothing to do with runtime stability.
Both of my colleague and I have experience in MVVM of Web App, while we are new to native android development. Now we have contrary opinions about android data-binding -- I'm a fan of it while he is not.
My Arguments:
Reduces boilerplate code which in turns brings
Less coupling
Stronger readability
Powerful, easy to implement custom attribute and custom view
Even faster than findViewById (details)
His Arguments:
The auto-generated .class increases app size.
Harder to debug
I've made some investigation but there are not many discussions about it. Now I want to collect the pros and cons of android data-binding.
Aspects of discussion include but are not limited to:
unit test
app size
performance
learning curve
readability
coupling
I will comment on your arguments first then I will state my opinion:
1.Remove boilerplate code - it will remove some it will just move some in the xml or it will require additional classes. So you have to be careful and balance the use of data binding.
2.Stronger readability - depends if you are a new developer then you may find it easy to learn it but if you previously worked on android you will need extra time to learn it.
3.Powerful - the code has more power, you can implement whatever you like in code. Think about it like this, everything you implement using data binding has a code equivalent (it might be longer and more code to write), but the revers is not valid.
4.Even faster than findViewById - comparing the speed between these two, in my opinion is useless, you will never notice the difference, if you see some difference, then one of the implementation is wrong.
5.Auto generated class - it's true it will increase the app size, but again only if you have tons of it it will matter. It's true that on the android dev web site they state that it's kind of bad to use libraries that create autogenerated code or annotations that will generate extra code.
6.Hard to debug - depends, like readability, of what you are used to, heck debugging is hard either way for some problems, and you will get better by debugging not by using a different library.
So this is pure my opinion, I've developed many apps using different libraries and different approaches, and they all had pros and cons, but what I've learn: balance everything, don't use tons of libraries, don't waste time implementing things that are implemented already and work well, don't "decouple everything", don't "couple" everything, don't use code only, don't try to "generate" everything.
I think it's quite wrong, and you can get a wrong idea, if you ask for 'pros & cons' about some library/implementation, because usually it won't be impartial, you will get a lot of pros from somebody who used the library in a specific way and it worked and others will give you cons because they used different and it didn't work.
So in conclusion, I think you should check what the library can do for you and what can't do for you and decide if it's good for your setup. In other words, you should decide if a library is good for you not other people ;).
Update - 8 August 2018
First of all I still stand with my initial conclusion, balance is the key in these kind of situations, but in my case, data-binding speed-up a little bit the development process and also improved it. Here are a few new points that you should all think about.
Testing the UI -- with data-binding it's much more easy to test the UI, but data-binding it's not enough for that, you also need a good architecture and using the Google suggested architecture will show the actual power of data-binding.
The most visible changes were provided for points 2 & 5 from my original answer. It kind of was easier to read the code after we decided to use data-binding, and the most important thing here is: we as a team decided that we will use data-binding and after that, we kind of expected to have most of the trivial and basic UI setup in the XML file.
For the debugging part, here's a little bit tricky, Android Studio has a lot to improve on the errors and autocomplete for the data-binding but the most common errors you'll get them after the first 2-3 occurrences. Also I've learned that a "clean project" form time to time, helps A LOT.
Another point that you'll have to take in consideration is the project configuration to use data-binding, right now AS (3.1) supports by default data-binding (just set a flag in graddle) for Java, but I had some issues with Kotlin, after a bit of search here on SO, I managed to fix everything.
As a second conclusion (from my original post), if you can and the project deadline/requirements/etc allows you to try data-binding, go for it it will worth (unless you do some really stupid stuff :)) ).
I am working on a huge Android project and the team has decided to phase out Data Binding library. Why? The primary reason is that it is exacerbating build time(10+ mins), by generating a lot of classes in the build process.
Even if i like danypata's answer i would like to add/edit some of his statements to android databinding.
1.Remove boilerplate code - As written in danypatas answer it removes some code and adds some code somewhere else like in layouts. That doesnt mean that the boilercode isnt reduced because usually it is reduced.
For example you may want to create a bindingadapter, which handles several custom arrayadapters for your spinner/recyclerview/listview/.. but requires only one simple adapter. You may want to use the adapter in your layout by using e.g.
app:myCoolAdaptersData="#{model.mydata}"
Now you can create your generic adapter and (re)use your bindingadapter in all your layouts instead of using for example:
ListView lv = findViewById(...);
CoolGenericAdapter<MyModel> coolAdapter = new CoolGenericAdapter<>(...);
lv.setAdapter(coolAdapter);
This is just one simple example which recudes the code alot in larger projects. Another sample to recude code is, that you bind your model to your layout. Updating field-values of your model usually updates your model aswell (if its at least a BaseObservable/ObservableField).
That means that you dont need to find all your views, update your views, update your models, ...
2.Stronger readability - The extra time spent for learning databinding doesnt really matter. Since the layouts are not really different except that you wrap them into a layout tag and put your namespaces there, it doesnt really differs from "regular" layouts. Using bindingadapters and accessing the model in the layout may take some time, but usually you can start beginning with the basics which are easy and beautiful to use aswell. Learning new stuff always takes time, but you will easy overhaul the time when using databinding after a while.
3.Powerful - Yes, its very powerful. Its easier to reuse existing code, reuse existing bindingadapters and may lead to more generated code but thats not always true. For example you may create multiple adapters within several classes instead of creating one bindingadapter, it may be hard to "optimize" it later. Optimizing the Bindingadapter means that it gets updated everywhere. Optimizing may decrease the "lines of code" since the boilerplace is reduced anyway.
I agree to 4. and 5.
6. Hard to Debug Since AS 3.0+ outputs useful hints like syntax issues in your layout (line number and file) its easy to debug databinding generated code. If you have problems finding the issue you may also want to check for errors in the generated code. Some librarys like dagger 2 or android architecture library may confuse you because the error lines doesnt match with the real "error". This is due generated code by other annotation processors. If you know that those annotation processors may get in trouble with databindings error outputs, you can easy fix that.
7. Unit Testing Its possible like if you dont use databinding by using executePendingBindings.
8. Readability Readability may be better without databinding. Since you put some business logic into your layout, some into your real code, it may lead to spaghetti-code. Another problem is that using lambdas in your layout may be very confused if the "layout-designer" doesnt know which param may be used.
Another very big problem is that bindingadapter can be everywhere. Using BindingAdapter annotation generates the code. That means that using this in your layout may lead to problems to find the proper code. If you want to update a bindingadapter you need to "find" it.
When should you use what? For larger projects it is a really good idea to use databinding together with the mvvm or mvp pattern. This is a really clean solution and very easy to extend. If you just want to create a small simple application you'r fine using MVC Pattern without databinding. If you have existing generic bindingadapters which can be used from other projects you may want to use databinding, because its easy to reuse this code.
Data binding, concept wise looks promising to me, but I do not like the implementation part.
I would appreciate a bit more simpler and direct approach to it.
Thus I feel lot more comfortable in keeping it old school.
Model classes, mutable objects, observers feel like too much to me, if some how the data variables used for binding are received as Objects that are mutable and observable directly in a class , then that would make the process lot more cleaner, simpler and concise.
Recently I’ve been rethinking my android architecture project, trying to adapt it to a more “clean architecture”, specifically, the kind of design suggested by “Uncle Bob”.
Which it involves several layers of abstractions, a nice isolation of responsibilities and a very strong dependency inversion achieved by dependency injection; which, ultimately, leads to a very decoupled-portable system. A perfect candidate to be tested by unit testing and integration testing.
In my android implementation I’ve ended up having three different modules or layers:
-domain: entities, interactors, presenters (pure java module)
-data: (acts as a repository to supply the data to the domain) (android library module)
-presentation: ui related stuff, fragments, activities, views, etc (android application module)
So, I’m trying to figure out what would be the best approach on the iOS ecosystem.
I’ve tried creating a project with multiple targets to achieve the same solution:
-domain: command line target (which seems very weird but I think is the most pure swift target available)
-data: cocoa touch framework
-presentation: cocoa touch framework
With this approach I can use these targets in the way I did with android modules. But the first caveat I’ve found it is that I need to add manually every new file to the dependent target.
But my knowledge is very limited in projects with multiple targets. I mean I’ve never created an iOS application with multiple targets. So I don’t know even if the solution would be use a framework (cocoa touch/cocoa) as a target instead of a command line module for the domain layer.
Any thought would be really appreciate.
Thanks!
Uncle Bob's Clean Architecture absolutely applies to iOS, Swift, and Obj-C. Architecture is language agnostic. Uncle Bob himself codes mostly in Java but in his talks he rarely mentions Java. All his slides do not even show any code. It is an architecture meant to be applied to any project.
Why am I so sure? Because I've studied MVC, MVVM, ReactiveCocoa, and Clean Architecture for 2 years. I like Clean Architecture the best, by far. I tested it by converting 7 Apple sample projects to using the Clean Architecture. I've used this approach exclusively for over a year. It works out better every time.
Some of the benefits are:
Find and fix bugs faster and easier.
Extract business logic from view controllers into interactors.
Extract presentation logic from view controllers into presenters.
Change existing behaviors with confidence with fast and maintainable unit tests.
Write shorter methods with single responsibility.
Decouple class dependencies with clear established boundaries.
We also added a router component so we can use multiple storyboards. No more conflicts.
Writing unit tests is greatly simplified too because I only need to test the methods at the boundaries. I don't need to test private methods. On top of that, I didn't even need any mocking framework because writing your own mocks and stubs becomes trivial.
I've written my experience for my last 2 years studying iOS architecture at Clean Swift I also put together some Xcode templates to generate all the Clean Architecture components to save a ton of time.
UPDATE - To answer #Víctor Albertos's question about dependency injection in the comment below.
This is a really great question and demands a long detailed answer.
Always keep the VIP cycle in mind. In this case, the doSomethingOnLoad() method is not a boundary method. Rather, it is an internal method invoked only within CreateOrderViewController. In unit testing, we test a unit's expected behavior. We give inputs, observe outputs, then compare the outputs with our expectations.
Yes, I could have made doSomethingOnLoad() a private method. But I chose not to. One of the goals of Swift is to make it easy for developers to write code. All the boundary methods are already listed in the input and output protocols. There is really no need to litter the class with extraneous private modifiers.
Now, we do need to test this behavior of "The CreateOrderViewController should do something on load with this request data" somehow, right? How do we test this if we can't invoke doSomethingOnLoad() because it is a private method? You call viewDidLoad(). The viewDidLoad() method is a boundary method. Which boundary? The boundary between the user and view controller! The user did something to the device to make it load another screen. So how do we invoke viewDidLoad() then? You do it like this:
let bundle = NSBundle(forClass: self.dynamicType)
let storyboard = UIStoryboard(name: "Main", bundle: bundle)
let createOrderViewController = storyboard.instantiateViewControllerWithIdentifier("CreateOrderViewController") as! CreateOrderViewController
let view = createOrderViewController.view
Simply calling the createOrderViewController.view property will cause viewDidLoad() to be invoked. I learned this trick a long time ago from someone. But Natasha The Robot also recently mentioned it too.
When we decide what to test, it is very important to only test the boundary methods. If we test every method of a class, the tests become extremely fragile. Every change we make to the code will break many, many tests. A lot of people give up because of this.
Or, think about it this way. When you ask how to mock CreateOrderRequest, first ask if doSomethingOnLoad() is a boundary method that you should write test for. If not, what is? The boundary method is actually viewDidLoad() in this case. The input is "when this view loads." The output is "call this method with this request object."
This is another benefit of using Clean Swift. All your boundary methods are listed at the top of the file under explicitly named protocols CreateOrderViewControllerInput and CreateOrderViewControllerOutput. You don't need to look elsewhere!
Think about what happens if you were to test doSomethingOnLoad(). You mock the request object, then assert that it equals to your expected request object. You are mocking something and comparing it. It's like assert(1, 1) instead of var a=1; assert(a, 1). What's the point? Too many tests. Too fragile.
Now, there is a time when you do mock CreateOrderRequest. After you've verified the correct CreateOrderRequest can be generated by the view controller component. When you test CreateOrderInteractor's doSomething() boundary method, you then mock CreateOrderRequest using interface dependency injection.
In short, unit testing is not about testing every unit of a class. It is about testing the class as a unit.
It is a mindset shift.
Hope that helps!
I have 3 series of draft posts in Wordpress on different topics:
In-depth look at each of the Clean Swift components
How to break up complex business logic into workers and service objects.
Writing tests in Clean Swift iOS architecture
Which one of these do you want to hear more first? Should I bump up the series on testing?
In my opinion Clean Architecture is a set of ideas, rules, principles... to make a code better.
[Android Clean Architecture]
With this approach I can use these targets in the way I did with android modules.
You are able create a target[About](application target or framework target...) but it depends on your needs
If you read Architecting Android...Reloaded from Fernando Cejas
you might have seen that I used android modules for representing each layer involved in the architecture.
A recurring question in discussions was: Why? The answer is simple… Wrong technical decision
The idea is that is not necessary to use some build components to implement Clean Architecture
Otto library is now used in the project I'm working on. I had to debug a certain thing and it was quite hard to find out why certain code was executed.
Isn't it Otto a little bit like goto? I mean we can execute the code whenever we want from the places completely unrelated to that code and the only evidence of this is annotation. Labels in goto are even more visible.
Basically the question is - is the usage of event buses acceptable in the projects?
Yes usage of EventBus is acceptable and even more like required in big production projects. Because of it makes code less. Problem is not EventBus is way HOW it's used.
EventBus is just simple and fast way instead of define a lot of interfaces.
Your problem is more like coding style things. Code is not clear and you cannot undestod what is going on and where.
Is there a way to somehow intercept calls to the standard Log in android and perform some other action?
In desktop Java one would usually get some logger so there are ways to install a different logging handler / implementation. However, Android seems to have a static call to Log, and I could not find any information about replacing the default behavior.
I realize I can monitor the device log through ADB, but I'd like to have a different behavior in running apps on a device who opt in (e.g., by executing a certain instruction when the program starts out).
As AedonEtLIRA points out Log is final so you need to roll/borrow a new one. I've been using Prasanta Paul's "MLog": http://prasanta-paul.blogspot.com/2010/07/custom-logger-for-android.html
It makes it easy to save logs to a text file and/or disable logging completely.
If it doesn't already do what you need, it is a good base for managing logging.
I think your best solution would be to replace all the Log calls in your application with your own class, MyLog, then call Log if they don't opt-in, and call your special logging feature if they opt-in.
Replacing all the Log calls shouldn't be hard, just a find and replace.
In addition to MLog proposed by #Darrell, there are several other logging frameworks for Android, including:
logback-android
log4j-android
microlog4android
Of the three, logback (the next-gen log4j) seems to be the most capable and have the richest API (and lots of documentation), while microlog is the most compact (but limited in features...but maybe it does all you need). All three support the SLF4J logging facade, so you can easily swap out microlog for logback, log4j, jul, or some newer framework down the road.
As with MLog, these frameworks require replacing the calls to android.os.util.Log (it doesn't "intercept" the calls as you might be after).
Because Log is final, I think you will have to write your own logging system and implement that if you want to change anything.