为什么片段中的getContext()有时会返回null? [英] Why getContext() in fragment sometimes returns null?
问题描述
为什么getContext()
有时返回null
?我将上下文作为参数传递给LastNewsRVAdapter.java
.但是LayoutInflater.from(context)
有时会崩溃.我在Play控制台上收到了一些崩溃报告.下面是崩溃报告.
Why getContext()
sometimes returns null
? I pass context to LastNewsRVAdapter.java
as an argument. But LayoutInflater.from(context)
sometimes crashes. I'm getting a few crash reports on play console. Below is crash report.
java.lang.NullPointerException
com.example.adapters.LastNewsRVAdapter.<init>
java.lang.NullPointerException:
at android.view.LayoutInflater.from (LayoutInflater.java:211)
at com.example.adapters.LastNewsRVAdapter.<init> (LastNewsRVAdapter.java)
at com.example.fragments.MainFragment$2.onFailure (MainFragment.java)
or .onResponse (MainFragment.java)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run
(ExecutorCallAdapterFactory.java)
at android.os.Handler.handleCallback (Handler.java:808)
at android.os.Handler.dispatchMessage (Handler.java:103)
at android.os.Looper.loop (Looper.java:193)
at android.app.ActivityThread.main (ActivityThread.java:5299)
at java.lang.reflect.Method.invokeNative (Method.java)
at java.lang.reflect.Method.invoke (Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
(ZygoteInit.java:825)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:641)
at dalvik.system.NativeStart.main (NativeStart.java)
这是LastNewsRVAdapter.java
构造函数.
public LastNewsRVAdapter(Context context, List<LatestNewsData>
latestNewsDataList, FirstPageSideBanner sideBanner) {
this.context = context;
this.latestNewsDataList = latestNewsDataList;
inflater = LayoutInflater.from(context);
this.sideBanner = sideBanner;
}
这是片段内的代码onCreateView
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_main_sonku_kabar, container, false);
tvSonkuKabar = view.findViewById(R.id.textview_sonku_kabar_main);
tvNegizgiKabar = view.findViewById(R.id.textview_negizgi_kabar_main);
refresh(view);
final SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.mainRefreshSonkuKabar);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refresh(view);
swipeRefreshLayout.setRefreshing(false);
}
});
setHasOptionsMenu(true);
return view;
}
这是Fragment中的refresh
方法
This is refresh
method inside Fragment
private void refresh(final View view) {
sideBanner = new FirstPageSideBanner();
final RecyclerView rvLatestNews = (RecyclerView) view.findViewById(R.id.recViewLastNews);
rvLatestNews.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
rvLatestNews.setNestedScrollingEnabled(false);
App.getApiService().getLatestNews().enqueue(new Callback<LatestNews>() {
@Override
public void onResponse(Call<LatestNews> call, Response<LatestNews> response) {
if (response.isSuccessful() && response.body().isSuccessfull()){
adapter = new LastNewsRVAdapter(getContext(), response.body().getData(), sideBanner);
rvLatestNews.setAdapter(adapter);
tvSonkuKabar.setVisibility(View.VISIBLE);
}
}
@Override
public void onFailure(Call<LatestNews> call, Throwable t) {
}
});
推荐答案
First of all, as you can see on this link, the method onCreateView() inside the fragment's lifecycle comes after onAttach(), so you should have already a context at that point. You may wonder, why does getContext() return null then? the problem lies on where you are creating your adapter:
App.getApiService().getLatestNews().enqueue(new Callback<LatestNews>() {
@Override
public void onResponse(Call<LatestNews> call, Response<LatestNews> response) {
if (response.isSuccessful() && response.body().isSuccessfull()){
adapter = new LastNewsRVAdapter(getContext(), response.body().getData(), sideBanner);
rvLatestNews.setAdapter(adapter);
tvSonkuKabar.setVisibility(View.VISIBLE);
}
}
@Override
public void onFailure(Call<LatestNews> call, Throwable t) {
}
});
尽管您在onCreateView()中指定了回调,但这并不意味着该回调中的代码将在此时运行.网络调用完成后,它将运行并创建适配器.考虑到这一点,您的回调可能会在该片段的生命周期中的那一点之后运行.我的意思是,用户可以进入该屏幕(片段)并转到另一个片段,或者在网络请求完成(并且回调运行)之前返回到上一个片段.如果发生这种情况,那么如果用户离开该片段(可能已调用onDetach()),则getContext()可能返回null.
Though you are specifying a callback in onCreateView(), that does not mean the code inside that callback will run at that point. It will run and create the adapter after the network call is done. With that in mind, your callback may run after that point in the lifecycle of the fragment. What I mean is that the user can enter that screen (fragment) and go to another fragment or return to the previous one before the network request finishes (and the callback runs). If that happens, then getContext() could return null if the user leaves the fragment (onDetach() may have been called).
此外,如果活动在网络请求完成之前被破坏,则也可能会发生内存泄漏.所以那里有两个问题.
Besides, you can have memory leaks also, in case the activity is destroyed before your network request finishes. So you have two issues there.
我对解决这些问题的建议是:
My suggestions to solve those issues are:
-
为了避免出现空指针异常和内存泄漏,应在调用片段内的onDestroyView()时取消网络请求(retrofit返回可以取消请求的对象:链接).
另一个防止空指针异常的选项是将适配器LastNewsRVAdapter的创建移到回调之外,并在片段中保留对其的引用.然后,在回调中使用该引用来更新适配器的内容:链接
Another option that will prevent the null pointer exception is to move the creation of the adapter LastNewsRVAdapter outside the callback and keep a reference to it in the fragment. Then, use that reference inside the callback to update the content of the adapter: link
这篇关于为什么片段中的getContext()有时会返回null?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!