拒绝位置设置请求时设置视图 returns 空指针?

Setting up view returns null pointer when location settings request is refused?

我遇到这个问题,当用户拒绝在弹出窗口中打开他们的 Location 设置时,我的 Fragment returns 中的 Views 为空。我似乎无法在 Fragment 中引用任何 Views。我想这是因为 Location 请求 View 的弹出对话框取代了我的 Fragment View 但我无法弄清楚如何在 [=] 中访问 Views 15=]。这是我的尝试:

private View fragmentView;
private View progressOverlay;
private View noPostsView;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (fragmentView == null) {
        fragmentView = inflater.inflate(R.layout.posts_tab, container, false);
        setupActivity(savedInstanceState);
        progressOverlay = fragmentView.findViewById(R.id.progress_overlay);
        progressOverlay.setVisibility(View.VISIBLE);
        noPostsView = fragmentView.findViewById(R.id.no_posts_layout);
        setupLocation();
    }
    return fragmentView;
}

private void setupLocation() {
    Context context = getContext();
    if(locationService == null) {
        locationService = new LocationService(context, new LocationUpdateListener() {
            @Override
            public void canReceiveLocationUpdates() {

            }

            @Override
            public void cannotReceiveLocationUpdates() {
                createSettingsRequest();
                //well we know we cant receive updates so we have to create a settings request
            }

            //update location to our servers for tracking purpose
            @Override
            public void updateLocation(Location location) {
                if (location != null) {
                    //Populate Recycler View
                    databaseQuery.getPublicPosts(location, progressOverlay, fragmentView, getContext());
                }
            }

            @Override
            public void updateLocationName(String localityName, Location location) {
                locationService.stopLocationUpdates();
            }
        });
        locationService.startUpdates();
    }
}

private void createSettingsRequest() {
    LocationRequest locationRequest = LocationRequest.create();
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationRequest.setInterval(30 * 1000);
    locationRequest.setFastestInterval(5 * 1000);
    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
            .addLocationRequest(locationRequest);
    builder.setAlwaysShow(true); //this is the key ingredient

    PendingResult<LocationSettingsResult> result =
            LocationServices.SettingsApi.checkLocationSettings(locationService.mGoogleApiClient
                    , builder.build());
    result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
        @Override
        public void onResult(LocationSettingsResult result) {
            final Status status = result.getStatus();
            final LocationSettingsStates state = result.getLocationSettingsStates();
            switch (status.getStatusCode()) {
                case LocationSettingsStatusCodes.SUCCESS:
                    // All location settings are satisfied. The client can initialize location
                    // requests here.
                    break;
                case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                    // Location settings are not satisfied. But could be fixed by showing the user
                    // a dialog.
                    try {
                        // Show the dialog by calling startResolutionForResult(),
                        // and check the result in onActivityResult().
                        status.startResolutionForResult(getActivity(), REQUEST_LOCATION);
                    } catch (IntentSender.SendIntentException e) {
                        FirebaseCrash.report(e);
                    }
                    break;
                case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                    // Location settings are not satisfied. However, we have no way to fix the
                    // settings so we won't show the dialog.
                    break;
            }
        }
    });
}

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            // Check for the integer request code originally supplied to startResolutionForResult().
            case REQUEST_LOCATION:
                switch (resultCode) {
                    case Activity.RESULT_OK:
                        break;
                    case Activity.RESULT_CANCELED:
                        setupNoPostsView();
                        break;
                }
                break;
        }
    }

private void setupNoPostsView() {
    progressOverlay.setVisibility(View.GONE);
    noPostsView.setVisibility(View.VISIBLE);
    RecyclerView recyclerView = (RecyclerView) fragmentView.findViewById(R.id.rv_posts_feed);
    recyclerView.setVisibility(View.GONE);
    TextView noPosts = (TextView) noPostsView.findViewById(R.id.no_posts_text);
    noPosts.setText(R.string.permission_location_rationale);
}

我只是想在用户单击 No 允许 Location Services 时调用 setupNoPostsView,但无论出于何种原因,progressOverlay View 一直返回 null 当我尝试设置 Visibility = View.GONE。关于如何解决这个问题的任何想法?

根据第一个答案的要求更新这里是我的布局:

Fragment.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/posts_tab"
    tools:showIn="@layout/app_bar_news_feed" tools:context=".news_feed">

    <include layout="@layout/include_progress_overlay"/>

    <include layout="@layout/no_posts"/>

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/rv_posts_feed"
        android:visibility="gone"
        />

</FrameLayout>

no_posts.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:id="@+id/no_posts_layout"
    android:visibility="gone"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:textSize="16sp"
        android:layout_gravity="center"
        android:gravity="center"
        android:textAlignment="center"
        android:id="@+id/no_posts_text" />

</FrameLayout>
  1. 您使用的是哪种布局?您可以为片段使用框架布局。 (你需要记住一件事,框架布局一次只能显示一个子布局)
  2. 将内容放入此框架布局中,您还必须再添加一个布局,即文本视图布局,表示该位置不是 available.At 开始此文本的视图属性视图应该被隐藏。

    <FrameLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent">
    
    <android.support.v7.widget.RecyclerView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:id="@+id/rv"
       />
       <TextView
           android:id="@+id/error"
           android:layout_gravity="left|center|right"
           android:layout_width="match_parent"
           android:visibility="gone"
           android:layout_height="wrap_content"
           android:text="No location available"
           android:textAlignment="center" />
    </FrameLayout>
    

类似的东西..^

  1. 现在进入java代码

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            // Check for the integer request code originally supplied to startResolutionForResult().
            case REQUEST_LOCATION:
                switch (resultCode) {
                    case Activity.RESULT_OK:
                        break;
                    case Activity.RESULT_CANCELED:
                        setupNoPostsView();
                        break;
                }
                break;
        }
    }
    
    
    
    private void setupNoPostsView() 
    {
        RecyclerView recyclerView = (RecyclerView) fragmentView.findViewById(R.id.rv_posts_feed);
        recyclerView.setVisibility(View.GONE);
        textView1.setVisibility(View.VISIBLE);
    
     }
    

所以,方法

status.startResolutionForResult(getActivity(), REQUEST_LOCATION);

正在调用由 google 提供的新 activity 播放服务,该服务显示用于打开位置设置的对话框。我们将 A 称为您的 activity,将 B 称为 google 播放服务提供的服务。可能,当创建 B 时,由于内存压力或因为您更改了设备的方向,A 被销毁。当你在 B 上 select 'refuse' 时,回调 'onActivityResult' 在视图被 Android 重新创建之前被调用(这实际上是可能的)。所以......你必须以不同的方式管理这种情况,例如在你的 onAcvityResult 上设置一种标志。示例:

private Integer myResult = null;

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (REQUEST_LOCATION == requestCode) {
        View root = getView();
        if (root != null) { // Consider also isResumed()
            // you can operate on your views
            applyLogicForResult(resultCode);
        } else {
            myResult = resultCode;
        }
    }
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { // Consider also onResume()
    if (myResult != null) {
        applyLogicForResult(myResult);
        myResult = null;
    }
}