First upon all this is not a duplicate question or have been answered on stackoverflow or xamarin forums. On xamarin forums this problem/question is still under discussion so i have posted it here.
So the problem with my app and also bunch of others which have been developed in Xamarin.Android reporting crashes (opt-in and opt-out) on Google's play console.
App actually not crashing. It just reporting automated crash reports to Google's play console.
Following is crash Stack Traces for Android 6.0 and 7.0 :
java.lang.RuntimeException:
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.reflect.InvocationTargetException:
at java.lang.reflect.Method.invoke(Native Method:0)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
(ZygoteInit.java:726)
In Android 5.1 and 5.0 :
java.lang.RuntimeException:
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Caused by: java.lang.reflect.InvocationTargetException:
at java.lang.reflect.Method.invoke(Native Method:0)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
For Android 4.2 and 4.4 :
java.lang.RuntimeException:
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:609)
at dalvik.system.NativeStart.main(Native Method:0)
Caused by: java.lang.reflect.InvocationTargetException:
at java.lang.reflect.Method.invokeNative(Native Method:0)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
Seems this exception occurring majorly in Android 6.0 and 7.0. Above is the only stack traces google play console provided for my and other developers app. There is not any detailed trace available yet.
For my app, crash reported whenever notification received on app. It impacting all of the app users at exact same time when they received notification.
Images of crash reports at the time of notification recieved
Following is the my FCM code :
MainActivity :
Task.Run(() =>
{
var instanceid = FirebaseInstanceId.Instance;
instanceid.DeleteInstanceId();
Log.Debug("TAG", "{0} {1}", instanceid.Token, instanceid.GetToken(this.GetString(Resource.String.gcm_defaultSenderId), Firebase.Messaging.FirebaseMessaging.InstanceIdScope));
});
Token Registration :
[Service]
[IntentFilter(new[] {
"com.google.firebase.INSTANCE_ID_EVENT"
})]
class MyFirebaseIIDService : FirebaseInstanceIdService
{
const string TAG = "MyFirebaseIIDService";
public override void OnTokenRefresh()
{
var refreshedToken = FirebaseInstanceId.Instance.Token;
Log.Debug(TAG, "Refreshed token: " + refreshedToken);
SendRegistrationToServer(refreshedToken);
}
void SendRegistrationToServer(string token) { }
}
OnMessageReceived :
[Service]
[IntentFilter(new[] {
"com.google.firebase.MESSAGING_EVENT"
})]
class MyFireMessagingService : FirebaseMessagingService
{
public override void OnMessageReceived(RemoteMessage message)
{
base.OnMessageReceived(message);
var title = string.Empty;
if (message.Data.Count > 0)
{
//Log.Debug(Tag, "Message data payload: " + message.Data);
title = message.Data["title"];
}
SendNotificatios(title);
}
public void SendNotificatios( string Header)
{
Notification.Builder builder = new Notification.Builder(this);
builder.SetSmallIcon(Resource.Drawable.Icon);
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
PendingIntent pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
builder.SetContentIntent(pendingIntent);
// builder.SetLargeIcon(BitmapFactory.DecodeResource(Resources, Resource.Drawable.Icon));
builder.SetContentTitle(Header);
builder.SetPriority(1);
builder.SetContentText("read more..");
builder.SetVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 });
builder.SetSound(Android.Net.Uri.Parse("android.resource://" + Application.PackageName + "/" + Resource.Raw.demonstrative));
builder.SetAutoCancel(true);
Random r = new Random();
int uniw = r.Next(1, 10);
NotificationManager notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(uniw, builder.Build());
}
}
Note : Notification works fine, just whenever notification arrived app reported crash to Google play console.
Please if anyone have any knowledge related to this problem will be helpful. TIA
Related
For my app I need values which are parsed by jSoup from a website and then returned to the user using a notification, these values change ~ every minute, so to be up-todate with the values I set up a task using a handler, this works good when the app is in foreground, but as soon as the user goes to the homescreen the app will return multiple exceptions like e.g. java.net.UnknownHostException or java.net.SocketTimeoutException, in the code this happens when jSoup is connecting to the specified site, I already tried using Services and AsyncTasks instead of threads, but it was always the exact same problem, I also searched for people with similar experiences, but I guess my issue is quite specific.
This is the code for the handler:
private final static int INTERVAL = 1000 * 60;
Handler mHandler = new Handler();
Runnable mHandlerTask = new Runnable()
{
#Override
public void run() {
try {
wakeLock.release();
} catch (RuntimeException e) {
e.printStackTrace();
}
if (!isUpdating) {
isUpdating = true;
App.shouldUpdate = true;
System.out.println("update");
final TinyDB tinydb = new TinyDB(getApplicationContext());
TextView priceEditText = loadedLayouts.get(1).findViewById(R.id.priceTextView);
TextView increaseEditText = loadedLayouts.get(1).findViewById(R.id.increaseTextView);
updatePricesStock(tinydb.getString("current_isin"), priceEditText, increaseEditText);
}
wakeLock.acquire(2*60*1000L /*10 minutes*/);
}
mHandler.postDelayed(mHandlerTask, INTERVAL);
}
}
};
and this is the code for the updateStockPrices method (I will not include updatePricesWarrant and updatePricesKnockout since they are essentially doing the same things and also throw the same exceptions)
public void updatePricesStock(final String ISIN, TextView priceText, TextView increaseText) {
final TinyDB tinydb = new TinyDB(getApplicationContext());
final Thread thread = new Thread(new Runnable() {
#Override
public void run() {
TinyDB tinydb = new TinyDB(getApplicationContext());
try {
Document doc = Jsoup.connect("https://www.ls-tc.de/de/aktie/" + ISIN).get();
System.out.println(ISIN);
increase = doc.selectFirst("#page_content > div > div:nth-child(1) > div > div.mpe_bootstrapgrid.col-md-8 > div > div:nth-child(3) > div > span:nth-child(3)").text().replace(" ", "");
tinydb.putString(ISIN + "notification_price", doc.selectFirst("#page_content > div > div:nth-child(1) > div > div.mpe_bootstrapgrid.col-md-8 > div > div:nth-child(3) > div > span:nth-child(1)").text() + "€");
} catch (IOException e) {
e.printStackTrace();
tinydb.putString(ISIN + "notification_price", "Error Scraping Price");
}
}
});
if(!thread.isAlive()) {
thread.start();
}
try{
thread.join();
}catch (Exception ex){
ex.printStackTrace();
}
if(!thread.isAlive()) {
notificationCompat = NotificationManagerCompat.from(getApplicationContext());
System.out.println("done");
System.out.println(tinydb.getString(ISIN + "notification_price"));
priceText.setText(tinydb.getString(ISIN + "notification_price"));
increaseText.setText(increase);
System.out.println("Text Updated " + priceText.getText().toString());
if(tinydb.getBoolean(ISIN + "_notification_status")) {
Notification notification = new NotificationCompat.Builder(getApplicationContext(), App.notificationChannel)
.setSmallIcon(R.drawable.ic_baseline_attach_money_24).setContentTitle(tinydb.getString(ISIN + "notification_name")).setContentText(tinydb.getString(ISIN + "notification_price")).setPriority(NotificationCompat.PRIORITY_MAX).setCategory(NotificationCompat.CATEGORY_STATUS).setOnlyAlertOnce(true).build();
notificationCompat.notify(tinydb.getInt(ISIN + "_notification_id"), notification);
}
isUpdating = false;
}
}
finnally these are the stacktraces I get:
W/System.err: java.net.SocketTimeoutException: timeout
W/System.err: at com.android.okhttp.okio.Okio$3.newTimeoutException(Okio.java:225)
at com.android.okhttp.okio.AsyncTimeout.exit(AsyncTimeout.java:263)
W/System.err: at com.android.okhttp.okio.AsyncTimeout$2.read(AsyncTimeout.java:217)
at com.android.okhttp.okio.RealBufferedSource.indexOf(RealBufferedSource.java:317)
at com.android.okhttp.okio.RealBufferedSource.indexOf(RealBufferedSource.java:311)
W/System.err: at com.android.okhttp.okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:207)
W/System.err: at com.android.okhttp.internal.http.Http1xStream.readResponse(Http1xStream.java:388)
at com.android.okhttp.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:146)
W/System.err: at com.android.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:900)
at com.android.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:772)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:493)
W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:429)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:560)
W/System.err: at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:106)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:30)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:734)
W/System.err: at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:706)
W/System.err: at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:299)
W/System.err: at org.jsoup.helper.HttpConnection.get(HttpConnection.java:288)
at de.xliquid.stockwatchultimate.MainActivity$4.run(MainActivity.java:266)
W/System.err: at java.lang.Thread.run(Thread.java:919)
W/System.err: Caused by: java.net.SocketException: socket is closed
at com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream.read(ConscryptFileDescriptorSocket.java:588)
at com.android.okhttp.okio.Okio$2.read(Okio.java:145)
at com.android.okhttp.okio.AsyncTimeout$2.read(AsyncTimeout.java:213)
W/System.err: ... 18 more
java.net.UnknownHostException: Unable to resolve host "www.onvista.de": No address associated with hostname
at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:156)
W/System.err: at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
at java.net.InetAddress.getAllByName(InetAddress.java:1152)
at com.android.okhttp.Dns$1.lookup(Dns.java:41)
W/System.err: at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:178)
at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:144)
at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:86)
at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:192)
at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:144)
at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:106)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:400)
W/System.err: at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:333)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:483)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:429)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:560)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:106)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:30)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:734)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:706)
at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:299)
at org.jsoup.helper.HttpConnection.get(HttpConnection.java:288)
W/System.err: at de.xliquid.stockwatchultimate.MainActivity$6.run(MainActivity.java:371)
at java.lang.Thread.run(Thread.java:919)
W/System.err: Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
W/System.err: at libcore.io.Linux.android_getaddrinfo(Native Method)
W/System.err: at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:200)
at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
W/System.err: ... 22 more
Also this app is solely for me so I don't really bother if the solution isn't the cleanest or drains the battery faster.
The problem was energy saving mode, if it is turned on the phone won't do requests in background / idle mode, no matter the wakelock, I solved my problem by adding a permission, so the app can request data even when the phone is in energy saving standby.
I am new to android. My BLE device expects only one byte(flag). I tried writing only one byte in a byte array but it never works. While writing an array to another characteristic where it expects 2 bytes works. Is there a way to solve my problem or do I have to ask for device code to be changed?
I am working with this project as my example
public void writeCustomCharacteristicStart() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("00001813-0000-1000-8000-00805f9b34fb"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
/*get the read characteristic from the service*/
byte pom= 1;
byte[] data= new byte[1];
data[0]=pom;
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString("00002a4e-0000-1000-8000-00805f9b34fb"));
if((mWriteCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE)>0 ) {
Log.w(TAG,"Writing started");
mWriteCharacteristic.setValue(data)
}
if(!mBluetoothGatt.writeCharacteristic(mWriteCharacteristic)){
Log.w(TAG, "Failed to write characteristic");
}
Log.w(TAG,"Writing ending");
}
08-06 11:59:57.700 29279-29279/com.example.devicescanactivity E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.devicescanactivity, PID: 29279
java.lang.IllegalStateException: Could not execute method of the activity
at android.view.View$1.onClick(View.java:4084)
at android.view.View.performClick(View.java:4858)
at android.view.View$PerformClick.run(View.java:20167)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5931)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:987)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at android.view.View$1.onClick(View.java:4079)
at android.view.View.performClick(View.java:4858)
at android.view.View$PerformClick.run(View.java:20167)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5931)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:987)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)
Caused by: java.lang.SecurityException: Need BLUETOOTH_PRIVILEGED permission: Neither user 10097 nor current process has android.permission.BLUETOOTH_PRIVILEGED.
at android.os.Parcel.readException(Parcel.java:1549)
at android.os.Parcel.readException(Parcel.java:1502)
at android.bluetooth.IBluetoothGatt$Stub$Proxy.writeCharacteristic(IBluetoothGatt.java:1003)
at android.bluetooth.BluetoothGatt.writeCharacteristic(BluetoothGatt.java:1029)
at com.example.devicescanactivity.BluetoothLeService.writeCustomCharacteristic(BluetoothLeService.java:377)
at com.example.devicescanactivity.DeviceControlActivity.onClickWrite(DeviceControlActivity.java:332)
Here is the error, I don't get the BLUETOOTH_PRIVILEGED error, but I don't get any errors when I write to the characteristic that accepts 2 bytes.
First, to use bluetooth in your app, you need to add the following permissions to your app manifest :
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
It is possible to write a 1 byte value to a BLE characteristic, provided the device expects a 1 byte value.
If there is a length issue, you should see the error in the onCharacteristicWrite() callback:
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("TAG", "onCharacteristicWrite() status: " + status + " - UUID: " + characteristic.getUuid());
} else if (status == BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH) {
Log.e("TAG", "onCharacteristicWrite() A write operation failed due to invalid attribute length");
} else {
Log.e("TAG", "onCharacteristicWrite() A write operation failed. Status = " + status);
}
}
Also, I would move the writeCharacteristic() call inside your check for PROPERTY_WRITE to ensure the write operation can be done:
if((mWriteCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0 ) {
Log.i(TAG,"Writing started");
mWriteCharacteristic.setValue(data)
if(!mBluetoothGatt.writeCharacteristic(mWriteCharacteristic)){
Log.e(TAG, "Failed to write characteristic");
}
}
The problem wasn't in what I write in the characteristic it was what characteristic I used. I used HID Control Point which when tested on the computer nRF Connect app worked fine for my device but it would not work on android because of its predefined states. We just changed characteristic to Record Access Control Point and it works for now.
Sometimes when i try to call getCameraPosition on my google map i am presented with the following exception:
java.lang.OutOfMemoryError: java.lang.String[] of length 1073741824 would overflow
at android.os.Parcel.readStringArray(Parcel.java:1798)
at android.os.StrictMode$ViolationInfo.<init>(StrictMode.java:2200)
at android.os.StrictMode.readAndHandleBinderCallViolations(StrictMode.java:1738)
at android.os.Parcel.readExceptionCode(Parcel.java:1527)
at android.os.Parcel.readException(Parcel.java:1496)
at com.google.android.gms.maps.internal.IGoogleMapDelegate$zza$zza.getCameraPosition(Unknown Source)
at com.google.android.gms.maps.GoogleMap.getCameraPosition(Unknown Source)
at com.myexample.fakegps.MainActivity$9.onCameraChange(MainActivity.java:1110)
at com.google.android.gms.maps.GoogleMap$7.onCameraChange(Unknown Source)
at com.google.android.gms.maps.internal.zzf$zza.onTransact(Unknown Source)
at android.os.Binder.transact(Binder.java:380)
at com.google.android.gms.maps.internal.IOnCameraChangeListener$Stub$Proxy.onCameraChange(IOnCameraChangeListener.java:93)
at com.google.maps.api.android.lib6.gmm6.api.a.a(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.api.a$1.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5289)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
I know its because StrictMode is enabled but when i convert my app into a system app the StrictMode gets enabled and i get this error (running the app as normal app runs fine).
I added the following code to try disable the StrictMode if my users moves my app to system apps:
private static void disableStrictMode() {
if (Build.VERSION.SDK_INT >= 9) {
doDisableStrictMode();
}
if (Build.VERSION.SDK_INT >= 16) {
//restore strict mode after onCreate() returns.
new Handler().postAtFrontOfQueue(new Runnable() {
#Override
public void run() {
doDisableStrictMode();
}
});
}
}
private static void doDisableStrictMode() {
StrictMode.ThreadPolicy.Builder builder = new StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy());
builder.permitAll();
StrictMode.ThreadPolicy policy = builder.build();
StrictMode.setThreadPolicy(policy);
if (Build.VERSION.SDK_INT >= 11) {
StrictMode.VmPolicy.Builder builder2 = new StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy());
builder2.detectAll();
builder2.penaltyLog();
StrictMode.VmPolicy policy2 = builder2.build();
StrictMode.setVmPolicy(policy2);
}
}
I call this code at the end of onCreate but it doesn´t work and i still get the exception, any ideas?
When I close my application, the service that had been started is supposed to continue running in the background. For some reason, the application crashes and throws a NullPointerException upon closing it.
I am using a MQTTConstants class to keep all the Constants in one place, and within that class I have a Hashset declared, which is then modified throughout the life of the application.
Is it possible that by closing the app, this information is being cleared? Although the service is never disconnected.
The service would continue to work off of this TOPIC_SET as it continues to run in the background.
public static HashSet<String> TOPIC_SET = new HashSet<String>();
STACK TRACE
02-20 14:14:30.620: E/AndroidRuntime(14753): FATAL EXCEPTION:
MQTTservice 02-20 14:14:30.620: E/AndroidRuntime(14753): Process:
com.l.ltestmqtt, PID: 14753 02-20 14:14:30.620:
E/AndroidRuntime(14753): java.lang.NullPointerException 02-20
14:14:30.620: E/AndroidRuntime(14753): at
com.l.ltestmqtt.MQTTService.handleStartAction(MQTTService.java:315)
02-20 14:14:30.620: E/AndroidRuntime(14753): at
com.l.ltestmqtt.MQTTService.handleStart(MQTTService.java:231)
02-20 14:14:30.620: E/AndroidRuntime(14753): at
com.l.ltestmqtt.MQTTService$2.run(MQTTService.java:196)
02-20 14:14:30.620: E/AndroidRuntime(14753): at
java.lang.Thread.run(Thread.java:841)
Here are the methods that are named within the Stack Trace
handleStart
synchronized void handleStart(Intent intent, int startId) {
// before we start - check for a couple of reasons why we should stop
Log.e("SERVICE", "----------HANDLESTART()-----------");
if (mqttClient == null) {
// we were unable to define the MQTT client connection, so we stop
// immediately - there is nothing that we can do
stopSelf();
return;
}
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
if (cm.getBackgroundDataSetting() == false) // respect the user's request not to use data!
{
// user has disabled background data
connectionStatus = MQTTConnectionStatus.NOTCONNECTED_DATADISABLED;
// update the app to show that the connection has been disabled
broadcastServiceStatus("Not connected - background data disabled");
// we have a listener running that will notify us when this
// preference changes, and will call handleStart again when it
// is - letting us pick up where we leave off now
return;
}
if (!handleStartAction(intent)) {
// the Activity UI has started the MQTT service - this may be starting
// the Service new for the first time, or after the Service has been
// running for some time (multiple calls to startService don't start
// multiple Services, but it does call this method multiple times)
// if we have been running already, we re-send any stored data
rebroadcastStatus();
rebroadcastReceivedMessages();
}
// if the Service was already running and we're already connected - we
// don't need to do anything
if (isAlreadyConnected() == false) {
// set the status to show we're trying to connect
connectionStatus = MQTTConnectionStatus.CONNECTING;
// we are creating a background service that will run forever until
// the user explicity stops it. so - in case they start needing
// to save battery life - we should ensure that they don't forget
// we're running, by leaving an ongoing notification in the status
// bar while we are running
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification =
new Notification(R.drawable.ic_launcher, "MQTT", System.currentTimeMillis());
notification.flags |= Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_NO_CLEAR;
Intent notificationIntent = new Intent(this, MQTTNotifier.class);
PendingIntent contentIntent =
PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(this, "MQTT", "MQTT Service is running", contentIntent);
nm.notify(MQTTConstants.MQTT_NOTIFICATION_ONGOING, notification);
// before we attempt to connect - we check if the phone has a
// working data connection
if (isOnline()) {
// we think we have an Internet connection, so try to connect
// to the message broker
if (connectToBroker()) {
// we subscribe to a topic - registering to receive push
// notifications with a particular key
// in a 'real' app, you might want to subscribe to multiple
// topics - I'm just subscribing to one as an example
// note that this topicName could include a wildcard, so
// even just with one subscription, we could receive
// messages for multiple topics
//subscribe to initial TOPIC_SET topics, ie device_id_topic, all_topic
subscribeToAllTopics();
//subscribeToTopic(topicName);
}
} else {
// we can't do anything now because we don't have a working
// data connection
connectionStatus = MQTTConnectionStatus.NOTCONNECTED_WAITINGFORINTERNET;
// inform the app that we are not connected
broadcastServiceStatus("Waiting for network connection");
}
}
// changes to the phone's network - such as bouncing between WiFi
// and mobile data networks - can break the MQTT connection
// the MQTT connectionLost can be a bit slow to notice, so we use
// Android's inbuilt notification system to be informed of0
// network changes - so we can reconnect immediately, without
// having to wait for the MQTT timeout
if (netConnReceiver == null) {
netConnReceiver = new NetworkConnectionIntentReceiver();
registerReceiver(netConnReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
// creates the intents that are used to wake up the phone when it is
// time to ping the server
if (pingSender == null) {
pingSender = new PingSender();
registerReceiver(pingSender, new IntentFilter(MQTTConstants.MQTT_PING_ACTION));
}
}
handleStartAction
private boolean handleStartAction(Intent intent) {
String action = intent.getAction();
if (action == null) {
return false;
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_SUBSCRIBE_TOPIC_INTENT)) {
handleSubscribeTopicIntent(intent);
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_PUBLISH_MSG_INTENT)) {
handlePublishMessageIntent(intent);
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_UNSUBSCRIBE_TOPIC_INTENT)) {
handleUnsubscribeTopicIntent(intent);
}
return true;
}
UPDATES: The problem exists within the handleStart() method. If I comment this if (!handleStartAction(intent)) { the issue no longer occurs.
FOR ρяσѕρєя K
The service is started inside MQTTNotifier Activity using this
MQTTServiceDelegate.startService(this);
which references this method inside the MQTTServiceDelegateClass
public static void startService(Context context) {
Intent svc = new Intent(context, MQTTService.class);
context.startService(svc);
}
I have solved the issue, I will mark this as the answer unless someone is able to provide a better solution.
I ran a quick test to see if the intent was == null, and if it was I just logged it, otherwise I processed the code.
private boolean handleStartAction(Intent intent) {
if (intent == null) {
Log.e("NULL INTENT", "***************NULL INTENT**************");
} else {
String action = intent.getAction();
if (action == null) {
return false;
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_SUBSCRIBE_TOPIC_INTENT)) {
handleSubscribeTopicIntent(intent);
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_PUBLISH_MSG_INTENT)) {
handlePublishMessageIntent(intent);
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_UNSUBSCRIBE_TOPIC_INTENT)) {
handleUnsubscribeTopicIntent(intent);
}
}
return true;
}
On my android project, I am getting an intermittent NullPointerException reported in both crashlytics and the play store for a null pointer exception when invoking one of my objects invokes a method on itself.
Here is the entirety of the method that has the NullPointerException:
#Override
public void notifyActivityStarted() {
startUpdatingLocation(); // <-- NullPointerException occurs here. This is line 83 of DefaultAndroidLocationProvider.java
}
private void startUpdatingLocation() {
final String bestProvider = getBestProviderName();
Log.d(LOGTAG, "Starting to update location for provider: " + bestProvider);
// If we don't have a location yet, then let's make sure we get one at
// least
// temporarily.
Location currentLoc = getLastLocationFromBestProvider();
if (currentLoc != null) {
Log.d(LOGTAG, "Hydrating with last location");
mLastLocation.hydrate(currentLoc);
}
mWorker = new WorkerThread("DefaultAndroidLocation");
// Get a location update every 10s from both network and GPS.
if (mManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
mManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
10000,
0,
DefaultAndroidLocationProvider.this,
mWorker.getLooper());
}
if (mManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
mManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
10000,
0,
DefaultAndroidLocationProvider.this,
mWorker.getLooper());
}
mIsUpdatingLocation = true;
shutdownInitiated = false;
}
Here is the stack trace:
java.lang.NullPointerException
at com.jingit.mobile.location.DefaultAndroidLocationProvider.notifyActivityStarted(DefaultAndroidLocationProvider.java:83)
at com.jingit.mobile.location.ActivityObserverSet.onStartObserved(ActivityObserverSet.java:48)
at com.jingit.mobile.location.LocationAwareFragment.onStart(LocationAwareFragment.java:41)
at android.support.v4.app.Fragment.performStart(Fragment.java:1484)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:941)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5633)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:896)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:712)
at dalvik.system.NativeStart.main(NativeStart.java)
I wasn't able to find anything to give me hints on the documentation for NullPointerException, and haven't been able to find any other helpful hints. Any thoughts or ideas would be greatly appreciated.