【问题标题】:Why is getcontext() null only in one method?为什么 getcontext() 仅在一种方法中为空?
【发布时间】:2018-06-05 00:51:28
【问题描述】:

您好,我正在制作一个位于 Android Studio 抽屉活动中的地图应用程序,一切都很顺利,直到我开始玩片段,因为我是 android 的新手,我真的不知道发生了什么或问题的原因是什么。

我用地图布局替换了主布局,使其成为我的“家”布局。然后我添加了一个片段,我可以在其中更改名为“配置”的应用程序的语言,并在抽屉菜单上按下“配置”按钮时调用该片段。

我注意到即使配置片段替换了地图布局,地图片段中的一些定位方法在后台仍然处于活动状态,我知道这是因为每次应用程序检查权限或更改位置时都会显示 Toast 消息这样做是为了视觉辅助,所以我知道它的工作原理。

在两种情况下,我的应用程序在同一行代码中因相同的错误而崩溃,而这恰好是我作为帮助而放在那里的祝酒词之一。这对我来说很奇怪,因为所有其他 toast 都工作正常,因为消息正在显示,但是当它在 onLocationChanged 方法到达特定 toast 时,会显示下一个错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
    at android.widget.Toast.<init>(Toast.java:114)
    at android.widget.Toast.makeText(Toast.java:277)
    at android.widget.Toast.makeText(Toast.java:267)
    at com.tesseract.psiclops.zerov2.mapFragment.onLocationChanged(mapFragment.java:172)
    at com.google.android.gms.internal.location.zzay.notifyListener(Unknown Source:4)
    at com.google.android.gms.common.api.internal.ListenerHolder.notifyListenerInternal(Unknown Source:8)
    at com.google.android.gms.common.api.internal.ListenerHolder$zza.handleMessage(Unknown Source:16)
    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)

所以触发错误的两件事是:

1.- 当我按下后退按钮并且后台堆栈中没有片段(我想)所以它隐藏(关闭?最小化?)应用程序然后我再次打开它......它崩溃了。

2.- 当我进入我的配置片段并更改语言时。注意:我用来更改语言的方法会重新启动活动,因此会显示语言的更改。

我认为,由于我正在关闭应用程序,同时按下后退按钮或调用我的 languaje 方法,因此 getcontext() 在此之后变为 null 是有道理的,但为什么其他 toasts 显示消息并且只在该特定行崩溃?还是具体方法?以及如何防止这种情况发生??

注意:当我注释掉 toast 时,一切正常,没有崩溃或任何事情:S,我真的需要了解发生了什么,以便以后防止出现任何问题。

地图片段:

    public class mapFragment extends Fragment implements OnMapReadyCallback, LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

private  GoogleMap mMap;
private GoogleApiClient mApiClient;
private Context mContext;

private OnFragmentInteractionListener mListener;

public mapFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_map, container, false);
}

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


 // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment)getChildFragmentManager()
            .findFragmentById(R.id.map1);
    mapFragment.getMapAsync(this);

}

private void SetSancrisM(final GoogleMap mMap) {

    // Add a marker in Sancris and move the camera

   // LatLng sancris = new LatLng(16.736380, -92.638795);
    LatLngBounds SanCris = new LatLngBounds(new LatLng(16.720215, -92.684189), new LatLng(16.749950, -92.596649));


    //mMap.addMarker(new MarkerOptions().position(sancris).title("Marker in Sancris"));
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SanCris.getCenter(), 16));
    //mMap.setLatLngBoundsForCameraTarget(SanCris);


}



@Override
public void onMapReady(GoogleMap googleMap) {

    mMap = googleMap;
    mMap.getUiSettings().setZoomControlsEnabled(true);

    try {
        // Customise the styling of the base map using a JSON object defined
        // in a raw resource file.
        boolean success = googleMap.setMapStyle(
                MapStyleOptions.loadRawResourceStyle(getContext(), R.raw.style_json));

        if (!success) {
            Toast.makeText(mContext, "Chido3", Toast.LENGTH_SHORT).show();
        }
    } catch (Resources.NotFoundException e) {
        Toast.makeText(mContext, "No cargó el styla", Toast.LENGTH_SHORT).show();
    }

    //Calls the function that moves the cam to Sancris
    SetSancrisM(mMap);


    //Location permission conditions

    if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

        Toast.makeText(mContext, "Failed to get location permission", Toast.LENGTH_SHORT).show();
        ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 200);
        return;

    } else {

        if (!mMap.isMyLocationEnabled()) {
            mMap.setMyLocationEnabled(true);
            Toast.makeText(mContext, "Chido", Toast.LENGTH_SHORT).show();

        }

    }


    mApiClient = new GoogleApiClient.Builder(getContext())
            .addApi(LocationServices.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

    mApiClient.connect();


}


@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case 200: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(mContext, "Failed to get permission 2", Toast.LENGTH_SHORT).show();

                } else {
                    mMap.setMyLocationEnabled(true);
                    Toast.makeText(mContext, "Chido2", Toast.LENGTH_SHORT).show();

                }
            }
        }
    }
}



@Override
public void onLocationChanged(Location location) {
    if(location==null){
        Toast.makeText(mContext, "No Location 4", Toast.LENGTH_SHORT).show();
    }else{
        LatLng ll= new LatLng(location.getLatitude(), location.getLongitude());
        CameraUpdate update= CameraUpdateFactory.newLatLngZoom(ll,mMap.getCameraPosition().zoom);
        mMap.animateCamera(update);

        Toast.makeText(mContext, "Chido4", Toast.LENGTH_SHORT).show(); //This one right here is the one not working
        }

}

LocationRequest mLocReq;

@Override
public void onConnected(@Nullable Bundle bundle) {

    mLocReq = LocationRequest.create();
    mLocReq.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocReq.setInterval(1000);

    if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 200);
        return;
    }
    LocationServices.FusedLocationApi.requestLocationUpdates(mApiClient, mLocReq, this);

    Toast.makeText(mContext, "Chido5", Toast.LENGTH_SHORT).show();

}







@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

}







//Este código tiene que ver con la comunicación entre fragmentos y actividades, osea déjalo para después


// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
}


@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof OnFragmentInteractionListener) {
        mListener = (OnFragmentInteractionListener) context;
    } else {
        throw new RuntimeException(context.toString()
                + " must implement OnFragmentInteractionListener");
    }
    mContext=context;
}

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}




/**
 * This interface must be implemented by activities that contain this
 * fragment to allow an interaction in this fragment to be communicated
 * to the activity and potentially other fragments contained in that
 * activity.
 * <p>
 * See the Android Training lesson <a href=
 * "http://developer.android.com/training/basics/fragments/communicating.html"
 * >Communicating with Other Fragments</a> for more information.
 */
public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
}
}

在 onLocationChanged 方法中不起作用的 toast

@Override
public void onLocationChanged(Location location) {
    if(location==null){
        Toast.makeText(getContext(), "No Location 4", Toast.LENGTH_SHORT).show();
    }else{
        LatLng ll= new LatLng(location.getLatitude(), location.getLongitude());
        CameraUpdate update= CameraUpdateFactory.newLatLngZoom(ll,mMap.getCameraPosition().zoom);
        mMap.animateCamera(update);

        Toast.makeText(getContext(), "Good4", Toast.LENGTH_SHORT).show(); //This one right here is the one not working
        }

}

mapfragment 方法中的所有其他 toast 工作正常。

如果您需要更多代码,请在此处询问我,我会为您添加。提前非常感谢您!

【问题讨论】:

  • 是否真的需要所有代码来重现问题?请阅读minimal reproducible example,尽量减少压力。
  • 哦,对不起,我只是想把所有的信息都放在这里,如果有人问我,我会编辑,然后添加更多代码,谢谢!
  • 我认为您误解了我的评论。您的代码仍然需要完整。这次编辑实际上使情况变得更糟,因为现在绝对没有关于正在发生的事情的信息。请仔细阅读minimal reproducible example,并创建一个实际上完整的示例。
  • 基本上,我们希望您做好调试代码的基础工作,并将问题缩小到重现代码所需的绝对最低限度。我的建议是创建一个新项目并添加/删除部分代码,直到您可以用最少的代码重现问题。这有两个原因: 1.您很有可能通过这样做自己找到原因和解决方案。 2. 发布这样一个缩小示例的问题时,其他用户不必都做基础工作,从而可以更快更有效地帮助您。

标签: java android google-maps android-fragments drawerlayout


【解决方案1】:

在 Fragment 中声明 Context 变量

private Context mContext;

从 onAttach() 初始化它

 @Override
 public void onAttach(Context context) {
 super.onAttach(context);
 mContext = context;

}

你的吐司会是

  Toast.makeText(mContext,getString(R.string.toast) , Toast.LENGTH_LONG).show();

【讨论】:

  • 哇,你做到了!它现在工作!你愿意解释为什么会这样吗?我应该把我所有的“getcontext()”改成一个变量吗?
  • 片段的生命周期工作方式不同,要获得执行此操作所需的上下文或调用 getApplicationContext() 如果它对您有用,您可以接受我的回答。
  • 如果这对你有用,那么你绝对只是在泄露你的上下文并且让你的 LocationListener 比你的 Fragment 存活的时间更长。
  • 我会接受它,尽管我仍然怀疑为什么特定吐司会崩溃而不是其他吐司……
  • @ianhanniballake 我想我完全是这样做的,你能指出一些我可以阅读的文档来避免这种情况吗?或者你愿意解释一下吗?这里是菜鸟,谢谢!
【解决方案2】:

getContext() 仅在 Fragment 附加到其包含的 Activity 时返回非空值 - 在 onAttach()onDetach() 之间。如果您有在这些事件之外发生的回调,那么您没有适当地清理您的侦听器。

您应该创建您的侦听器(即调用requestLocationUpdates())的最早时间是在onAttach()

然后,您必须在 onDetach() 中取消注册您的侦听器(即调用 removeUpdates()),以防止泄露您的 LocationListener 和整个 Fragment。

通常,您应该只在您的 Fragment 在屏幕上可见时才请求更新。在这种情况下,您将在onStart() 注册并在onStop() 取消注册。

【讨论】:

  • 非常感谢!这给了我更多的视角,我想我知道如何寻找我现在需要的信息,感谢它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-27
  • 2021-03-01
  • 2021-04-24
  • 2012-03-25
  • 1970-01-01
  • 2021-09-15
相关资源
最近更新 更多