Get problem while calling a method of a class from fragment - android-studio

i have 2 classes here:
#1 AlarmReceiver
class AlarmReceiver: BroadcastReceiver() {
...
fun setRepeatingAlarm(context: Context) {} //the method that i want to call
}
#2 SettingFragment (which is attached to SettingActivity)
SettingFragment(): PreferencefragmentCompat() {
private lateinit var reminder: String
private lateinit var language: String
private lateinit var alarmReceiver: AlarmReceiver
private lateinit var langPreference: Preference
private lateinit var reminderPreference: SwitchPreference
override fun onCreatePreferences(savedInstanceState: Bundle?, s: String?) {
addPreferencesFromResource(R.xml.settings)
init()
}
private fun init() {
reminder = resources.getString(R.string.key_reminder)
language = resources.getString(R.string.key_language)
alarmReceiver = AlarmReceiver()
langPreference = findPreference<Preference> (language) as Preference
reminderPreference = findPreference<SwitchPreference> (reminder) as SwitchPreference
}
private fun reminderSetting() {
// the method where i place the that method
}
i confused on how to define the context param from that method i called.
i tried to code this:
alarmReceiver.setRepeatingAlarm(activity.applicationContext)
but i got error "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type FragmentActivity?"
how to solve this problem? thank you :)

The activity property is actually calling the Fragment's getActivity() method, which can return null - it's possible for the fragment to be in a state where it's created, but isn't actually attached to an Activity yet, so in that case this method will return null.
You're chaining another call onto the result, so because it could be null, you're either calling Activity.applicationContext (good!) or null.applicationContext (very bad!). So the warning is telling you you're doing this, and you either need to handle that potential null safely (with the ?. call) or explicitly say "this is definitely not going to be null when I call it" (with the !!. call)
You should read up on Kotlin's null safety handling because it's important, and it's there to make your life a whole lot easier in the end. But in this case (and most cases) you shouldn't use !! because there are some situations where it won't be true, the property will be null, and then your app crashes
Here's the safe way to handle it:
activity?.let { alarmReceiver.setRepeatingAlarm(it.applicationContext) }
there's a whole bunch of ways you could write that, but that's the simplest to understand - if activity is not null, it runs the let block, passing in the non-null activity as a variable called it. Then you can just run your code the same way because now you know it's not null! If activity is null, that let block won't run at all. Your alarm won't be set, but it won't be set if your app crashes either - this way you can handle it, or if this is a rare case where it shouldn't ever happen, you can just do nothing - it's definitely not going to crash with a NullPointerException at least!

Related

Replace a Thread -- that has state variable -- with a Coroutine

To restate the title, I'm wondering if there is a way to convert the MyThread class below to a Kotlin Coroutine.
If you look closely, you will notice that the MyThread class has a property variable called someObject that can be modified from inside the both the run and the cancel methods. In this case SomeObject is completely encapsulated inside MyThread and I want to keep it that way. Is there a way to convert MyThread to a coroutine or do I already have the most elegant version of the code?
class MyCancellable: Thread(){
val someObject= SomeObject()
override fun run() {
super.run()
while(someObject.keepGoing){
someObject.value++
}
}
fun cancel(){
someObject.keepGoing=false
}
}
A reusable coroutine is a suspend function where the only parameter is CoroutineScope, so something roughly equivalent to what you have is:
fun CoroutineScope.cancellableCounter() = withContext(Dispatchers.Default) {
val someObject = SomeObject()
while (someObject.keepRunning) {
yield()
someObject.value++
}
}
The function can be called from inside another coroutine, or it can be passed to async or launch, such as myScope.launch(::cancellableCounter). The returned Job can be cancelled by calling cancel() on it.
But as mentioned in the comments, there may be a better way to design it depending on how SomeObject is supposed to be used.
Edit: Maybe for the ServerSocket you'd need to do something like this. I haven't tested it, so not totally sure. But I don't think you want to directly call accept() in a coroutine because it blocks for potentially a long time and does not cooperate with cancellation. So I'm suggesting you still need a dedicated thread. suspendCancellableCoroutine can bridge this to a suspend function.
suspend fun awaitSomeSocket(): Socket = suspendCancellableCoroutine { continuation ->
val socket: ServerSocket = generateSocket()
continuation.invokeOnCancellation { socket.close() }
thread {
runCatching {
val result = socket.use(ServerSocket::accept)
continuation.resume(result)
}
}
}
I think you want a class that can start its own coroutine? That seems like the equivalent, something like:
class MyCancellable(private val scope: CoroutineScope) {
private var job: Job? = null
val someObject = SomeObject()
fun run() {
if (job != null) return
job = scope.launch {
while(someObject.keepGoing) {
someObject.value++
}
}
}
fun cancel() {
someObject.keepGoing = false
}
}
Typically you'd do job.cancel() instead, and check isActive in the while loop - I don't think it matters here, but it might be worth doing it "properly" (and it is technically different to someObject.keepGoing going false for some other reason). And if you're doing that, maybe TenFour04's suggestion is better, since the only reason you need a class/object is so you can put externally visible run and cancel functions in it. If the coroutine just runs anyway, and you call cancel on the Job it returns, it's all good!

Achilles Cassandra - Getting result of conditional update

How to get response when performing a conditional update/delete from Achilles?
I tried using a custom ResultListener, but it doesn't always work correctly.
public class ResultListener implements LWTResultListener {
private boolean applied;
#Override
public void onSuccess() {
applied = true;
}
#Override
public void onError(LWTResult lwtResult) {
applied = false;
}
public boolean isApplied() {
return applied;
}
}
From my caller class, I call isApplied() but it seems that the onSuccess method is called asynchronously. The caller class doesn't see the updated value of applied field.
That's not the problem with Cassandra/Achilles itself, but general problem with async programming - callback could be called at any point of time...
For your code there are 2 things:
First, you need to understand if the callback was called or not - you may add another boolean variable that will be set by both onSuccess & onError to indicate that callback was called already. And your code need to check this variable before calling isApplied;
Second - you need to guarantee that the change is visible by other parts of the code. You can add the volatile keyword to the declaration of applied variable (and to the declaration of variable described above). This keyword will indicate that data could be changed by some other thread, and Java will enforce that data is always read from memory. Following article describes this in quite good details.

Xamarin Forms - CustomObject, XAML Initialization, Setter not called, DependencyProperty, I'm lost?

I have a problem and I searched a solution about it. Lucky, I red lot of post about it but I'm lost with the explaination I found. The initale problem is coming from a personal project about the polyline of the Xamarin.Forms.Map where the initialization is realized by a binding from the XAML part..
Let me be clear by an example :
I have an object CustomMap.cs which inherit from Xamarin.Forms.Map (This file is in the PCL part -> CustomControl/CustomMap.cs)
public class CustomMap : Map, INotifyPropertyChanged
{
public static readonly BindableProperty PolylineAddressPointsProperty =
BindableProperty.Create(nameof(PolylineAddressPoints), typeof(List<string>), typeof(CustomMap), null);
public List<string> PolylineAddressPoints
{
get { return (List<string>)GetValue(PolylineAddressPointsProperty); }
set
{
SetValue(PolylineAddressPointsProperty, value);
this.GeneratePolylineCoordinatesInner();
}
}
// ...
}
So the Xaml part of the page, where the control is called, looks like that:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:control="clr-namespace:MapPolylineProject.CustomControl;assembly=MapPolylineProject"
x:Class="MapPolylineProject.Page.MainPage">
<ContentPage.Content>
<control:CustomMap x:Name="MapTest" PolylineAddressPoints="{Binding AddressPointList}"
VerticalOptions="Fill" HorizontalOptions="Fill"/>
</ContentPage.Content>
</ContentPage>
The Csharp part:
public partial class MainPage : ContentPage
{
public List<string> AddressPointList { get; set; }
public MainPage()
{
base.BindingContext = this;
AddressPointList = new List<string>()
{
"72230 Ruaudin, France",
"72100 Le Mans, France",
"77500 Chelles, France"
};
InitializeComponent();
//MapTest.PolylineAddressPoints = AddressPointList;
}
}
So, everything is fine if I edit the PolylineAddressPoints from the object instance (if the commented part isnt' commented..), but if I init the value from the XAML (from the InitializeComponent();), it doesn't work, the SetValue, in the Set {}, isn't called..
I then searched on the web about it and get something about the Dependency Properties? or something like that. So I tried some solutions but, from WPF, so some methods, such as DependencyProperty.Register();. So yeah, I can't find the way to solve my problem..
I also though about something, if DependencyProperty.Register(); would exists in Xamarin.Forms, then it means I would have to do it for each values? Because, if every value has to be set by a XAML binding logic, it would not work, I would have to register every value, doesn't it?
I'm sorry if I'm not clear, but I'm so lost about this problem.. Please, do not hesitate to ask for more details, thank in advance !
I finaly got a solution just over here => Ignore the Binding initialization
Copy paste from Stackoverflow. This following answer was given by Stephane Delcroix, thank to him !
There are multiple questions in this:
Why is the property setter never called when using Xaml ?
Am I properly defining my BindableProperty ?
Why is my binding failing ?
Let me answer them in a different order.
Am I properly defining my BindableProperty ?
The BindableProperty declaration is right, but could be improved by using an IList<string>:
public static readonly BindableProperty PolylineAddressPointsProperty =
BindableProperty.Create(nameof(PolylineAddressPoints), typeof(IList<string>), typeof(CustomMap), null);
but the property accessor is wrong, and should only contains this:
public IList<string> PolylineAddressPoints
{
get { return (IList<string>)GetValue(PolylineAddressPointsProperty); }
set { SetValue(PolylineAddressPointsProperty, value); }
}
I'll tell you why while answering the next question. But you want to invoke a method when the property has changed. In order to do that, you have to reference a propertyChanged delegate to CreateBindableProperty, like this:
public static readonly BindableProperty PolylineAddressPointsProperty =
BindableProperty.Create(nameof(PolylineAddressPoints), typeof(IList<string>), typeof(CustomMap), null,
propertyChanged: OnPolyLineAddressPointsPropertyChanged);
And you have to declare that method too:
static void OnPolyLineAddressPointsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
((CustomMap)bindable).OnPolyLineAddressPointsPropertyChanged((IList<string>)oldValue, (IList<string>)newValue);
}
void OnPolyLineAddressPointsPropertyChanged(IList<string> oldValue, IList<string> newValue)
{
GeneratePolylineCoordinatesInner();
}
Why is the property setter never called when using Xaml ?
The property, and the property accessors, are only meant to be invoked when accessing the property by code. C# code.
When setting a property with a BindablePrperty backing store from Xaml, the property accessors are bypassed and SetValue() is used directly.
When defining a Binding, both from code or from Xaml, property accessors are again bypassed and SetValue() is used when the property needs to be modified. And when SetValue() is invoked, the propertyChanged delegate is executed after the property has changed (to be complete here, propertyChanging is invoked before the property change).
You might wonder why bother defining the property if the bindable property is only used by xaml, or used in the context of Binding. Well, I said the property accessors weren't invoked, but they are used in the context of Xaml and XamlC:
a [TypeConverter] attribute can be defined on the property, and will be used
with XamlC on, the property signature can be used to infer, at compile time, the Type of the BindableProperty.
So it's a good habit to always declare property accessors for public BindableProperties. ALWAYS.
Why is my binding failing ?
As you're using CustomMap as bot View and ViewModel (I won't tell the Mvvm Police), doing this in your constructor should be enough:
BindingContext = this; //no need to prefix it with base.
As you're doing it already, your Binding should work once you've modified the BindableProperty declaration in the way I explained earlier.

Parameter specified as non-null is null when using Mokito anyObject() on Kotlin function

My code as below, refering to the solution in https://stackoverflow.com/a/30308199/3286489
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.*
class SimpleClassTest {
private fun <T> anyObject(): T {
Mockito.anyObject<T>()
return uninitialized()
}
private fun <T> uninitialized(): T = null as T
lateinit var simpleObject: SimpleClass
#Mock lateinit var injectedObject: InjectedClass
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
}
#Test
fun testSimpleFunction() {
simpleObject = SimpleClass(injectedObject)
verify(injectedObject).settingDependentObject(anyObject())
}
}
I still have the below error
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method my.package.InjectedClass.settingDependentObject, parameter dependentObject
Did I miss anything?
UPDATED
Below is the code tested (simplest form and working)
class SimpleClass(val injectedClass: InjectedClass) {
fun simpleFunction() {
injectedClass.settingDependentObject(DependentClass(Response.Builder().build()))
}
}
open class DependentClass(response: Response) {
}
open class InjectedClass() {
lateinit var dependentObject: DependentClass
fun settingDependentObject(dependentObject: DependentClass) {
this.dependentObject = dependentObject
}
}
By default Kotlin classes and members are final. Mockito cannot mock final classes or methods.
Thus when you write:
verify(injectedObject).settingDependentObject(anyObject())
the real implementation is called which requires non null argument.
To fix that either open your class and method or, even better, change SimpleClass to accept an interface as its constructor argument and mock the interface instead.
There is a project specifically to help deal with Kotlin "closed by default" in unit testing with Mockito. For JUNIT, you can use the kotlin-testrunner which is an easy way to make any Kotlin test automatically open up classes for testing as they are loaded by the classloader. Usage is simple, just add one annotation of #RunWith(KotlinTestRunner::class), for example:
#RunWith(KotlinTestRunner::class)
class MyKotlinTestclass {
#Test
fun test() {
...
}
}
This is thoroughly covered in the article Never say final: mocking Kotlin classes in unit tests
This covers your use case in an automatic way by allowing all classes to be mocked that otherwise would not be allowed.
I ran into the same issue with Mockito when using RETURNS_DEEP_STUBS. It seems like nulls are still returned for nested objects, even when using the kotlin-allopen plugin.
Please check out and comment on this issue on Mockito if you're having the same problem.
You can use this function instead
inline fun <reified T : Any> any(): T = Mockito.any(T::class.java) ?: T::class.java.newInstance()

Guice and RequestScoped behaviour in multiple threads

I am using Guice's RequestScoped and Provider in order to get instances of some classes during a user request. This works fine currently. Now I want to do some job in a background thread, using the same instances created during request.
However, when I call Provider.get(), guice returns an error:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot
access scoped object. Either we are not currently inside an HTTP Servlet
request, or you may have forgotten to apply
com.google.inject.servlet.GuiceFilter as a servlet
filter for this request.
afaik, this is due to the fact that Guice uses thread local variables in order to keep track of the current request instances, so it is not possible to call Provider.get() from a thread different from the thread that is handling the request.
How can I get the same instances inside new threads using Provider? It is possible to achieve this writing a custom scope?
I recently solved this exact problem. There are a few things you can do. First, read up on ServletScopes.continueRequest(), which wraps a callable so it will execute as if it is within the current request. However, that's not a complete solution because it won't forward #RequestScoped objects, only basic things like the HttpServletResponse. That's because #RequestScoped objects are not expected to be thread safe. You have some options:
If your entire #RequestScoped hierarchy is computable from just the HTTP response, you're done! You will get new instances of these objects in the other thread though.
You can use the code snippet below to explicitly forward all RequestScoped objects, with the caveat that they will all be eagerly instantiated.
Some of my #RequestScoped objects couldn't handle being eagerly instantiated because they only work for certain requests. I extended the below solution with my own scope, #ThreadSafeRequestScoped, and only forwarded those ones.
Code sample:
public class RequestScopePropagator {
private final Map<Key<?>, Provider<?>> requestScopedValues = new HashMap<>();
#Inject
RequestScopePropagator(Injector injector) {
for (Map.Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
Key<?> key = entry.getKey();
Binding<?> binding = entry.getValue();
// This is like Scopes.isSingleton() but we don't have to follow linked bindings
if (binding.acceptScopingVisitor(IS_REQUEST_SCOPED)) {
requestScopedValues.put(key, binding.getProvider());
}
}
}
private final BindingScopingVisitor<Boolean> IS_REQUEST_SCOPED = new BindingScopingVisitor<Boolean>() {
#Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == RequestScoped.class;
}
#Override
public Boolean visitScope(Scope scope) {
return scope == ServletScopes.REQUEST;
}
#Override
public Boolean visitNoScoping() {
return false;
}
#Override
public Boolean visitEagerSingleton() {
return false;
}
};
public <T> Callable<T> continueRequest(Callable<T> callable) {
Map<Key<?>, Object> seedMap = new HashMap<>();
for (Map.Entry<Key<?>, Provider<?>> entry : requestScopedValues.entrySet()) {
// This instantiates objects eagerly
seedMap.put(entry.getKey(), entry.getValue().get());
}
return ServletScopes.continueRequest(callable, seedMap);
}
}
I have faced the exact same problem but solved it in a different way. I use jOOQ in my projects and I have implemented transactions using a request scope object and an HTTP filter.
But then I created a background task which is spawned by the server in the middle of the night. And the injection is not working because there is no request scope.
Well. The solutions is simple: create a request scope manually. Of course there is no HTTP request going on but that's not the point (mostly). It is the concept of the request scope. So I just need a request scope that exists alongside my background task.
Guice has an easy way to create a request scope: ServletScope.scopeRequest.
public class MyBackgroundTask extends Thread {
#Override
public void run() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
doTask();
}
}
private void doTask() {
}
}
Oh, and you probably will need some injections. Be sure to use providers there, you want to delay it's creation until inside the created scope.
Better use ServletScopes.transferRequest(Callable) in Guice 4

Categories

Resources