hidroh / materialistic

A material-design Hacker News Android reader
https://play.google.com/store/apps/details?id=io.github.hidroh.materialistic
Apache License 2.0
2.3k stars 509 forks source link

App crashes due to network issue #1426

Open YYYSSSHHH opened 4 years ago

YYYSSSHHH commented 4 years ago

Environment Info: Materialistic: android:versionCode="79" android:versionName="3.3" Android OS: Version = 6.0.1

Description information: We find that mobile apps are prone to crashes due to a network issue, mainly because successful network API calls return unexpected or no data. And we found that when this app's network returned data is null or some fields are null (JSON format), a random value or the network request fails (status code is 404), is empty, the app has crashed.

crash information:

crashActivity=io.github.hidroh.materialistic.ListActivity

java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add onError handling. at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:112) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5539) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635) Caused by: rx.exceptions.OnErrorNotImplementedException: Primitive array can't take null values. at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:386) at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:383) at rx.internal.util.ActionSubscriber.onError(ActionSubscriber.java:44) at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:153) at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115) at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.checkTerminated(OperatorObserveOn.java:273) at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:216) at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:107) ... 7 more Caused by: java.lang.IllegalArgumentException: Primitive array can't take null values. at java.lang.reflect.Array.set(Array.java:406) at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:78) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25) at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:119) at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:218) at retrofit2.OkHttpCall.execute(OkHttpCall.java:180) at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:91) at io.github.hidroh.materialistic.data.HackerNewsClient.getStories(HackerNewsClient.java:111) at io.github.hidroh.materialistic.StoryListViewModel.lambda$getStories$0(StoryListViewModel.java:27) at io.github.hidroh.materialistic.-$$Lambda$StoryListViewModel$hfQuXTh6BF8mOaKgfYZTArlVyZ4.call(lambda) at rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:48) at rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:33) at rx.Observable.unsafeSubscribe(Observable.java:10256) at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.call(OperatorSubscribeOn.java:100) at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:230) at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818) rx.exceptions.OnErrorNotImplementedException: Primitive array can't take null values. at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:386) at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:383) at rx.internal.util.ActionSubscriber.onError(ActionSubscriber.java:44) at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:153) at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115) at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.checkTerminated(OperatorObserveOn.java:273) at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:216) at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:107) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5539) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635) Caused by: java.lang.IllegalArgumentException: Primitive array can't take null values. at java.lang.reflect.Array.set(Array.java:406) at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:78) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25) at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:119) at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:218) at retrofit2.OkHttpCall.execute(OkHttpCall.java:180) at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:91) at io.github.hidroh.materialistic.data.HackerNewsClient.getStories(HackerNewsClient.java:111) at io.github.hidroh.materialistic.StoryListViewModel.lambda$getStories$0(StoryListViewModel.java:27) at io.github.hidroh.materialistic.-$$Lambda$StoryListViewModel$hfQuXTh6BF8mOaKgfYZTArlVyZ4.call(lambda) at rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:48) at rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:33) at rx.Observable.unsafeSubscribe(Observable.java:10256) at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.call(OperatorSubscribeOn.java:100) at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:230) at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818) java.lang.IllegalArgumentException: Primitive array can't take null values. at java.lang.reflect.Array.set(Array.java:406) at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:78) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25) at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:119) at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:218) at retrofit2.OkHttpCall.execute(OkHttpCall.java:180) at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:91) at io.github.hidroh.materialistic.data.HackerNewsClient.getStories(HackerNewsClient.java:111) at io.github.hidroh.materialistic.StoryListViewModel.lambda$getStories$0(StoryListViewModel.java:27) at io.github.hidroh.materialistic.-$$Lambda$StoryListViewModel$hfQuXTh6BF8mOaKgfYZTArlVyZ4.call(lambda) at rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:48) at rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:33) at rx.Observable.unsafeSubscribe(Observable.java:10256) at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.call(OperatorSubscribeOn.java:100) at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:230) at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818)

Finally: The cause of the program crash may be that the network response data is not handled properly in the code, such as null or empty. If you have confirmed or fixed this problem, please give me a reply, thank you!

YYYSSSHHH commented 4 years ago

How do we test the APP? We use the fuzzing method to simulate the network response data. For example, when the app receives network API response data from the server or network, we will replace it with 404, null and random data.

A very simple example:

normal data :Value=”hello” -----fuzzing-----> simulated data :Value=null or network request fails(404、503) or Value=”heee”(random data) or Value=""(empty) , etc.