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.
Related
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
I tring to create an animation to my activity.
The animation working as it need to but it working only once.
Intent i = new Intent(a, UserDataActivity.class);
i.putExtra("userData", t);
a.startActivity(i);
a.overridePendingTransition(R.anim.spin_anim, R.anim.static_anim);
I starting the activity from other thread if it's matters.
a is a pointer to the main activity.
I know that the overridePendingTransition is working when calling the startActivity and the finish methods because of that I don't need to kill the calling acticity.
I solved the problem by running the code in the UI Thread
a.runOnUiThread(new Runnable()
{
#Override
public void run()
{
Intent i = new Intent(a, UserDataActivity.class);
// putting in the intent the user data
i.putExtra("userData", t);
a.startActivity(i);
a.overridePendingTransition(R.anim.spin_anim, R.anim.static_anim);
}
});
I would like if someone will explain me why this didn't work on other thread?
I have an Activity with 3 spinners. These spinners get their data from a web-service by a method that takes about 1 minute to be completed.
I want to load the Activity first and after it is made visible, call that web-service method and load data. I have tested the following codes separately but none of them solved my problem. In these samples application goes into a black screen and when the web-service operation completed, it is made visible.
#Override
protected void onCreate() {
//.........
final Runnable r = new Runnable()
{
public void run()
{
loadMyData();
}
};
Utilities.performOnBackgroundThread(r);
}
#Override
protected void onResume() {
new Thread() {
#Override
public void run() {
loadMyData();
}
}.start();
super.onResume();
}
#Override
protected void onStart() {
if (comesFromOnCreateMethod)
{
final Runnable r = new Runnable()
{
public void run()
{
loadMyData();
}
};
Utilities.performOnBackgroundThread(r);
}
comesFromOnCreateMethod = false;
super.onStart();
}
#Override
protected void onResume() {
if (comesFromOnCreateMethod)
{
final Runnable r = new Runnable()
{
public void run()
{
loadMyData();
}
};
Utilities.performOnBackgroundThread(r);
}
comesFromOnCreateMethod = false;
}
If you are getting a black screen, then I would assume your code is being run on the UI thread and not on the background, causing the UI to hang until the work is completed.
One of the best solutions to doing background work is an AsyncTask. Using this, you can call it in your onCreate() method, and when its done, it will post a callback to the UI thread for you in which you can display you data.
If you want this method to run everytime this Activity displays, then call it in onResume(). Otherwise, call it in onCreate().
In your onCreate, make the async tasks as the others have advised. Make sure you generate the content for the app first and then call the asyncTasks. You can control your spinners from the callback.
First of all, you might want to increase your accept rate, 39% is pretty low.
Anyway, you might want to check AsyncTask, it should do the thing. http://developer.android.com/reference/android/os/AsyncTask.html
Typically, you will want to initialize in onPreExecute, do the networking in the doInBackGround, and set the result to the UI thread on the OnPostExecute. Hope this will help.
Use AssynchTask() and you should call super.onResume() or any lifecycle method in respective life cycle method first then other specific method you want to do....
I understand what the CalledFromWrongThreadException exception means, but I cannot comprehend how the code I have written isn't executing on the uithread in this situation.
In my main activity I create a handler.
private final Handler handler = new AppHandler(this);
In the onCreateDialog method of the activity, I was using the constructor suggested by the android examples of timepicker dialogues. Since I was getting the CalledFromWrongThreadException in a way I didn't understand and wasn't reproducible on my devices or the emulator, I tried to pass a reference of my activity in to the create dialogue constructor.
So my code to create the dialog looks like this.
#Override
protected Dialog onCreateDialog(int id) {
final Calendar c = Calendar.getInstance();
switch (id) {
case TIME_DIALOG_ID:
return new TimePickerDialog(this, this, getHandler(),
mTimeSetListener, c.get(Calendar.HOUR_OF_DAY),
0, false);
The first instance of "this" gets used as a Context by the dialog, the second instance gets stored off as an Activity.
The dialog itself is the android sample code but I have been attempting to fix the threading problems I'm seeing.
Then inside of the dialog where I am having threading issues. I use the main activity and try to use its handler to execute the setTitle command as a runnable.
mainactivity.getHandler().post(new Runnable() {
public void run() {
setTitle(mDateFormat.format(mCalendar.getTime()));
}
});
Edit: Changing the code so that the attempt to run on the ui thread is using the method on the main activity instead of the handler produces the same results.
mainactivity.runOnUiThread(new Runnable() {
public void run() {
setTitle(mDateFormat.format(mCalendar.getTime()));
}
});
Here's a copy of a stacktrace:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:3214)
at android.view.ViewRoot.invalidateChild(ViewRoot.java:681)
at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:707)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511)
at android.view.View.invalidate(View.java:5418)
at android.widget.TextView.checkForRelayout(TextView.java:5750)
at android.widget.TextView.setText(TextView.java:2866)
at android.widget.TextView.setText(TextView.java:2727)
at android.widget.TextView.setText(TextView.java:2696)
at com.android.internal.app.AlertController.setTitle(AlertController.java:222)
at android.app.AlertDialog.setTitle(AlertDialog.java:100)
at com.testapp.TimePickerDialog$1.run(TimePickerDialog.java:159)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
at dalvik.system.NativeStart.main(Native Method
Also note that I use this same handler all over my app to successfully execute things on the UI thread.
Any suggestions on other approaches I might try or tips to debug this would be greatly appreciated.
Thanks!
Use
runOnUiThread(new Runnable() {
#Override
public void run() {
//UI CODES
}});
Edit
I think u should deal the DialogClass as innerclass for mainActivity,then just call runOnUiThread
Hope this may help you
In the end the issue is that I was calling showDialog() from a thread that was not the ui thread.
I figured out the issue when reading android dev blog on memory leaking and realized that I had passed a handle to the activity beyond where it should be.
I'm now calling showDialog() from inside of the runOnUiThread of the main activity as sonu pointed out and everything seems to be working.
I want to refresh the activity as i want thatwithout firing any event some work gets performed and activity calls by itself. So, i want to know is there any option in android to refresh the activity by itself.
You can do this by yourself through a Handler on which you call postDelayed(..)
http://developer.android.com/reference/android/os/Handler.html#postDelayed(java.lang.Runnable, long)
Put this in your class:
private final Handler handler = new Handler();
make a function called: doTheAutoRefresh() that does:
private void doTheAutoRefresh() {
handler.postDelayed(new Runnable() {
#Override
public void run() {
doRefreshingStuff(); // this is where you put your refresh code
doTheAutoRefresh();
}
}, 1000);
}
Call this function in your onCreate.
NOTE: this is the basic approach. consider stopping this after onPause has been called and to resume it after onResume. Look at the handler class to see how to remove.
You can create a thread and and call the refresh() with the task you want to refresh
for other questions I've pulled the most effective ways to do this are:
finish();startActivity(getIntent());
OR
// Refresh main activity upon close of dialog box
Intent refresh =new Intent(this, ActivityWeAreIn.class);
startActivity(refresh);
Note: this also works with Activity objects or from Fragments using getActivity()