拒绝位置设置请求时设置视图 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>
- 您使用的是哪种布局?您可以为片段使用框架布局。 (你需要记住一件事,框架布局一次只能显示一个子布局)
将内容放入此框架布局中,您还必须再添加一个布局,即文本视图布局,表示该位置不是 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>
类似的东西..^
现在进入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;
}
}
我遇到这个问题,当用户拒绝在弹出窗口中打开他们的 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>
- 您使用的是哪种布局?您可以为片段使用框架布局。 (你需要记住一件事,框架布局一次只能显示一个子布局)
将内容放入此框架布局中,您还必须再添加一个布局,即文本视图布局,表示该位置不是 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>
类似的东西..^
现在进入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;
}
}