Does creating an activity using the .withIntent() not work in Robolectric 2? I'm doing the following
activity = Robolectric.buildActivity(MyActivity.class)
.create()
.withIntent(intent)
.get();
And i'm getting a NullPointerException when doing the following in the onCreate() of my activity.
Bundle bundle = getIntent().getExtras();
I can code a null check in my onCreate() and set the intent by doing the following but it seems redundant to set the intent and call the onCreate() method again when Robolectric already does that when creating the Activity instance. This seems like an unnecessary work around.
Robolectric.shadowOf(activity).setIntent(intent);
activity.onCreate(null);
This is a case where a fluent-style API kinds of leads you down the wrong path...
You want to:
activity = Robolectric.buildActivity(MyActivity.class)
.withIntent(intent)
.create()
.get();
so that the intent is provided to the builder before it calls onCreate().
For newer versions of Robolectric use Robolectric.buildActivity(Class, Intent).
I figured out my problem. I wasn't instantiating the Intent properly. I was instantiating it with the no-arg constructor when i needed to give a Context and the class of the Activity it was being sent to
EDIT: It was fixed in version 2.2.
I tackled with the same issue. It was reported but no fix has been provided yet. For now, I manage to hack it using Activity's setter before calling onCreate(), taking advantage from the fact that its lifecycle has not yet started:
Intent intent = new Intent();
MainActivity mainActivity = Robolectric.buildActivity(MainActivity.class)
.create()
.get();
mainActivity.setIntent(intent);
mainActivity.onCreate(null);
Related
My team is writing a service that leverages the retryable topics mechanism offered by Spring Kafka (version 2.8.2). Here is a subset of the configuration:
#Bean
public ConsumerFactory<String, UploadMessage> consumerFactory() {
return new DefaultKafkaConsumerFactory<>(
this.springProperties.buildConsumerProperties(),
new StringDeserializer(),
new ErrorHandlingDeserializer<>(new KafkaMessageDeserializer()));
}
#Bean
public RetryTopicConfiguration retryTopicConfiguration(KafkaTemplate<String, Object> kafkaTemplate) {
final var retry = this.applicationProperties.retry();
return RetryTopicConfigurationBuilder.newInstance()
.doNotAutoCreateRetryTopics()
.suffixTopicsWithIndexValues()
.maxAttempts(retry.attempts())
.exponentialBackoff(retry.initialDelay(), retry.multiplier(), retry.maxDelay())
.dltHandlerMethod(DeadLetterTopicProcessor.ENDPOINT_HANDLER_METHOD)
.create(kafkaTemplate);
}
KafkaMessageDeserializer is a custom deserialiser that decodes protobuf-encoded messages and may throw a SerializationException in case of a failure. This exception is correctly captured and transformed into a DeserializationException by Spring Kafka. What I find a bit confusing is that the intercepted poison pill message then hits all of the retry topics before eventually reaching the dead letter one. Obviously it fails with exactly the same error at every step.
I know that RetryTopicConfigurationBuilder::notRetryOn may be used to skip the retry attempts for particular exception types, but what if I want to use exactly the same list of exceptions as in ExceptionClassifier::configureDefaultClassifier? Is there a way to programmatically access this information without basically duplicating the code?
That is a good suggestion; it probably should be the default behavior (or at least optionally).
Please open a feature request on GitHub.
There is a, somewhat, related discussion here: https://github.com/spring-projects/spring-kafka/discussions/2101
I read spring-kafka/kafka documentation back and forth, and still cannot find a way, how to do proper transactional behavior with error recovering. I believe this is not trivial question, so please read until end. I believe whole this question revolves around finding way how to reposition over failing record or how to ack in error handler. But mabye there are better ways, I don't know.
So records are flowing in, and some of them are invalid. What I would like to have as a minimal solution is(in which I will then fix sevaral problems you probably see as well):
1) we cannot afford the luxury of stopping the production in case of some trivial mishap, like one or few invalid records. Thus if there is invalid record in kafka topic, I would like to log it, or resend it to different queue, but then proceed with processing following records.
2) there are permanent and temporary failures. Permanent failure is record unable to deserialize, record failing data validation. In this case, I'd like to skip the invalid record, as discussed in 1). Temporary failure might be some specific exception or state, like for example database connection errors, network issues etc. In this case, we do not want to skip failing record, we want to retry, after some delay.
Subject of this question is ONLY implementing skip/don't skip behavior.
Lets say, that this is our starting point:
private Map<String, Object> createKafkaConsumerFactoryProperties(String bootstrapServers, String groupId, Class<?> valueDeserializerClass) {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, valueDeserializerClass);
props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
return props;
}
#Bean(name="SomeFactory")
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory(
#Value("${…}") String bootstrapServers,
#Value("${…}") String groupId) {
ConcurrentKafkaListenerContainerFactory<String, String> factory =
new ConcurrentKafkaListenerContainerFactory<>();
ConsumerFactory<String, String> consumerFactory = new DefaultKafkaConsumerFactory<>(
createKafkaConsumerFactoryProperties(bootstrapServers, groupId, AvroDeserializer.class),
new StringDeserializer(),
new AvroDeserializer(SomeClass.class));
factory.setConsumerFactory(consumerFactory);
// factory.setConcurrency(2);
// factory.setBatchListener(true);
return factory;
}
and we have listener like:
#KafkaListener(topics = "${…}", containerFactory = "SomeFactory")
public void receive(#Valid List<SomeClass> messageList) {/*logic*/}
Now how this behave if I understand correctly:
when listener gets message, ~when we reach inside of receive method, the kafka message will be already acked, and if receive method throw an exception, the next poll will return following record. Because ack happened, and we do not have error handler defined, thus logging error handler will kick in. This is not necessarily what we want. We can use SeekToCurrentErrorHandler to reprocess the message. Or one can specify TransactionManager, and if exception 'leaks' from listener, repositioning will also happen. If someone know performance comparison of these two approaches, please tell me.
when message cannot be deserialized, deserializer will fail, message will not be acked and same record will be polled again. This is some sort of "poison packet" since kafka will spin on this message indefinitelly. We do have retry.backoff.ms to at least slow it down, but I can't see any max number retries or something. So the best thing we can do is to stop/pause container in this situation. Which is way to harsh. Btw. I'm new to kafka/spring-kafka, I did not see anywhere mention, how to manually reposition offset from outside of an application, meaning OK, listener is down, but now what? Another solution would be not to fail deserializer, and return something. But what?? KafkaNull, great, but then our listener will fail because SomeClass ClassCastException. We can send some artificial value of SomeClass, which is again horrible, because this is not a data what we actually get. Also this is architectonically incorrect.
or we can use repositioning error handler, which would be great, well if we know how to do that. I need to seek to next record. But while documentation says, that ErrorHandler should communicate which record caused the failure, it seems that it fails to do so. So even in non-batch listener I have list of records(1 failed + bunch of unprocessed), and have no idea where set offset to.
So what is the solution to this madness?
Well the best I can come up with right now is pretty ugly: do not fail in deserializer (bad), do not accept specific type in listener (bad), filter out KafkaNulls manually (bad) and finally trigger bean validation manually (bad). Is there a better way? Thanks for examplantion, I'd be grateful for every hint or direction given how to achieve this.
See the documentation for the upcoming 2.2 release (due tomorrow).
The DefaultAfterRollbackProcessor (when using transactions) and SeekToCurrentErrorHandler (when not using transactions) can now recover (skip) records that keep failing, and will do so after 10 failures, by default. They can be configured to publish failed records to a dead-letter topic.
Also see the Error Handling Deserializer which catches deserialization problems and passes them to the container so they can be sent to the error handler.
Our app is crashing on Android O due to the new background execution limits. We are on Firebase version 10.2.1, which is the one that added Android O support.
Seems like an issue with Firebase? Or is there some change needed to support this on our end?
java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.firebase.INSTANCE_ID_EVENT pkg=my.package.name cmp=my.package.name/my.package.name.MyFcmIdService (has extras) }: app is in background uid UidRecord{30558fa u0a327 RCVR idle procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1505)
at android.app.ContextImpl.startService(ContextImpl.java:1461)
at android.content.ContextWrapper.startService(ContextWrapper.java:644)
at android.support.v4.content.WakefulBroadcastReceiver.startWakefulService(WakefulBroadcastReceiver.java:99)
at com.google.firebase.iid.zzg.b(zzg.java:9)
at com.google.firebase.iid.zzg.a(zzg.java:72)
at com.google.firebase.iid.zzg.a(zzg.java:2)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:23)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:34)
at com.google.firebase.iid.FirebaseInstanceId.<init>(FirebaseInstanceId.java:31)
at com.google.firebase.iid.FirebaseInstanceId.getInstance(FirebaseInstanceId.java:47)
at com.google.firebase.iid.FirebaseInstanceId.a(FirebaseInstanceId.java:4)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:19)
at com.google.firebase.iid.FirebaseInstanceIdService.b(FirebaseInstanceIdService.java:35)
at com.google.firebase.iid.zzb$zza$1.run(zzb.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Update Upgrading to 11.4.2 resolves this issue.
#KaMyLL is right. I had the same issue with our app and could solve it by replacing the IntentService (which we have started within onTokenRefresh()) with an JobIntentService.
Because I found the JobScheduler and JobIntentService docs a bit confusing, I would like to some everything up with some code snippets. I hope this makes everything clear to everyone having this issue.
What is causing this issue?
Due to the new Background Execution Limits of Android 8, you should not start background services anymore when the app could be in background:
While an app is in the foreground, it can create and run both foreground and background services freely. When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods.
And also:
In many cases, your app can replace background services with JobScheduler jobs.
So for Android 7.x and below, using startService() when the app is in background is (as far as I know) no problem. But in Android 8, this results in a crash. In consequence, you should use a JobScheduler now. The behavioral difference between JobScheduler and an IntentService is that an IntentService is executed immediately. On the other hand, a job enqueued to a JobScheduler is not guaranteed to be executed immediately. The Android OS will determine when there is a good point of time to do so in order to be more energy efficient. So there might be a delay. And I have no idea so far how long this could take.
So one solution could be to check the OS version and branch your code using if-else. Fortunately, the support library helps us to solve this in a more elegant way without duplicating any code: JobIntentService, which basically does this for you under the hood.
How to reproduce the issue?
The first quote above states that the app still "has a window of several minutes in which it is still allowed to create and use services.", so in order to reproduce and debug the issue (with the example of onTokenRefresh() in Firebase), you could set a breakpoint before your start your service with startService(). Close the app and wait there for 5-10 minutes. Continue the execution and you will see the IllegalStateException from this question.
Being able to reproduce the issue as fundamental to make sure that our fixes really solve the problem.
How to migrate my IntenService to JobIntentService?
I use FirebaseInstanceIdService.onTokenRefresh() as an example:
a) Add the BIND_JOB_SERVICE permission to your service:
<service android:name=".fcm.FcmRegistrationJobIntentService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"/>
b) Instead of extending from IntentService, simply extend from android.support.v4.app.JobIntentService, rename the onHandleIntent(Intent) method to onHandleWork(Intent), and add a enqueueWork(Context, Intent) convenient function:
public class FcmRegistrationJobIntentService extends JobIntentService
{
// Unique job ID for this service.
static final int JOB_ID = 42;
// Convenience method for enqueuing work in to this service.
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, FcmRegistrationJobIntentService.class, JOB_ID, work);
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
// the code from IntentService.onHandleIntent() ...
}
}
c) Start the job using the enqueueWork() convenient function:
public class ComfyFirebaseInstanceIdService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
Intent intent = new Intent(this, FcmRegistrationJobIntentService.class);
// startService(intent);
FcmRegistrationJobIntentService.enqueueWork(this, intent);
}
}
I hope this example is helpful. At least after following these steps, I was not able to reproduce the issue on my Android 8 device anymore, and it continues to work an my Android 7 device.
Update
as FirebaseInstanceIdService deprecated we should remove this from the code, and use onNewToken from FirebaseMessagingService instead.
I've done some research about it and the best option is to transform IntentService into JobIntentService available in app compat library. It would behave like IntentService on all pre-Oreo devices. On Android 8 and above it will enqueue job to android system JobScheduler. This job by default have set deadline parameter to 0, so theoretically it should fire as fast as possible.
as of today (26/10/2018), FirebaseInstanceIDServie isdeprecated, try this to fix the above issue link
To start, let me say that I have read several questions here about SingleInstance, but still cannot find a direct answer that helps me. That said, I apologize if I missed anything.
Here's my question:
I am building a Xamarin Forms app for iOS and Android. I have a single AppInitializer class in a PCL where I register all of my interface dependencies using Autofac. I then assign the Container from the builder as a static property on the app class. The problem I encounter is that while I'm registering everything with .SingleInstance(), I'm not actually getting a single instance.
Init Logic Example:
var builder = new ContainerBuilder();
builder.RegisterType<ErrorHandler>().SingleInstance().As<IErrorHandler>();
…
builder.RegisterType<MemberViewModel>().SingleInstance().As<IMemberViewModel>();
…
AppContainer.Current = builder.Build();
I am letting Autofac handle resolving interfaces in my constructors. For example:
public MemberViewModel(ISettingsViewModel settings, IErrorHandler errorHandler, …) : base(settings, errorHandler){…}
I then use said model on a page as below:
Example page usage:
public ProfilePage()
{
InitializeComponent();
var displayModel = Model.CurrentMember;
…
}
…
**public IMemberViewModel Model =>
AppContainer.Current.Resolve<IMemberViewModel>();**
In this example I set Model.CurrentMember's properties immediately before arriving on this page. I've set breakpoints and know for a fact this is happening. However, when I resolve the instance of the model, the properties on CurrentMember are null.
Am I doing something wrong here or have I encountered a bug?
-Edit-
Made it clear that I'm using Autofac.
-Edit 2-
Adding more detail.
My implementation of the IMemberViewModel class has various properties on it, including an observable object called current member. It is declared as below:
public class MemberViewModel : ViewModelBase, IMemberViewModel
{
…
(see constructor above)
…
public MemberDisplay CurrentMember =>
m_CurrentMember ?? (m_CurrentMember = new MemberDisplay())
On the implementation of IMemberViewModel I have a method that sets the various properties on CurrentMember.
The order of operations is this:
The end user taps an image for a member. This fires a command on the (theoretically) singleton instance of the IMemberViewModel implementation. This command executes an async task that awaits an async call to the API to load the data for that member. After that data is loaded and the properties set on CurrentMember, the app navigates to the profile screen. The profile screen resolves IMemberViewModel (per above).
Expected Behavior:
The properties on CurrentMember from the resolved instance of IMemberViewModel are set to the values that have just been set from the load data method. This expectation arises from assuming that there is a single instance of IMemberViewModel.
Actual Behavior:
The CurrentMember's properties are at their default values, i.e. string.Empty, 0, null, etc.
The odd thing here is that this doesn't happen to every model. I have a message model that I am resolving in the same manner on the same screen and it seems to be fine.
This issue turned out to be caused by the way we were going about initializing everything. For posterity's sake, I will give a brief breakdown of what was happening and what I did to prevent it.
Previous App Flow:
App opens & constructor is called. This calls into the initialization routine above.
User logs in.
First instance of IMemberViewModel resolved using static container.
A message pops up asking the user for Push Notifications Permissions
When this happens, the app OnSleep is called (iOS)
After the user selects an answer, OnResume is called.
OnResume calls initialization routine
New container created.
Call to load data happens on old container, new pages reference new container.
Issue arises as described above.
Correction to the flow:
First, from what I can tell the init calls do not need to be made on resume and/or start if made in the app constructor. If the app is "killed" because other apps need the memory space, a fresh version of the app will be created on next launch (see the Android Activity Lifecycle and the iOS App Lifecycle).
Second, because I'm paranoid and because it can't hurt, in the app init routine I am now checking to determine whether the container exists and whether the interface is already registered.
public static void Init(ISetup setup)
{
if (Container != null && IsModelRegistered()) return;
RegisterDependencies(setup);
…
}
private static bool IsModelRegistered()
{
return Container.IsRegistered<IMemberViewModel>();
}
I'm trying to use .numChildren() in AngularFire, but not sure I'm doing it correctly.
function getServiceProviders(serviceId) {
var serviceProviders = ref.child('services').child(serviceId).child('providers');
return serviceProviders.numChildren();
}
I'm getting the following error:
TypeError: e.numChildren is not a function
Not sure if this is due to me using Browserify, or I'm just trying to access numChildren incorrectly.
Any help is appreciated. Thanks in advance!
Your code snippet doesn't use AngularFire, it only uses the Firebase JavaScript SDK. Although your project undoubtedly uses AngularFire, it doesn't relate to this question.
When you look at the documentation for the .child() method in the Firebase JavaScript SDK, you'll see that it returns a Firebase reference. And if you look further into that class, you should notice that it doesn't have a numChildren method.
numChildren is only available on a DataSnapshot object, which you get in any of the on(... event handlers.
So:
serviceProviders.on('value', function(snapshot) {
console.log(snapshot.numChildren());
}
Since the snapshot will be loaded asynchronously, you cannot return the number of children from getServiceProviders. See my answer to this question for a broader explanation of that: Asynchronous access to an array in Firebase