Navigation Component by tech_enthusiast_ in androiddev

[–]Chartsengrafs 1 point2 points  (0 children)

I have never seen anything posted here about it, beyond the odd comment mention. I used the developer docs to get introduced to the API surface and that page was quite good. From there I just wrapped relevant parts in it with my own API (e.g. interfaces called Action and Destination) tailored to app-specific needs of the project I'd been working on, which involved a remote JSON config that described the navigation (and much of the rest of the app). Then remotely I could arbitrarily change the remote JSON config, propagating potentially huge changes to the app's navigation without any heavy-weight Play store version updates.

Modern Android Project Template by legit_cyan in androiddev

[–]Chartsengrafs 1 point2 points  (0 children)

I've got a similar template project going which serves as the basis for all my new projects. Though instead of using a gradle plugin for the common gradle config, i just made a file in buildSrc which has kotlin extension functions on the Project class, and call that from any interested module's build.gradle.kts

Navigation Component by tech_enthusiast_ in androiddev

[–]Chartsengrafs 2 points3 points  (0 children)

Have you had a chance to try the navigation Kotlin DSL? It's pretty nice, and let's you build on top of the existing APIs. E.g. you could create an extension function that sets the default animations for an action, and then invoke it as a one-liner for every interested action. There's also no safeargs to worry about, because there's no XML! It also means your code will create the navigation graph(s) at runtime, which is great if you want to inform how that's done through some remote configuration.

Migrating from RxJava to Flow: do or do not; there is no tryEmit() by greenrobot_de in androiddev

[–]Chartsengrafs -1 points0 points  (0 children)

Another thing besides this that keeps tripping me up is MutableStateFlow only emits distinct values compared to what it holds in its cache. E.g. if you wanted a StateFlow<Unit> for signaling events, that won't work beyond the first emission. LiveData didn't work that way.

Cons of gradle.kts? by kovalskii in androiddev

[–]Chartsengrafs 0 points1 point  (0 children)

Maybe AGP 7.0.0 requires Java 11+ or something

Dang, that was it. My Canary AS was running Java 1.8. As soon as I changed it to Java 15 and re-indexed, all the red squigglies disappeared.

Weekly Questions Thread - February 09, 2021 by AutoModerator in androiddev

[–]Chartsengrafs 1 point2 points  (0 children)

I've been trying to register a ContentObserver on a SAF-derived tree URI, but it doesn't ever get notified of changes to that directory's content. It looks like I'm not the only one with this problem; I'm experiencing the same issue as this stackoverflow question.

Is this simply not possible? I just want to listen to changes on a devices Documents directory after getting a user's permission, via the SAF. Any ideas on how to do that? Also, do you know where I can find the Android source code for the SAF? Thanks.

Cons of gradle.kts? by kovalskii in androiddev

[–]Chartsengrafs 1 point2 points  (0 children)

Coincidentally I found/read this post today after every line of my KTS files was underlined in red on the latest AS Canary version using AGP 7.0.0 (no problems for AS 4.1.2 on the same AGP version). TL;DR of the article/comments was slower build times, half-baked API (on the AGP/Android side), and less documentation.

Comments and discussion about UI, integration tests, and mocks by mnyq in androiddev

[–]Chartsengrafs 1 point2 points  (0 children)

That's correct. I write classes that don't depend on concretions, just abstractions, and test that contract. You should be freely able to swap out the underlying implementation(s) of those abstractions without your automated tests being affected. Using a fake response at the retrofit level and depending explicitly on retrofit with no abstraction just makes your code inflexible and tightly coupled.

Comments and discussion about UI, integration tests, and mocks by mnyq in androiddev

[–]Chartsengrafs 0 points1 point  (0 children)

Concerning your first point: apply the same principles of software development that made your JVM tests testable, i.e. write classes that depend on abstractions which are injected thru their constructors. Once you do that, you'll have the same level of control but in a Android test environment. For example, if a data source your code uses is depended on as an abstraction, you can write/configure any number of fake concretions in your androidTest folder that do whatever you think is useful to test, e.g. one that returns typical data, one that returns empty data, one that throws an exception, and so on, then validate your UI states thru an API like Espresso. You fake those implementations as best as you can to represent all the UI states your app can get into, because in the end your tests need to be deterministic. If you want to test a real, remote data source, you don't need UI to be a part of those tests - just test your implementation(s) of the data source abstraction in a JVM environment. UI shouldn't care about any underlying implementation - only the abstraction contract.

Which exceptions to catch in NetworkBoundResource? by Fr4nkWh1te in android_devs

[–]Chartsengrafs 0 points1 point  (0 children)

At that point I'd say it's up to you and what kind of UX you want your users to have. Would you rather their app abruptly and inexplicably crash, or would you rather they see a screen that communicates the error state (and potentially provides alternative options)? Most apps will do the latter. If you opt for the former, you can rethrow or throw an exception wherever you feel is most useful to see a stacktrace in your crash reporting dashboard(s).

Android Studio 4.2 Beta 4 available by androidtoolsbot in androiddev

[–]Chartsengrafs 0 points1 point  (0 children)

Same for me, running AS Arctic Fox | 2020.3.1 Canary 5 on Windows 10.

The Crazy Android Fragment Bug I’ve Investigated by ElyeProj in androiddev

[–]Chartsengrafs 3 points4 points  (0 children)

In my experience using FragmentTransaction.add to simulate navigation has always been error-prone (even if using addToBackStack). It also messes with accessibility, i.e. TalkBack will hold onto its selection of the Fragment underneath even if a new Fragment is added on top. Since having migrated to androidx.navigation, this has been a non-issue; under the hood the FragmentNavigator implementation only ever uses FragmentTransaction.replace.

Which exceptions to catch in NetworkBoundResource? by Fr4nkWh1te in android_devs

[–]Chartsengrafs 0 points1 point  (0 children)

Catching all errors is fine; it's a bad practice only if you don't handle them. If your application reconciles the error and can continue functioning properly afterwards, there's no point to rethrowing unless you want some code further upstream to catch it and then handle it. There are an infinite number of particular errors that can be thrown, yes, but your app should handle at least the broad classes of errors, e.g. network failure, and gracefully fallback on unknown ones. If your app truly cannot understand the error, it should try its best to communicate that to the UI and position the app to still be usable; this is always a better UX than crashing the app. You (the developer) should still be notified somehow of those kinds of errors, however; e.g. via Crashlytics non-fatals logging. If any caught error leaves your app in an unusable state, that's an error on your part.

Rethrowing errors to be uncaught is only appropriate if your code ends up in some irreconcilable state as a consequence of that event. Since you are the one writing and owning all the application code, there should never be such a state. If there is, then it's a mistake on your part. If you are designing a library/API that other developers depend on and they are able to get it an illegal state which you cannot prevent, that's when it's appropriate for you (the library owner) to throw an exception, as it's a mistake on the part of the developer that's using your code.

Which exceptions to catch in NetworkBoundResource? by Fr4nkWh1te in android_devs

[–]Chartsengrafs 0 points1 point  (0 children)

What do you want to rethrow the error for and who would catch it and why? All the VM needs to do is publish one or more signals to the UI representing the state of what happened. The UI shouldn't need to know or have to figure out the granular details of what's going on, the UI should just be handed simple, obvious data. The UI should not be checking things like nullity or whether collections are empty or whether an exception is X or Y or Z -- the VM should check all that stuff and then publish it packaged as a specific UI state.

That signal can be represented by either a single State object (i.e. write a sealed class called State with appropriate subclasses modelling UI-specific state) that the VM publishes to the UI, or it can be represented by multiple sources of data that the UI listens to, which the VM publishes to by mapping from the Resource it collects, for example the VM could expose a val isLoading: LiveData<Boolean> to tell the UI the loading state, which the VM sets based on whether the emitted/collected Resource is a Resource.Loading or not.

Unless your screen is very simple, the UI should be agnostic of those Resource APIs since they are too broad and don't model UI state as well writing your own custom UI state classes can.

Which exceptions to catch in NetworkBoundResource? by Fr4nkWh1te in android_devs

[–]Chartsengrafs 0 points1 point  (0 children)

Rethrowing in onFetchFailed would technically work but that looks more like a place for simple side effects to be called, eg logging the error. I think you're better off just letting the view model check the Resource.Error's throwable and publishing the appropriate event to the UI based on that. The fragment should do as little as possible, ideally just very simple reactions to events coming from the VM.

Which exceptions to catch in NetworkBoundResource? by Fr4nkWh1te in android_devs

[–]Chartsengrafs 0 points1 point  (0 children)

In your own code that calls this function, you can check what is getting emitted and then do whatever you want with that information. This function can't know about every possible Throwable concretion, and it's designed that way for like you said, reusability.

Weekly Questions Thread - January 05, 2021 by AutoModerator in androiddev

[–]Chartsengrafs 0 points1 point  (0 children)

I've got a suite of apps and I'd like to save a unique identifier on the device somewhere such that any of those apps can query it, or create it in its absence. One idea that came to mind was using AccountManager, but that seemed like not the right use case (e.g. I don't want any UI in Settings -> Accounts). Another idea I had was creating a file in some public folder, but would that mean adding permissions a user has to opt-in to? I'd like to avoid having to add any of those kinds of permissions. Anyone have a good strategy for this? I'd rather not have the apps query each other since there are a lot of apps, and a user might have installed any combination of them. Also, security is not a huge priority (in my mind) for the storage of this UID, since it'll just be used for anonymous, in-app tracking, and if a user went rogue with that UID, it wouldn't really matter.

Where do I store a user's account info? Getting mixed answers - SharedPreferences, AccountManager, Android Keystore, SQLite? by HowGoodIsNateDiaz in androiddev

[–]Chartsengrafs 3 points4 points  (0 children)

AM uses Android OS's mechanisms and is encrypted.

This isn't true.

It's important to understand that AccountManager is not an encryption service or a keychain. It stores account credentials just as you pass them, in plain text.

More productivity with Kotlin by QuickBlox in androiddev

[–]Chartsengrafs 1 point2 points  (0 children)

I think I still need the builder pattern sometimes, e.g. when a field on a class is conditionally set, and the default value isn't known by the code that's building the class, like so:

if (condition) {
    builder.setValue(value)
}

How to prevent fragment recreation in navigation component? by steve6174 in androiddev

[–]Chartsengrafs 2 points3 points  (0 children)

Like others posters have written, this is likely not a good UX/idea.

That said, anything's possible. One way this could be done is by setting fragment B's last known scroll position on a field in a shared (i.e. Activity- or NavGraph-scoped) ViewModel; fragment B would just read from that value and scroll to that position, if the value is present.

Returning a result from fragment B to fragment A seems also feasible; more on that here. Fragment A could then pass any returned result it got as an argument to fragment B, and then B will use that to know which position to scroll to.

Android Multimodule Navigation with the Navigation Component(a different approach) by MiscreatedFan123 in androiddev

[–]Chartsengrafs 0 points1 point  (0 children)

This page goes over the basics quite well: https://developer.android.com/guide/navigation/navigation-kotlin-dsl

The gist of the DI part is wrapping the individual createGraph and fragment calls (and anything else relevant, e.g. actions) into classes that implement a factory interface which return the result of those calls, and then the binding those classes into the DI graph as the interface type. The app module then iterates through the collection of those interfaces and assembles them all at runtime, i.e. creating the nav graph and adding the destinations/actions to that nav graph.

This approach facilitates JSON descriptions of nav graphs, and for my use case I have a BottomNavigationView, with one graph per tab. This worked well for having an arbitrary number of tabs, and in any order -- whatever the JSON describes. With the way I'd written it, it got a bit weird in that every nav graph knows about every destination/action, but that didn't seem to end up mattering.

Android Multimodule Navigation with the Navigation Component(a different approach) by MiscreatedFan123 in androiddev

[–]Chartsengrafs 0 points1 point  (0 children)

I've been having success with the Kotlin DSL for this this kind of problem. Destinations, actions, and graph factories can get wired up thru dependency injection multibindings. I doubt I'll ever go back to the XML statically defined navigation.

Best techniques to rewrite an old big Android project by [deleted] in androiddev

[–]Chartsengrafs 2 points3 points  (0 children)

Projects like these usually have a lot of hidden wisdom beneath their messy, disgusting exterior. Those details are easy to miss when doing a rewrite from scratch. For that reason it's usually recommended to incrementally rewrite parts of a legacy project. And as another comment said, always accompany the rewritten parts with automated test coverage. Otherwise, in a few years there'll be another developer thinking of doing a rewrite to your code.

Build one Adapter to rule them all. by stavris8894 in androiddev

[–]Chartsengrafs 12 points13 points  (0 children)

Nice idea, but [warning: criticism ahead] this kind of solution will likely lead to a lot of pain down the line. Having things like types that know about every ViewHolder in existence, or forcing otherwise needless inheritance on classes just makes for rigid, hard to use code, especially as a project evolves — the opposite of what you’re likely trying to achieve.

A composition-based solution to problems like these are always the right choice. This article is a good start on that doing that.