1

在我的應用程序中,我有一個經典的「MyLocationButton」的MapFragment。 在較舊的API上我沒有任何問題,但是因爲Google要求開發者使用運行時權限,所以我遇到了這個問題:當用戶點擊ALLOW時,已經說過的按鈕沒有出現,至少沒有直到用戶刷新這個片段。有沒有辦法讓用戶的媒體在獲得權限後立即刷新片段?Android運行時Permissions:捕捉用戶的新聞「允許」

編輯: 我使用嵌套的片段,我發現我的問題是,你可以在的AOSP Issue Tracker此頁面看到的一樣。我已經使用最新版本的Android API(v24)解決了這個問題。

Android Permissions

我會後我的MapFragment

public class MapFragment extends Fragment implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, PetrolStationsArray.PetrolStationsListener { 

    private GoogleMap mGoogleMap; 
    private int mMapType; 
    private static LatLng mPosition; 
    private static float mZoom; 
    private CoordinatorLayout mCoordinatorLayout; 
    private View mLocationButton; 
    private AppCompatImageButton mTurnGPSOn; 

    private FragmentManager mFragmentManager; 
    private FragmentTransaction mFragmentTransaction; 

    private SupportMapFragment mSupportMapFragment; 
    private SupportPlaceAutocompleteFragment mSupportPlaceAutocompleteFragment; 

    private LocalBroadcastManager mLocalBroadcastManager; 

    private PetrolStationsArray mPetrolStationsArray; 

    protected LocationRequest mLocationRequest; 
    protected GoogleApiClient mGoogleApiClient; 
    Marker mCurrLocationMarker; 

    private CountDownTimer mDragTimer; 
    private boolean mTimerIsRunning = false; 


    // Design pattern to instantiate a new fragment. 
    public static MapFragment newInstance() { 
     MapFragment fragment = new MapFragment(); 

     return fragment; 
    } 

    /********************************************************/ 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     // Since API 23, Android requests you check for Location Permissions. 
     if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      checkLocationPermission(); 
     } 

     mMapType = Integer.parseInt(loadPreferences(SETTINGS_PREFERENCES, MAP_KEY)); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.fragment_map, container, false); 

     mLocalBroadcastManager = LocalBroadcastManager.getInstance(getContext()); 

     mPetrolStationsArray = PetrolStationsArray.get(); 

     mDragTimer = new CountDownTimer(DRAG_TIMER_INTERVAL, DRAG_TIMER_INTERVAL + 1) { 
      @Override 
      public void onTick(long l) { 

      } 

      @Override 
      public void onFinish() { 
       mTimerIsRunning = false; 
       mPetrolStationsArray.setPosition(mPosition); 
      } 
     }; 

     return view; 
    } 

    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 
     super.onViewCreated(view, savedInstanceState); 

     // Initialise a new fragment inside of this one. 
     mFragmentManager = getChildFragmentManager(); 
     mSupportMapFragment = (SupportMapFragment) mFragmentManager.findFragmentByTag(MAP_FRAGMENT_TAG); 
     mSupportPlaceAutocompleteFragment = (SupportPlaceAutocompleteFragment) mFragmentManager.findFragmentByTag(AUTOCOMPLETE_FRAGMENT_TAG); 

     mCoordinatorLayout = (CoordinatorLayout) view.findViewById(R.id.coordinator_layout); 

     /* 
     ** Never inflate fragments inside other fragments in a layout.xml! 
     ** Do it programmatically. 
     ** See here for reference: http://stackoverflow.com/a/19815266/4938112. 
     */ 
     if (mSupportMapFragment == null) { 
      mSupportMapFragment = new SupportMapFragment(); 
      fragmentTransaction(mFragmentManager, mSupportMapFragment, R.id.map_fragment_container, MAP_FRAGMENT_TAG); 
     } 

     // Asynchronous thread to load map. 
     mSupportMapFragment.getMapAsync(this); 

     if (mSupportPlaceAutocompleteFragment == null) { 
      mSupportPlaceAutocompleteFragment = new SupportPlaceAutocompleteFragment(); 
      fragmentTransaction(mFragmentManager, mSupportPlaceAutocompleteFragment, R.id.card_view, AUTOCOMPLETE_FRAGMENT_TAG); 
     } 

     // Filter for a specific place type. 
     AutocompleteFilter typeFilter = new AutocompleteFilter.Builder() 
       .setTypeFilter(AutocompleteFilter.TYPE_FILTER_CITIES | AutocompleteFilter.TYPE_FILTER_ADDRESS) 
       .build(); 

     mSupportPlaceAutocompleteFragment.setFilter(typeFilter); 

     mSupportPlaceAutocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() { 
      @Override 
      public void onPlaceSelected(Place place) { 
       LatLng position = place.getLatLng(); 

       CameraUpdate centre = CameraUpdateFactory.newLatLng(position); 
       CameraUpdate zoom = CameraUpdateFactory.zoomTo(ZOOM_LEVEL); 

       mGoogleMap.moveCamera(centre); 
       mGoogleMap.animateCamera(zoom); 
      } 

      @Override 
      public void onError(Status status) { 
       Log.d("PLACE_ERROR", "An error occurred: " + status); 
      } 
     }); 

     mTurnGPSOn = ((AppCompatImageButton) view.findViewById(R.id.turn_gps_on)); 

     mTurnGPSOn.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       // Ask if the user wants to open the GPS - settings. 
       displayPromptToEnableGPS(getActivity()); 
      } 
     }); 
    } 

    @Override 
    public void onActivityResult(int requestCode, int resultCode, Intent data) { 
     super.onActivityResult(requestCode, resultCode, data); 
    } 

    @Override 
    public void onMapReady(GoogleMap googleMap) { 
     this.mGoogleMap = googleMap; 

     mGoogleMap.setMapType(mMapType); 

     if (mPosition != null) { 
      CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(mPosition, mZoom); 
      mGoogleMap.moveCamera(cameraUpdate); 
     } 

     mGoogleMap.setTrafficEnabled(true); 
     mGoogleMap.getUiSettings().setMapToolbarEnabled(false); 

     mGoogleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() { 
      @Override 
      public void onCameraChange(CameraPosition cameraPosition) { 
       mPosition = cameraPosition.target; 
       mZoom = cameraPosition.zoom; 

       if (mTimerIsRunning) { 
        mDragTimer.cancel(); 
       } 

       mDragTimer.start(); 
       mTimerIsRunning = true; 
      } 
     }); 

     // Get the "My Position" button. 
     mLocationButton = ((View) mSupportMapFragment.getView().findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2")); 
     RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) mLocationButton.getLayoutParams(); 

     Resources r = getActivity().getResources(); 
     int px = (int) TypedValue.applyDimension(
       TypedValue.COMPLEX_UNIT_DIP, 
       10, 
       r.getDisplayMetrics() 
     ); 

     // Position on right bottom. 
     rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0); 
     rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); 
     rlp.setMargins(0, 0, px, px); 

     turnOnMyLocation(); 
    } 

    @Override 
    public void onPause() { 
     super.onPause(); 

     // Stop location updates when Activity is no longer active. 
     if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { 
      LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); 
     } 

     mPetrolStationsArray.removePetrolStationListener(this); 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 

     mPetrolStationsArray.setPetrolStationsListener(this); 
    } 

    @Override 
    public void onListUpdated() { 
     // Cleaning all the markers. 
     if (mGoogleMap != null) { 
      mGoogleMap.clear(); 
     } 

     List<PetrolStation> petrolStationList = mPetrolStationsArray.getList(); 

     for (PetrolStation petrolStation : petrolStationList) { 
      double lat = petrolStation.getLat(); 
      double lon = petrolStation.getLon(); 
      String name = petrolStation.getName(); 

      if (mGoogleMap != null) { 
       mGoogleMap.addMarker(new MarkerOptions() 
         .position(new LatLng(lat, lon)) 
         .title(name)); 
      } 
     } 
    } 

    @Override 
    public void onServerRequest() { 

    } 

    @Override 
    public void onConnected(Bundle bundle) { 
     mLocationRequest = new LocationRequest(); 
     mLocationRequest.setInterval(1000); 
     mLocationRequest.setFastestInterval(1000); 
     mLocationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER); 

     if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { 
      LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); 
     } 
    } 

    @Override 
    public void onConnectionSuspended(int i) { 
     // TODO 
    } 

    @Override 
    public void onConnectionFailed(ConnectionResult connectionResult) { 
     // TODO 
    } 

    @Override 
    public void onLocationChanged(Location location) { 
     if (mCurrLocationMarker != null) { 
      mCurrLocationMarker.remove(); 
     } 

     // Just a check to overtake the 
     // 'java.lang.IllegalStateException: Fragment MapFragment{42f519d0} not attached to Activity' 
     // exception I've encountered. 
     if (!isAdded()) { 
      return; 
     } 

     // Stop location updates. 
     if (mGoogleApiClient != null) { 
      LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); 
     } 
    } 

    // Start the transaction between different fragments. 
    private void fragmentTransaction(FragmentManager mFragmentManager, Fragment fragment, int id, String tag) { 
     mFragmentTransaction = mFragmentManager.beginTransaction(); 
     mFragmentTransaction.add(id, fragment, tag); 
     mFragmentTransaction.commit(); 
     mFragmentManager.executePendingTransactions(); 
    } 


    /********************************************* 
    ************ LOCATION PERMISSIONS ************ 
    *********************************************/ 

    @Override 
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { 
     super.onRequestPermissionsResult(requestCode, permissions, grantResults); 

     switch (requestCode) { 
      case MY_PERMISSIONS_REQUEST_LOCATION: { 
       // If request is cancelled, the result arrays are empty. 
       if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
        turnOnMyLocation(); 
       } else { 
        // Permission denied, boo! Disable the functionality that depends on this permission. 
        String message = getResources().getString(R.string.permission_denied); 

        Snackbar snackbar = Snackbar 
          .make(mCoordinatorLayout, message, Snackbar.LENGTH_LONG) 
          .setAction(R.string.close_snack_bar, new View.OnClickListener() { 
           @Override 
           public void onClick(View view) { 

           } 
          }); 

        snackbar.show(); 
       } 
      } 
     } 
    } 

    // Ask for permission (START DIALOG) in Android APIs >= 23. 
    public boolean checkLocationPermission() { 
     if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
      // Should we show an explanation? 
      if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) { 
       // Prompt the user once explanation has been shown. 
       requestPermissions(new String[] { 
         Manifest.permission.ACCESS_FINE_LOCATION 
       }, MY_PERMISSIONS_REQUEST_LOCATION); 
      } else { 
       // No explanation needed, we can request the permission. 
       requestPermissions(new String[] { 
         Manifest.permission.ACCESS_FINE_LOCATION 
       }, MY_PERMISSIONS_REQUEST_LOCATION); 
      } 

      return false; 
     } else { 
      return true; 
     } 
    } 

    public void turnOnMyLocation() { 
     // Initialise Google Play Services. 
     if (mGoogleApiClient == null) { 
      buildGoogleApiClient(); 
     } 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { 
       mGoogleMap.setMyLocationEnabled(true); 
      } 
     } else { 
      mGoogleMap.setMyLocationEnabled(true); 
     } 
    } 

    // Let's build our Location Services API Client. 
    protected synchronized void buildGoogleApiClient() { 
     mGoogleApiClient = new GoogleApiClient 
       .Builder(getContext()) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(LocationServices.API) 
       .build(); 

     mGoogleApiClient.connect(); 
    } 

    public static void displayPromptToEnableGPS(final Activity activity) { 
     final AlertDialog.Builder builder = new AlertDialog.Builder(activity); 
     final String action = Settings.ACTION_LOCATION_SOURCE_SETTINGS; 
     final String message = MyFuelApp.getAppContext().getResources().getString(R.string.open_gps_settings); 

     builder.setMessage(message) 
       .setPositiveButton(MyFuelApp.getAppContext().getResources().getString(R.string.confirm_ok), 
         new DialogInterface.OnClickListener() { 
          public void onClick(DialogInterface d, int id) { 
           activity.startActivity(new Intent(action)); 
           d.dismiss(); 
          } 
         }) 
       .setNegativeButton(MyFuelApp.getAppContext().getResources().getString(R.string.deny_no), 
         new DialogInterface.OnClickListener() { 
          public void onClick(DialogInterface d, int id) { 
           d.cancel(); 
          } 
         }); 
     builder.create().show(); 
    } 

} 
+3

通常這是通過使用onRequestPermissionsResult函數完成的。 –

+0

我已經嘗試刷新我的_onRequestPermissionsResult_函數中的片段,但我無法真正瞭解如何進行片段刷新。任何提示? 謝謝你的回覆。 – Davide3i

+0

http://stackoverflow.com/questions/20702333/refresh-fragment-at-reload這可能有幫助 – Eenvincible

回答

0

一個解決方法就是問前打開MapFragment。這樣你只需要檢查你的片段是否有權限加載一個視圖或另一個視圖。 另一種方法是在方法turnOnMyLocation()中添加按鈕。

+0

我發現我的問題與這些人相同: https://code.google.com/p/android/issues/detail?&id=189121 – Davide3i

0

您可以使用

onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 

這個回調中,你應該檢查你同時請求允許與一個在參數傳遞的請求代碼的平等。如果匹配,則可以獲得用戶結果。

如果用戶允許的權限,那麼你可以簡單地分離和附加您片斷如下:

Fragment currentFragment = getFragmentManager().findFragmentByTag("FRAGMENT"); 
    FragmentTransaction fragTransaction = getFragmentManager().beginTransaction(); 
    fragTransaction.detach(currentFragment); 
    fragTransaction.attach(currentFragment); 
    fragTransaction.commit(); 

這是怎麼了你的片段將被重新加載,也是你的觀點得到刷新。我希望通過這個,你可以解決你的問題。

+0

我'我發現我的問題與這些人一樣: https://code.google.com/p/android/issues/detail?&id=189121 – Davide3i