anvil-ui / anvil

Minimal UI library for Android inspired by React
MIT License
1.45k stars 90 forks source link

Anvil needs promotion #46

Open zserge opened 8 years ago

zserge commented 8 years ago

While Anvil has certain advantages over Anko, Google Data Binding library or React Native, only a few people know about this library. There is no Anvil tutorials around the web, documentation on Github and my blog suffers from my linguistic skills (English is my second language).

I wonder if any of you have finished any apps using Anvil, or maybe have a blog and would like to spread the word about Anvil? Any help is appreciated.

zserge commented 8 years ago

So far we have a website where I try to post my thoughts about Anvil - http://zserge.com We also have Anvil website with a brief description of what it does - http://anvil.site We have some examples - in Kotlin https://github.com/zserge/anvil-kotlin-demos and in Java https://github.com/zserge/anvil-examples

@krugloid wrote an alarm clock (https://github.com/trikita/talalarmo) and a Takahashi slide app (https://github.com/trikita/slide) with Anvil + Redux.

We've made a wrapper for RecyclerView to use it with Anvil - https://github.com/trikita/anvil-recyclerview

@Orgmir wrote a budget app https://github.com/Orgmir/budget-app-android/ (but unfortunately it uses old Anvil syntax)

@felipecsl made a few demos using Anvil - https://github.com/felipecsl/cycle-android

Also we have Redux libraries - one by @brianegan with a clever name https://github.com/brianegan/bansa and another by myself and @krugloid https://github.com/trikita/jedux

But there is still an endless area of unwritten demos like HN reader, Github client, Reddit client, IRC chat etc, so volunteers are welcome!

felipecsl commented 8 years ago

I'd like to further explore the Cycle paradigm for Android and that will involve using Anvil more extensively. I have a bigger app that I've been building for a while (https://github.com/elifut/android) where I plan to use cycle-android to build some screens and see how it goes. I'll make sure to open issues and provide feedback to you about how Anvil goes, I'm pretty excited about that. Thanks for the great work!

brianegan commented 8 years ago

Hey there! Anvil is super cool, I'd be happy to help out a bit more. My problems: I'm still trying to find the right architecture that works with Anvil, and I haven't written even a medium-sized app with it yet, only sample projects as a playground. Going the Redux route is really nice in some ways and a bit cumbersome still in others, so I'm still trying to play with it in that area.

However, I'm planning on Blogging a bit more in general about these things, work's just been a bit crazy lately. What topics would you be most interested in covering? Basics, how anvil works, etc? What format are you thinking? We could go something like the gitbook route, blog posts, videos, etc.

Another random idea: A coworker at SoundCloud even mentioned it might be cool to have an Organization similar http://github.com/reactjs to encapsulate all of the well maintained solutions in one area, so folks have a trusted authority of where to turn.

zserge commented 8 years ago

@brianegan thanks for the feedback, really appreciate it! The flexibility of Anvil can play against it, it doesn't force you to use MVVM or Redux or "your own architecture TM". And to new users it can be a problem. So far I've been more than happy with Redux architecture as long as it supports middlewares (like trikita/jedux). I can now prototype an average simple app (audio looper, irc chat, puzzle game, presentation making app) in ~3-8 hours.

Blog posts are more than welcome, since I often find I can't express or organize my thoughts in human-readable English. I feel that Anvil may be too complex to newcomers (it requires a serious paradigm shift for traditional Android developers) - they just don't get what Anvil does and think it exists just to replace XML layout with code like Anko. I'm open to suggestions, I tried to sum up Anvil core APIs at http://anvil.site, but it's far from being perfect. Tutorials and success stories is probably what we need in the first place.

Making an organization makes a perfect sense as soon as we get a community. So far it's been just a couple of projects around the web using Anvil and they are easy to discover. But I will definitely consider this in the nearest future.

LalitMaganti commented 8 years ago

I've been playing around a lot with Android's view binding in my IRC app (https://github.com/tilal6991/channels). The biggest issues with the native view binding is that it is one way and requires a lot of boilerplate to inform the UI of exactly what has changed.

Having come across Anvil I feel it could remove much of the boilerplate I've noticed when writing the app so far. I'll take a look and see how usable it is with bansa and if it works I'd be happy to espouse how awesome the library it is :)

virtualandy commented 8 years ago

I'm just scratching the surface of Android but would happy to be a guinea pig for any rough drafts of blog posts/tutorials. I can deal with poor English (@zserge everything I've seen written so far has been pretty great!) and help translate or complete it as needed. I can even help turn a rough outline into a full post if that would help, assuming you can provide the steps to walk me through doing ___ and ending up with an app or just snippet.

Can't commit a ton of time but should be able to respond in a few days time at worst. Let me know if that helps. And in the meantime I'll keep learning and hopefully write one of my own tutorials.

brianegan commented 8 years ago

@tilal6991 Sounds great :) Let me know if you run into any issues along the way if you try out Bansa / Jedux! Be really interested to hear what worked well and what was confusing so we can document and improve the libraries!

LalitMaganti commented 8 years ago

@brianegan So I did take a look at Bansa and the biggest issue I find is with the concept of copying the class on every state change. I feel this is simply not a scalable system on Android where short lived objects just create GC churn especially on old versions of Android.

Some sort of system which relies on mutable state (which I understand is completely orthogonal to the concept of functional programming which Jedux/Bansa are trying to emulate) is required I feel.

zserge commented 8 years ago

@tilal6991 Yes, immutability can be painful. In java it's even worse. I see two problems here - producing lots of garbage and writing lots of code.

Garbage: in fact, GC is happy to collect smaller objects more frequently rather than large ones less often. In your code you would emit actions on UI interactions (or some background asynchronous inputs), but it should not happen every 1ms. With this in mind, freeing a small object from time to time should be fine. You may split your state class into smaller subclasses, so actions would modify only a part of it and thus produce less garbage. I did this in some audio software and it worked fine. Of course if your demand is zero garbage - then you will end up with using state pools or something. Also, consider using identifiers/references instead of objects inside your state. E.g. instead of keeping recorded audio samples in your state class keep them as a files and let state contain only a file name. Same for databases- use IDs etc.

Next, code. I used Immutables in Java to reduce the boilerplate and it kept me away from writing most of the code. Collections were the hardest ones to deal with. Arrays has terrible performance and Lists were hard to modify. I often wrote custom wrappers for them. I don't know if something similar exists for Kotlin, but I'm sure the language is powerful enough to write a handy builders for your state.

Finally, immutability in Redux is a religious thing, but you may actually avoid it. Yes, you will lose predictability in your state and you will have to make all state methods synchronized. But I think it should work fine. Mutating a class that is never cached and treated as an immutable is not much different from replacing one immutable instance with another. It really sounds like a pool of states when a previous state is feed and replaced, well, by the same object. Don't cache the state object - and it will look like as if it's immutable. I don't think there are many examples of mutable Redux states around the web, so you're likely to be a ground breaker. Would be interesting to hear about the results though.

LalitMaganti commented 8 years ago

@zserge my info about allocations was from https://medium.com/google-developers/developing-for-android-ii-bb9a51f8c8b9#.ov0n9fmzw

I do understand the idea of object pools and I've already been using them in the app so for objects it's fine. The biggest issue is with collections: I've got a lot of maps and lists of stuff in my app and of course copying collections is very expensive if I want to switch between them with immutable state it's not great.

One idea I've been playing around with is some sort of transaction oriented list and map data strctures (similar to AdapterHelper in RecyclerView's library) which could be updated in the background but just the operations themselves would be stored with the list not modified. Then on the main thread, the transactions could be committed and Anvil's render method can be called. It's a race/concurrency minefield so need to think some more about how it might work :)

brianegan commented 8 years ago

"I've got a lot of maps and lists of stuff in my app and of course copying collections is very expensive if I want to switch between them with immutable state it's not great."

Totally, and this is a bit deceptive. I'm always doing state.copy in the reducers, but the Immutable library used by @zserge and Kotlin's state.copy actually do something called "structural sharing" when you make a "copy." Meaning they copy the least amount of values they need to, and share references to the parts of the previous state that didn't change. Therefore, if you have a large map, and state.copy to update a different value, it won't completely copy that map over every time. This is how immutability in most functional languages remain memory efficient!

Also, as zserge notes, instead of making the whole state immutable, you could make only part of your state tree immutable. You could use something like the immutable collections from https://github.com/andrewoma/dexx that use structural sharing as well to reduce memory footprint.

However, you have a totally valid point and is one thing I need to investigate more. I don't think this model will totally work with larger apps, and memory optimization might be necessary.

And of course -- you can alway just avoid immutability all together :)

LalitMaganti commented 8 years ago

@brianegan the library you linked simply seems to be hiding the copies away. They're still there just hidden away (https://github.com/andrewoma/dexx/blob/master/collection/src/main/java/com/github/andrewoma/dexx/collection/ArrayList.java#L101).

I did know about Kotlin's structural sharing when you make a copy of the object - I was more concerned about your collection copy when you update the counter list (i.e. the map operation used at https://github.com/brianegan/bansa/blob/master/examples/listOfCounters/src/main/kotlin/com/brianegan/bansa/listOfCounters/counterReducer.kt#L22 calls https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/generated/_Collections.kt#L1206 which is making a copy).

I think with my initial experimentation I will be avoiding Immutability. It's a shame Android wasn't designed with it in mind but we have to work with with we have.

brianegan commented 8 years ago

@tilal6991 Oh dang, good catch on that one! Yah, that is definitely not a great immutable abstraction, haha.

Might also be worth checking out http://immutables.github.io/immutable.html -- this is the lib @zserge uses in some of his projects. It might be better at this!

However, if you're not into it and worried about memory and GC pauses, no immediate need to go immutable! Still definitely one of the biggest open questions for me as well. While I agree with the usefulness of immutability, the platform might not be ready for it.

LalitMaganti commented 8 years ago

Don't get me wrong I love FP and immutability (Haskell is my fav language :P). As you say, the platform is just not made for it unfortunately.

I will check out the other library as well as continue playing around with Bansa and Anvil to see where I get :)

zserge commented 8 years ago

@tilal6991 I haven't used andrewoma/dexx library, but it seems like ArrayList from that library is not a representative implementation (they state in the comment to the class that it's only aimed for infrequent modifications to achieve fast access times). Vector class from that library seems to be a smarter list implementation, but probably some benchmarks would show it better.

LalitMaganti commented 8 years ago

@zserge nice spot! I didn't notice that Vector was the efficient immutable implementation.

Integrating changes of these collections with concepts like notifyItemInserted of recyclerview should be interesting though. Something to think about I guess...

brianegan commented 8 years ago

@tilal6991 I've got a simple RecyclerView + Bansa implementation here:

https://github.com/brianegan/bansa/blob/master/examples/listOfCountersVariant/src/main/kotlin/com/brianegan/bansa/listOfCountersVariant/BansaRenderableRecyclerViewAdapter.kt

You can check out RootView in that example to look at how I'm using the adapter + recycler view in that area. Not sure this is the best implementation, just what I came up with!

Nice cus it handles the notifying of state changes, etc. You can just continually provide the correct data to the adapter and it'll handle the rest.

If you want the nice animations from recylcerView, you can simply use setHasStableIds(true), and implement a getId function. Then, when you notifyDataSetChanged on the collection, the underlying Recyclerview implementation will handle diffing the data sets and performing the appropriate animations!

brianegan commented 8 years ago

@zserge Good catch on the vector impl! This whole convo is so good it makes me want to write more docs (the original topic!).

Gonna start putting together some material this weekend :)

LalitMaganti commented 8 years ago

@brianegan wow that is nice! I forgot about recyclerview having the ability to make change notifications based on ids :D Will definitely look into that.

Edit: while it definitely seems like an excellent option to explore there are still some caveats which make calling the individual methods more efficient: http://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#notifyDataSetChanged(). I can live with them though so will do a deep dive.

brianegan commented 8 years ago

@tilal6991 Yah for sure it's more efficient to call individual methods. In my opinion, this is not great advice: "If you are writing an adapter it will always be more efficient to use the more specific change events if you can. Rely on notifyDataSetChanged() as a last resort."

Personally, I'd start with notifyDataSetChanged at first b/c it's so simple, and optimize if you run into performance issues second. I feel like starting with the low-level methods might be premature optimization as we've used this a decent amount at work and not run into big performance issues, but I don't know the data needs of your app!

LalitMaganti commented 8 years ago

@brianegan totally get where you're coming from and I agree with your statement that it's premature optimisation. Just wanted to note it because it was explicitly in the docs.

For my needs I do not imagine it being a problem (in fact I think it might be more efficient in some cases).

brianegan commented 8 years ago

Totes. Thanks for sharing and good discussion :)

nfortu commented 8 years ago

@zserge Great library!!, I'm playing with Anvil because I really want reactive views in Android.

One big concern I have is the lack of composable components, I'm probably wrong but all the examples I saw are one main virtual render tree and it's allways rendered, I think that the main advantage of React is composability and be able to update an individual component independent of other compoennts.

Is there a good way of doing this? Can I have a AnvilComponent with nested components and tell Anvil to render just one of them and not all the hierarchy? like react does. I want to represent my app in components with internal state and update the view only for the component's sub-tree.

Thanks.

zserge commented 8 years ago

@nfortu Thanks for the feedback!

You can nest components: define component as class MyView extends RenderableView and include/reuse as v(MyView.class, ....). Of course you may wonder how to pass data into the component nested? Java typing makes it hard to have a generic dynamic State object, so you will have to call your custom component/view methods directly, e.g. ((MyView) Anvil.currentView()).setFoo(). That's how can pass "properties" when you mount components. Or you may continue using Fragments as components if you like.

Another thing is rendering individual components. React use case is somewhat different from Anvil: web has no "smart" adapters that would reuse views, and browser screen is often filled with more views than mobile device. That's why to achieve decent performance React asks you to render each component individually. Anvil often deals with smaller screens, Android views are much heavier than DOM nodes so you can't have lots of them at once, and adapters reduce the actual view count. So despite Anvil has an internal method to render individual component (see Anvil.render(Mount m), it's hidden from the public API because there is no real performance gain from rendering individual mount points vs rendering it all at once.

zserge commented 8 years ago

@nfortu Another option to have components is to compose functions, e.g.:

void myLayout() {
  linearLayout(() -> {
    navigation(someProperties);
    content(someContent);
  });
}

void navigation(MyNavigationProps props) {
  frameLayout(() -> {
    // define you layout that may depend on props
  });
}
...

It makes it harder to make stateful components with this approach, but you may enclose state objects with your closures, or pass them from top to bottom etc.

nfortu commented 8 years ago

@zserge Thanks! really appreciate your feedback, I'll take this in consideration, by the way I'm using Kotlin so I'll probably end up with some design/arquitecture once I start a new app, General design concepts are clear for me because I have Android and React experience but I know fo sure many Android developers doesnt's know the concepto of reactive views (I talk with many of them about this) and that's why most of them do not look up for Anvil (maybe). I agree that Anvil need more articles, more complex examples, etc

graknol commented 8 years ago

@nfortu I've written AnvilKotlin, which wraps around this library, but I'm also exploring the idea of what you mentioned, a real viewtree over at AnvilCore. So stay tuned for that, as I hopefully release a version in the near future. :)

lenguyenthanh commented 8 years ago

@nfortu : do you have any good article about reactive views? I wanna discover it because Anvil looks awesome. I just try google but nothing found :(

p/s: sorry guys for ask the question in a wrong place

nfortu commented 8 years ago

@lenguyenthanh The concept was introduced by React library from Facebook, there are tons of articles and videos, just look for React info to learn about the concept of reactive views, Watch this video, it was the first intruduction of the idea: https://www.youtube.com/watch?v=DgVS-zXgMTk

DavidMihola commented 8 years ago

Hi,

I just wanted to (1) thank you for Anvil, (2) agree that it needs more publicity and (3) mention that I submitted a talk about Bansa/Anvil for the upcoming Droidcon in Vienna in September 2016. So far it doesn't seem like my talk was accepted, but maybe they will accept it in the second selection round... In any case I hope I'll be able to use in a proper app soon!

MatthewPosgate commented 7 years ago

I have stumbled across Anvil while trying to learn android development from a c# perspective using Xamarin. I like the look of it a lot but I'm a bit too new to attempt a translation of anvil from java to c# although the languages are very similar. I'm just wondering if anyone else has gone down this route? By putting a nuget package in the right place millions of visual studio developers would have access to it.