I recently replaced all the deprecated AsyncTask code in my apps with handlers and newSingleThreadExecutors. After retrieving response data from a remote server, I update the UI in the handler.post section of the code.
I've never personally been able to reproduce any problems with this, but on some devices (mostly oppo's, redmi's, vivo's, etc) under some real-world conditions, getView() returns null and my stop-gap attempt to re-inflate the view fails. The number of crashes has increased by a lot:
Exception java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
Rough outline of my code:
public class ResultFragment extends Fragment {
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.result, container, false);
}
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
Bundle bundle = this.getArguments();
assert bundle != null;
String query_url = bundle.getString("query_url");
send_request(query_url);
}
void send_request(String... urls) {
Handler handler = new Handler(Looper.getMainLooper());
Executors.newSingleThreadExecutor().execute(() -> {
.....
handler.post(() -> {
context = getContext();
final TextView mTextView;
final WebView mWebView;
if (getView() != null) {
mTextView = getView().findViewById(R.id.count);
mWebView = getView().findViewById(R.id.result);
} else {
View view = LayoutInflater.from(context).inflate(R.layout.result, null); <-- crash
mTextView = view.findViewById(R.id.count);
mWebView = view.findViewById(R.id.result);
}
My understanding from the lifecycle documentation is that I should be able to get the view with this code. And I do understand that trying to re-inflate the code like this is a dangerous proposition (crashes might occur!). But how do I do so when getView() returns null?
As I say, I've never been able to replicate these crashes. So I'm open to trying anything that might work.
For general information, I'm targeting sdk version 33.
You wouldn't do this at all. If you don't have a view, reinflating it isn't going to do what you expect. It would, at best, create a new set of views that are in memory only and not displayed on the screen. In other words it would be pointless.
Also, that's not what your problem is. You problem is that the context is null. Your fragment isn't attached to any. In this case, what you probably want to do is update any persisted state (if any) and skip updating the UI.
Also, if you're inflating your UI normally on an excutor that then posts to a handler- stop. THat's not how it works. THe inflation should happen in the onCreateView function. You can fill in the views like that, but you would NEVER inflate them like that.