Estimote / Android-Indoor-SDK

Estimote Indoor SDK for Android
MIT License
63 stars 28 forks source link

Indoor location Forced close #16

Closed HAmatrook closed 6 years ago

HAmatrook commented 6 years ago

Prerequisites

Basic information

Estimote SDK version: [com.estimote:indoorsdk:2.3.0]

Android devices affected: [HUAWAEI P smart]

Android OS version affected: [Oreo 8.0.0]

Beacon hardware version: [F3.3]

Description

[forced close if I run the activity]

Steps to reproduce: I did not get it

Expected behavior: [View the map with the user position]

Actual behavior: [Forced close]

(Optional) Additional information

`package com.example.albayan.location_try;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.app.Notification;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import com.estimote.indoorsdk.IndoorLocationManagerBuilder;
import com.estimote.indoorsdk_module.algorithm.OnPositionUpdateListener;
import com.estimote.indoorsdk_module.algorithm.ScanningIndoorLocationManager;
import com.estimote.indoorsdk_module.cloud.CloudCallback;
import com.estimote.indoorsdk_module.cloud.EstimoteCloudException;
import com.estimote.indoorsdk_module.cloud.IndoorCloudManager;
import com.estimote.indoorsdk_module.cloud.IndoorCloudManagerFactory;
import com.estimote.indoorsdk_module.cloud.Location;
import com.estimote.indoorsdk_module.cloud.LocationPosition;
import com.estimote.indoorsdk_module.view.IndoorLocationView;
import com.estimote.internal_plugins_api.cloud.CloudCredentials;
import com.estimote.cloud_plugin.common.EstimoteCloudCredentials;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    IndoorLocationView indoorLocationView; // = (IndoorLocationView) findViewById(R.id.indoor_view);
    ScanningIndoorLocationManager indoorLocationManager;

    //IndoorLocationView a = (IndoorLocationView) findViewById(R.id.indoor_view);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        indoorLocationView = (IndoorLocationView) findViewById(R.id.indoor_view);

        // Connection to Estimote and the App
        final CloudCredentials cloudCredentials = new EstimoteCloudCredentials("fireguider-ay4", "0e5620d33e32a3d8629c9510acce971c");
        IndoorCloudManager cloudManager = new IndoorCloudManagerFactory().create(this, cloudCredentials);

        // Get the saved map  in estimote
        cloudManager.getLocation("senior-project-room-np8", new CloudCallback<Location>() {

            TextView err = (TextView)findViewById(R.id.error);

            @Override
            public void success(Location location) {
                // view the map in the app ( have to insert it first in the Layout=========================
                indoorLocationView = (IndoorLocationView) findViewById(R.id.indoor_view);
                indoorLocationView.setLocation(location);
                err.setText("setLocation");

                // scan beacons automatically==============================================================
                indoorLocationManager = new IndoorLocationManagerBuilder(MainActivity.this, location,cloudCredentials)
                        .withDefaultScanner()
                        .build();

                // Position Update Listener ===============================================================
                indoorLocationManager.setOnPositionUpdateListener(new OnPositionUpdateListener() {
                    @Override //it will update the user's position in the mpp
                    public void onPositionUpdate(LocationPosition locationPosition) {

                        indoorLocationView.updatePosition(locationPosition);

                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(MainActivity.this, "Movement", Toast.LENGTH_SHORT).show();

                            }
                        });

                        err.setText("setOnPositionUpdate");
                    }

                    @Override // I can't See You , Hide
                    public void onPositionOutsideLocation() {
                        indoorLocationView.hidePosition();

                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(MainActivity.this, "--Movement", Toast.LENGTH_SHORT).show();

                            }
                        });
                        indoorLocationManager.startPositioning();
                        err.setText("Error onPositionOutsideLocation");
                    }
                });
            }
            @Override
            public void failure(EstimoteCloudException e) {
                err.setText(e.getBody());
                //Log.e("MYAPP", e.getBody());
            }
        });

        // Notification ( Scanning beacons is still working in the background)
        Notification notification = new Notification.Builder(this)
                .setSmallIcon(R.drawable.notification_icon_background)
                .setContentTitle("Indoor location")
                .setContentText("Scan is running...")
                .setPriority(Notification.PRIORITY_HIGH)
                .build();

    }

    // Stop and Start

    @Override
    protected void onStart() {
        super.onStart();
        indoorLocationManager.startPositioning();

    }
    @Override
    protected void onStop() {
        super.onStop();
        if (indoorLocationManager != null)
            indoorLocationManager.stopPositioning();
    }

}

`

FATAL EXCEPTION: main Process: com.example.albayan.location_try, PID: 4732 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.albayan.location_try/com.example.albayan.location_try.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'void com.estimote.indoorsdk_module.algorithm.ScanningIndoorLocationManager.startPositioning()' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void com.estimote.indoorsdk_module.algorithm.ScanningIndoorLocationManager.startPositioning()' on a null object reference at com.example.albayan.location_try.MainActivity.onStart(MainActivity.java:138) at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1333) at android.app.Activity.performStart(Activity.java:6992) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2780) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)  at android.app.ActivityThread.-wrap11(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)  at android.os.Handler.dispatchMessage(Handler.java:105)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6541)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 

Poberro commented 6 years ago

I'm not an Indoor SDK expert, but error message clearly tells that you that in line 138 (in method onStart) startPositioning was called on null object reference. When you look at that line it is obvious that indoorLocationManager must be null . Next step is to check where indoorLocationManager is initialized and it seems that it is inside getLocation callback. This request looks like it is asynchronous cloud request. So now it is clear what happens:

  1. in onCreate asynchronous call is made to Cloud
  2. onStart methods is called (as Activity lifecycle diagram says)
  3. NullPointerException is thrown becasue indoorLocationManager is null
  4. Cloud callback finishes and sets initializes indoorLocationManager (but is too late) In other words onStart gets called before Cloud call has finished and finds indoorLocationManager set to null, becuase it is initialized when callback ends. Solution will be to call startPositioning after callback finishes. I wander why call to indoorLocationManager is guarded for null inside onStop, but not inside onStart? I needed to look at the code to find why this is happening, but if you already have your Android Studio running, the simplest method is to run your code in debug mode and place one breakpoint in line where NPE happens and second one in line where variable is initialized or cleared. Then run the code and see in which line program stops first.