Toast crash during main thread execution - android

I've got a method test() that runs every 3 seconds in main thread using the following Runnable and Handler decleration:
private Runnable _checker = new Runnable() {
#Override
public void run() {
try {
test();
} finally {
if (!_stopTest) {
_testHandler.postDelayed(_checker, 3000);
}
}
}
};
This toast message runs on main thread during test() method:
Toast.makeText(getActivity(), "Recalculating...", Toast.LENGTH_SHORT).show();
ends up with exception:
04-02 09:56:44.229 31232-31232/com.app E/UncaughtException: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
at android.widget.Toast.<init>(Toast.java:105)
at android.widget.Toast.makeText(Toast.java:262)
at com.BaseSupportFragment.test(BaseSupportFragment.java:916)
The exception occurs during onBackPressed, which I override to remove the fragment container (which contains the fragment that should show the toast message that fails).
Does anybody know what happens here?

The exception occurs during onBackPressed.
Next time getActivity() is called it returns null, because your fragment currently is not attached to any activity. Thus crash happens.
In onBackPress() you have to cancel scheduled runnables:
_testHandler.removeCallbacks(_checker);

Related

App randomly crashes when starting background thread of a fragment

I have this code for my fragment:
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
txtAngle = view.findViewById(R.id.textView_angle);
updateTextThread = new Thread(new Runnable() {
#Override
public void run() {
while (threadRunning) {
txtAngle.setText("1");
}
}
});
threadRunning = true;
updateTextThread.start();
}
#Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
threadRunning = false;
}
The app works fine the first time I navigate to this fragment, but if I return to the main page and navigate to this fragment again, the app has a 30% chance to crash, throwing java.lang.NullPointerException: Attempt to invoke virtual method 'int android.text.Layout.getWidth()' on a null object reference for the setText line of the thread. I tried to use Thread.interrupt() to stop the thread but it didn't work.
So what caused the crash and how can I solve it?
You should take care ot two things here :
sharing a variable between two threads
updating UI out of the render thread / main thread
What you should do :
use thread safe variables like AtomicBoolean or a volatile boolean for the threadRunning var... and a double checked locking or a Lock for verifying the value of the var
without this you have no guarantee that you update thread loop is not before the setText method when changing the threadRunning var value...
also, you'd better call super.onDestroyView() at the end of the onDestroyView method.
What you could do :
Dispatch the TextView update from the update thread to the main thread using one of the following possibility (not exhaustive)
use a Handler associated with the main Looper
use a coroutine or rxJava to dispatch the work to the right thread

Using RunOnUIThread causing null pointer Exception After Switching to another Fragment

public class ViewPagerTask extends TimerTask {
#Override
public void run() {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (viewPager.getCurrentItem() == 0){
viewPager.setCurrentItem(1);
} else if (viewPager.getCurrentItem() == 1){
viewPager.setCurrentItem(2);
} else viewPager.setCurrentItem(0);
}
});
}
}
I'm using this code to change images in a view. But the problem is I'm using it in fragment and when I change the fragment and app runs for few seconds and then suddenly pop's null pointer error. Now What I understand the reason is that it tries to change the image but doesn't find the view and create this error I have no clue what to do. Please Help :)
Error
E/AndroidRuntime: FATAL EXCEPTION: Timer-0
Process: com.example.android.indianmetro, PID: 5150
java.lang.NullPointerException: Attempt to invoke virtual method 'void
android.support.v4.app.FragmentActivity.runOnUiThread(java.lang.Runnable)'
on a null object reference
at com.example.android.indianmetro.HomeFragment$ViewPagerTask.run(HomeFragment.java:258)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
E/AbstractTracker: Can't create handler inside thread that has not called
Looper.prepare()
The first, you should understand about threads in Android. In Android, we have a thread called MainUIThread. I'm not sure that's the main thread or not. However, It has an instance of Looper class.
Your fragment source basically runs on MainUIThread by default. When you create the sub-class of TimerTask, you are creating a new Runnable for run your source in another thread, is that right?
Your error message java.lang.NullPointerException means that the return value of getActivity() method are null. A good place to start is the JavaDocs. They have this covered:
Thrown when an application attempts to use null in a case where an object is required. These include:
Calling the instance method of a null object.
Accessing or modifying the field of a null object.
Taking the length of null as if it were an array.
Accessing or modifying the slots of null as if it were an array.
Throwing null as if it were a Throwable value.
Applications should throw instances of this class to indicate other illegal uses of the null object.
The solution for you:
Let check and make sure you are not finishing the Activity. (Another case that's you detach this Fragment of called Activity. Because you are using ViewPager, I guess that you are swipe two times to left or right. It automatically detach your fragment by default) Try to abandon it.
If you have to finish your Activity which contains your Fragment or has to detach your fragment. The easy way is checked null before call runOnUiThread() method.
public class ViewPagerTask extends TimerTask {
#Override
public void run() {
Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (viewPager.getCurrentItem() == 0) {
viewPager.setCurrentItem(1);
} else if (viewPager.getCurrentItem() == 1) {
viewPager.setCurrentItem(2);
} else {
viewPager.setCurrentItem(0);
}
}
});
}
}
}
Your TimerTask is fired after the fragment is removed. In that case, getActivity() will return null and hence the exception.
I can suggest two choices:
assign getActivity() output to a local var when TimeTask is fired, check and use if not null.
cancel your TimerTask in onDetach(). This is a recommended approach.

Error when using handlers Attempt to invoke virtual method 'boolean android.os.Handler.sendMessage

I am getting a
E/AndroidRuntime: FATAL EXCEPTION
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Handler.sendMessage(android.os.Message)' on a null object reference at com.example.android.slidenerd180handler.MainActivity$MyThread.run(MainActivity.java:37)
I am not sure why it is not working, I did everything that it said in this tutorial video on youtube for android handler, but it still doesn't work.
the line 37 is handler.sendMessage(message);
class MyThread implements Runnable {
#Override
public void run() {
for(int i =0;i<100;i++){
Message message = Message.obtain();
message.arg1=i;
handler.sendMessage(message);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
It does not work if you do not make sure that the Handler is initialized before you send a message.
For that, you can make your thread sleep for a few ms (like 2 ms) before sending the message. The fact is that when the UIThread is running thread.start(), the secondary thread (the one implementing Runnable) starts.
The loop in the run() method starts and the instruction handler.sendMessage(message) is executed by the secondary thread before the instruction handler = new Handler() can be read by the UIThread.
You can't be sure that it will always happens this way so you have to make sure the Handler is initialized first. You can put Thread.sleep(100); into the run() section of the secondary thread.
This error means that you are trying to send a message that is null. In other words, the message is empty. Check where you are obtaining the message and make sure that there is not a chance that the message will be null.
Before sending the message, you should add an if statement. Try replacing your code with this:
class MyThread implements Runnable {
#Override
public void run() {
for(int i =0;i<100;i++){
Message message = Message.obtain();
if(message != null){
message.arg1=i;
handler.sendMessage(message);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Hope this helps!
You are starting MyThread before handler is initialized(I guess from onCreate() of activity). Initialize handler before it MyThread executes.

Attempt to invoke virtual method 'boolean android.os.Handler.postDelayed(java.lang.Runnable, long)' on a null object reference

I was following this page Adding items to Endless Scroll RecyclerView with ProgressBar at bottom and I think I did everything right, but for some reason I get back on this line onLoadMoreListener.onLoadMore();
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Handler.postDelayed(java.lang.Runnable, long)' on a null object reference
I know that there are a lot of posts regarding the null pointer error, but that line is in a if statement and it shouldn't be executed if it's null.
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
Why is this happening ? What code should I post to help figuring out the problem ?
mAdapter.setOnLoadMoreListener(new MyAdapter.OnLoadMoreListener() {
#Override
public void onLoadMore() {
//add progress item
myDataset.add(null);
mAdapter.notifyItemInserted(myDataset.size() - 1);
handler.postDelayed(new Runnable() {
#Override
public void run() {
//remove progress item
myDataset.remove(myDataset.size() - 1);
mAdapter.notifyItemRemoved(myDataset.size());
MyRecyclerItems gridItem= new MyRecyclerItems();
gridItem.setAbout("Test");
gridItem.setEmail("tesssst#gmail.com");
myDataset.add(0,gridItem);
mAdapter.notifyItemInserted(myDataset.size());
mAdapter.setLoaded();
}
}, 2000);
System.out.println("load");
}
});
This error means handler is null.
Just initialize handler object before calling post method like this:
handler=new Handler();
As you pointed out the onLoadMoreListener field is not null based on the if statement. What you didn't include however is the code being executed inside the onLoadMore() method.
From the partial stack trace you are trying the call postDelayed(java.lang.Runnable, long) on a Handler inside the onLoadMore() method and said Handler has not been initialized (is null).

getActivity() throws Null pointer exception after restarting app

I have an Activity and inside that activity , in onCreate I am doing fragment transaction. The first time I open the app ,everything works fine. But if I minimize my app (Not close. just pressing home button) , browse through other apps and come back to my app , then it crashes in getActivity() call of one of the fragment. This is the fragment related code:
MenuLayout.java
public void startAnimation()
{
final Random random = new Random();
TimerTask animateTask = new TimerTask() {
#Override
public void run() {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
animateHandler(random.nextInt(SIZE*SIZE));
}
});
}
};
timer = new Timer();
timer.scheduleAtFixedRate(animateTask,1000,1500);
}
The above method is called in onCreateView.
It crashes in the getActivity() call inside the timer task. And yes, I do call timer.cancel in onPause().
Logcat:
06-28 22:33:06.136 31786-31809/sample.apps.sampleapp E/AndroidRuntime﹕ FATAL EXCEPTION: Timer-0
Process: sample.apps.sampleapp, PID: 31786
java.lang.NullPointerException
atsample.apps.sampleapp.MenuLayout$2.run(MenuLayout.java:155)
at java.util.Timer$TimerImpl.run(Timer.java:284)
Thank you.
Try this, it should work for you.
if(isAdded())//add this
animateHandler(random.nextInt(SIZE*SIZE));
Remove getActivity(). No need to add it as it is in onCreate().
Just call runUIOnThread() directly.

Categories

Resources