I can make calls without a hitch as long as there are no parameters. I know that as a beginner to app programming that this will be a ridiculously simple thing I missed or something overly complex, but here goes.
I have an interface inside a fragment and have the #Query in place like so:
interface RewardsApiService {
#GET("JSON/return-data.asp")
fun getCID(
#Query("cid") strCustomerID: String,
#Query("process") strProcess: String
)
fun getRewards(): retrofit2.Call<ResponseData<List<RewardsCards>>>
}
My question is this: Where do I define and assign those variables, strCustomerID and strProcess, so the interface can use them? strCustomerID is a SharedPreference.
The short answer is: You don't. Retrofit autogenerates the code based on what you have tagged with #GET, #Query, etc.
You should call it like this:
val call = service.getCID("foo", "bar")
However the generated call will url will look like this:
[your base url]/JSON/return-data.asp?cid=foo?process=bar
So make sure that url matches what you want.
Outside of the retrofit specific stuff there are some deeper architectural concerns. I'd have a look at https://developer.android.com/jetpack/guide and consider restructuring the project slightly.
For example, you dont want to be making API calls from within a fragment. This creates concerns around potentially doing IO on the main or UI thread and you are likely to end up trying to figure out crashes around that.
At a bare minimum I'd recommend splitting the interface out into a separate file and making sure your network call is done within a coroutine with IO scope.
Related
This might be a very silly question, but I am logging the methods that are triggered in my app as strings. When an issue is submitted, I would like to automatically input the text of the strings as parameters for methods. E.g:
For method:
fun assignPot(potType: PotType, ball: DomainBall, action: PotAction) {...}
I'd like to somehow call method:
assignPot(FOUL(2, BLUE(5), SWITCH))
From String:
"FOUL(2, BLUE(5), SWITCH)"
The only workaround I can think of is to split the string and create a when -> then function to get actual classes from strings, but I wondered if there's a more concise way for this.
This is not what you want to do. You should design your app in a way that prevents users from providing input similar to actual code.
However, you can achieve this. Complex parsings like this oftenly use regex-based approaches.
As you said, you should map your string part to class. If your PotType is enum, you can do something like
val re = Regex("[^A-Za-z\s]")
val reNumbers = Regex("[^0-9\s]")
// get classes
val classNames = originalString.replace(re, "").split(" ")
// get their constructor numerical arguments
val classArgs = originalString.replace(reNumbers, "").split(" ")
After that you can implement mapping with when expression. You probably will use some collection of Any type.
As you see, this sadly leads you to parsing code by code. Concise way to solve is to implement your own script compiler/interpreter and use it in your application :) That will later lead you to dealing with security breaches and so on.
If you are logging problematic method calls and want to repeat them immediately after issue is submitted, you probably want to programatically save the calls to lambdas and call them when you receive an issue log.
I have classes MainActivity and MyService. In service I connect with a server, but I also need to update some UI for which I would need Context from MainActivity. More precisely I need to use a layoutInflater and then update the views. Should this be done separately?
Example of one function
private suspend fun setStations(serverText: String) {
withContext(Main) {
for (i in (1..numStations(serverText)))
{
frame = ScrollView( ) //would need context here
layoutInflater.inflate(R.layout.frame_layout, frame)
.
.
.
Generally, you would want to separate your business logic and UI concerns as much as possible, to make the code more readable and testable. To do so, you can follow architectural patters such as MVP, MVVM or MVI, based on the need and complexity of your app.
Thus, in your case you can potentially have a callback setup in your activity, that is called when the service finishes executing its code.
For reference, here are a few great reads for this:
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
https://antonioleiva.com/clean-architecture-android/
Also, here's a sample project that uses MVVM (a pretty common architecture)
https://github.com/skydoves/Pokedex
Typically, such a relationship is organized by the architectural pattern (model view presenter). You should make requests to the server in the presenter and then refer to Activity. This might help you https://github.com/Arello-Mobile/Moxy
Recently at my company a debate started after reviewing a different approach for writing heavy duty classes.
A big Java class holding component specific logic (no standard OOP principles made sense) had to be rewritten in Kotlin. The solution provided was splitting the logic in categories and the categories into separate files with internal extension functions to the main class.
Example:
Main.kt
class BigClass {
// internal fields exposed to the extension functions in different files
// Some main logic here
}
BusinessLogic.kt
internal fun BigClass.handleBussinessCase() {
// Complex business logic handled here accessing the exposed internal fields from BigClass
}
What are your thoughts on this? I haven't seen it used anywhere maybe for a good reason, but the alternative of thousand lines classes seems worse.
You have to consider that an extension function is nothing more than a function with an implicit first parameter which is referenced with this.
So in your case you'd have something like:
internal fun handleBussinessCase(ref: BigClass)
which would translate to Java as:
static void handleBussinessCase(BigClass ref)
But this could be assumed to be a delegate pattern, which could be encapsulated much cleaner in Kotlin as well.
Since the properties have to be internal anyhow, you could just inject these as a data class into smaller use-cases. If you define an interface around these (which would make the properties public though), you could create a delegate pattern with it and still reference each property with this in your implementation.
Here are some thoughts on making extension functions for the class:
It will be a utility function that will operate with the object you're extending, it will not be an object function, meaning that it will have access to only public methods and properties;
If you're planning to use class that being extended in unit tests, these methods (extensions) will be harder to mock;
Most likely they wont behave as you expect when used with inherited objects.
Maybe I missed something, so please read more about extensions here.
I have created a custom view in android. one of the methods has a signature like this:
fun show(CategoryFilterModel model) {/*...*/}
and it works fine. and now i'd like to create a overloaded function which would look like this if i did it by adding it to the custom view class:
fun show(ShopFilterModel model) {/*...*/}
Notice the type is different so this is a method overload.
a thought came to me that i could instead use an extension in kotlin to add another method to the class.
so it would like something like this:
fun MyCustomView.show(ShopFilterModel: model){
}
is this advised or should i only add utility methods with extensions ? Are there any overheads ?
It’s not only for utilities, as you can read in this great answer, which lists pretty much all use cases.
Imho, if you have control over that class you want to extend with a method, there’s no problem to add the method directly to it as opposed to doing it with an extension method. Yet, technically you can consider doing this. Please be aware that calling such an extension function from Java isn’t very idiomatic because it will be compiled to a static function. If it’s ever going to be invoked from Java, I’d rather use ordinary methods when possible.
I am getting into Inversion of Control, specifically using Guice and RoboGuice for Android and I have a question.
I have a method call that returns a Resource (which is essentially an XML or JSON String).
public Resource getResource(){
// Some implementation details that call a web service and throw the result in a string...
String resource = ........
}
The Resource class is really just a wrapped String, so I figured it made sense to pass it in in the constructor, since it is an essential part of a Resource object.
public class Resource{
Resource(String theXMLorJSON){
...
}
}
A couple of questions:
How do I construct a new Resource in the getResource call? I would think that I want to use IoC and not call new in the method.
If another class takes a Resource in the constructor, how can I use the Guice container to construct it when I need a dynamic String at construction time? I just asked a similar question and believe there may be a specific way to handle this using Guice.
Thanks so much!
I think you may be misunderstanding something about dependency injection. You don't need to try to avoid using new in all cases... you primarily want to avoid using new to create anything that you might want to be able to mock out for testing, and it's generally best to allow the container to wire up any class that depends on such an object.
Your Resource class, though, sounds like a simple value object that you can easily create manually in any testing you do. It also doesn't depend on any kind of services... it just contains a String. So there's no reason to try to have the container create it.
The class containing the getResource() method, on the other hand, you definitely want the container to create, because you'd like to be able to use something that depends on that class in testing without having to actually call a web service.
Note that if you have a class with a constructor that takes both dependencies you want injected by the container and parameters that are only known at runtime, you need to create an intermediate factory of some kind with a method that only takes the runtime parameters. With Guice you can automatically create such a factory from an interface using the Assisted Inject (not sure if that works with RoboGuice, but it's easy to create such a factory implementation manually too).