getGeoPoint() 方法在调用时返回 null。 Firebase 集合中有超过 1 个文档

Posted

技术标签:

【中文标题】getGeoPoint() 方法在调用时返回 null。 Firebase 集合中有超过 1 个文档【英文标题】:getGeoPoint() method returns null when called. There is more than 1 document in the Firebase collection 【发布时间】:2021-01-21 22:55:06 【问题描述】:

我正在关注有关使用 Google Maps API 构建包含 用户位置 功能的 Chatroom 应用程序的教程,但是,我关注它只是为了学习如何使用 Google Maps API,我'正在尝试构建一个跟踪应用程序,可以记录旅行路线并按日期访问它们等。

有一个UserLocation 对象,由地理位置、时间戳和一个用户对象组成,它的实例存储在 Firestore 集合中。数据库工作正常:

但是,经过身份验证后,我收到以下错误:

E/androidRuntime: FATAL EXCEPTION: main
    Process: com.example.trackingapp, PID: 13386
    java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.firebase.firestore.GeoPoint com.example.trackingapp.models.UserLocation.getGeo_point()' on a null object reference
        at com.example.trackingapp.ui.MainActivity.setCameraView(MainActivity.java:109)
        at com.example.trackingapp.ui.MainActivity.onMapReady(MainActivity.java:410)
        at com.google.android.gms.maps.zzac.zza(Unknown Source)
        at com.google.android.gms.maps.internal.zzaq.dispatchTransaction(Unknown Source)
        at com.google.android.gms.internal.maps.zzb.onTransact(Unknown Source)
        at android.os.Binder.transact(Binder.java:499)
        at ds.b(:com.google.android.gms.dynamite_mapsdynamite@203615052@20.36.15 (040700-0):2)
        at com.google.maps.api.android.lib6.impl.bf.run(:com.google.android.gms.dynamite_mapsdynamite@203615052@20.36.15 (040700-0):2)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

我猜我在尝试将原始 App 的逻辑实现到我的时犯了一个错误。

我几乎可以肯定问题在于mUserListEventListener 的使用方式。这个变量实际上包含了将 UserLocations 放入 ArrayList 的所有逻辑,但它只在 OnDestroy() 方法中调用!!

教程的源代码就是这样写的,mUserListEventListener没有其他用法。我已经尝试在其他地方实现 UserLocations 逻辑,但我无法做到。

这里是相关的 MainActivity 代码。这是我的应用程序中唯一的活动(除了登录和注册):

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback 

    //    Variables Google Maps
    private boolean mLocationPermissionGranted = false;
    private MapView mMapView;
    private FusedLocationProviderClient mFusedLocationClient;
    private UserLocation mUserLocation;
    private ArrayList<UserLocation> mUserLocations = new ArrayList<>();
    private GoogleMap mGoogleMap;
    private LatLngBounds mMapBoundary;
    private UserLocation mUserPosition;

    //    Variables Firebase
    private FirebaseFirestore mDb;
    private ListenerRegistration mUserListEventListener;
    private Set<String> mUserIds = new HashSet<>();


    //    Otras Variables
    private RecyclerView rvUsers;
    private UserRecyclerAdapter adapter;
    private ArrayList<User> mUserList = new ArrayList<>();
    private static final String TAG = "MainActivity";

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

        initGoogleMap(savedInstanceState);

        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

        // DATA DE FIREBASE
        //
        mDb = FirebaseFirestore.getInstance();
        rvUsers = (RecyclerView) findViewById(R.id.user_list_recycler_view);
        getUsers();
        initUserRecyclerView();
        setUserPosition();
    

    private void setCameraView()

        double bottomBoundary = mUserPosition.getGeo_point().getLatitude() - .1;
        double leftBoundary = mUserPosition.getGeo_point().getLongitude() - .1;
        double topBoundary = mUserPosition.getGeo_point().getLatitude() + .1;
        double rightBoundary = mUserPosition.getGeo_point().getLongitude() + .1;

        mMapBoundary = new LatLngBounds(
                new LatLng(bottomBoundary,leftBoundary),
                new LatLng(topBoundary,rightBoundary)
        );

        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mMapBoundary,0));
    

    private void setUserPosition()
        for (UserLocation userLocation : mUserLocations)
            if (userLocation.getUser().getUser_id().equals(FirebaseAuth.getInstance().getUid()))
                mUserPosition = userLocation;
            
        
    

    private void getUserDetails()
        if (mUserLocation == null)
            mUserLocation = new UserLocation();

            DocumentReference userRef = mDb.collection("Users")
                    .document(Objects.requireNonNull(FirebaseAuth.getInstance().getUid()));

            userRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() 
                @Override
                public void onComplete(@NonNull Task<DocumentSnapshot> task) 
                    if (task.isSuccessful())
                        Log.d(TAG, "onComplete: successfully set the user details.");

                        User user = task.getResult().toObject(User.class);
                        mUserLocation.setUser(user);
                        ((UserClient)getApplicationContext()).setUser(user);
                        getLastKnownLocation();
                    
                
            );
        
        else 
            getLastKnownLocation();
        
    

    private void saveUserLocation()
        if(mUserLocation != null)
            DocumentReference locationRef = mDb.
                    collection("User Locations")
                    .document(Objects.requireNonNull(FirebaseAuth.getInstance().getUid()));

            locationRef.set(mUserLocation).addOnCompleteListener(new OnCompleteListener<Void>() 
                @Override
                public void onComplete(@NonNull Task<Void> task) 
                    if(task.isSuccessful())
                        Log.d(TAG, "saveUserLocation: \ninserted user location into database." +
                                "\n latitude: " + mUserLocation.getGeo_point().getLatitude() +
                                "\n longitude: " + mUserLocation.getGeo_point().getLongitude());
                    
                
            );
        
    

    private void getLastKnownLocation() 
        Log.d(TAG, "getLastKnownLocation: called");

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) 
            return;
        
        mFusedLocationClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() 
            @Override
            public void onComplete(@NonNull Task<Location> task) 
                if (task.isSuccessful())
                    Location location = task.getResult();
                    GeoPoint geoPoint = new GeoPoint(location.getLatitude(), location.getLongitude());
                    Log.d(TAG, "onComplete: latitude: " + geoPoint.getLatitude());
                    Log.d(TAG, "onComplete: longitude" + geoPoint.getLongitude());

                    mUserLocation.setGeo_point(geoPoint);
                    mUserLocation.setTimestamp(null);
                    saveUserLocation();
                
            
        );
    


private void getUsers() 

        CollectionReference usersCollection = mDb
                .collection("Users");

        mUserListEventListener = usersCollection.addSnapshotListener(new EventListener<QuerySnapshot>() 
            @Override
            public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) 
                Log.d(TAG, "onEvent: called.");

                if (e != null) 
                    Log.e(TAG, "onEvent: Listen failed.", e);
                    return;
                

                if(queryDocumentSnapshots != null)

                    // Clear the list and add all the users again
                    mUserList.clear();
                    mUserList = new ArrayList<>();

                    for (QueryDocumentSnapshot doc : queryDocumentSnapshots) 
                        User user = doc.toObject(User.class);
                        mUserList.add(user);
                        getUserLocation(user);
                    

                    Log.d(TAG, "onEvent: user list size: " + mUserList.size());
                

            
        );

    

    private void getUserLocation(User user)
        DocumentReference locationRef = mDb.collection("User Locations")
                .document(user.getUser_id() );

        locationRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() 
            @Override
            public void onComplete(@NonNull Task<DocumentSnapshot> task) 
                if (task.isSuccessful())
                    if(task.getResult().toObject(UserLocation.class) != null)
                        mUserLocations.add(task.getResult().toObject(UserLocation.class));
                    
                
            
        );
    


    @Override
    protected void onResume() 
        super.onResume();
        if (checkMapServices()) 
            if (mLocationPermissionGranted) 
                getUsers();
                getUserDetails();
             else 
                getLocationPermission();
            
        
        mMapView.onResume();
    

    @Override
    protected void onStart() 
        super.onStart();
        mMapView.onStart();
    

    @Override
    protected void onStop() 
        super.onStop();
        mMapView.onStop();
    

    @Override
    public void onMapReady(GoogleMap map) 
        map.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) 
            return;
        
        map.setMyLocationEnabled(true);
        mGoogleMap = map;
        setCameraView();
    

    @Override
    protected void onPause() 
        mMapView.onPause();
        super.onPause();
    

    @Override
    protected void onDestroy() 
        mMapView.onDestroy();
        super.onDestroy();
        if(mUserListEventListener != null)
            mUserListEventListener.remove();
        
    

    @Override
    public void onLowMemory() 
        super.onLowMemory();
        mMapView.onLowMemory();
    


【问题讨论】:

【参考方案1】:

拥有NullPointerException 与返回 null 不同。 在这种情况下,如错误跟踪所示,在这里:

at com.example.trackingapp.ui.MainActivity.setCameraView(MainActivity.java:109)

调用了一个空 obj。

java.lang.NullPointerException: Attempt to invoke virtual method 
    'com.google.firebase.firestore.GeoPoint 
     com.example.trackingapp.models.UserLocation.getGeo_point()'
     on a null object reference

这里是mUserPosition.getGeo_point()

错误提示mUserPosition为null,需要先初始化。

如果 var mUserPosition 为空,您可能需要调用 getUserDetails(这我不知道)。

if (mUserPosition == null) 
    getUserDetails();

【讨论】:

以上是关于getGeoPoint() 方法在调用时返回 null。 Firebase 集合中有超过 1 个文档的主要内容,如果未能解决你的问题,请参考以下文章

为啥 UITableViewCells cellForRowAt 方法不调用?

opencv调用nu-book/zxing-cpp识别二维码

python -- 函数传参

调用方法并将返回值分配给数组时,为啥C#在调用方法时使用数组引用?

nu.xom:Document

如何监视调用另一个返回承诺的服务的服务函数 - 打字稿