App randomly crashes when starting background thread of a fragment - android

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

Related

Why non UI thread can modify UI?

Yes, it shouldn't but the thread i made in my mainActivity in onCreate can modify UI, like this :
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
someTextview.setText("Hello");
}
});
thread.start();
I'm using android studio 2.2.2 .
Short answer: you can do it as long as you do it before the mainthread enter onResume()
Detail:
Usually you get a error like this when modifying UI from non UI thread
android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
and this exception is throwed here in the ViewRootImpl class
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
the mThread is the main thread. After the ViewRootImpl instance is created, UI modify opertations will need to check thread.
So when did the ViewRootImpl instance is created?
android.view.WindowManagerImpl.java
#Override
public void addView(#NonNull View view, #NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
android.view.WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
...
root = new ViewRootImpl(view.getContext(), display);
...
}
So when did the addView method is called?
android.app.ActivityThread.java
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
}
.
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
...
case RESUME_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
SomeArgs args = (SomeArgs) msg.obj;
handleResumeActivity((IBinder) args.arg1, true, args.argi1 != 0, true,
args.argi3, "RESUME_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
((SomeArgs) obj).recycle();
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
here you can see the ViewRootImpl instance is created around RESUME_ACTIVITY event, so before the main thread handles the resume event, you are allowed to modify UI from other threads. you just need to be quick.
It is not recommended to do that though.
Why non UI thread can modify UI?
Technically, a non UI thread can do that. But it is a really bad idea.
Why?
Because there are all sorts of problems with thread-safety if you do that. The UI framework is designed on the assumption that it can access the UI data structures without synchronization. (This simplifies things immensely, and removes the possibility of deadlocks between UI and non-UI threads ... which are next to impossible for a mortal programmer to anticipate.)
This can result in the worst kind of bugs; i.e. the ones that you can't test for, and you can't reproduce reliably ... or at all ... on your hardware.
The Android framework tries to protect you from doing this kind of thing to yourself ...
If you want to modify UI on Non-UI thread, you can do it via
Activity.runOnUIThread()
Runnable
View.Post(Runnable)
AsyncTask
In your code, you are using Activity.runOnUIThread()
Do a look at https://developer.android.com/guide/components/processes-and-threads.html
you can not update the UI from any thread other than the UI thread or the "main" thread.
only using :
Activity.runOnUIThread(runnable)
View.Post(Runnable), view.postDelayed()
AsyncTask
the important question is why your code is modifying the UI?
probably, you are starting the Thread from the onCreate(). if you tried to run this thread inside a Button onClick() for example, your app will crash throwing
CalledFromWrongThreadException

What exactly does the post method do?

I've encountered a very weird feature.
When I'm trying to run an animation on the main thread, it does not start.
When I run said animation using
getView().post(new Runnable() {
#Override
public void run() {
getView().startAnimation(a);
}
});
It does start.
I've printed the CurrentThread before starting the animation and both print main.
Obviously, I am missing something here, as both should start the animation on the main thread...
My guess is that as post adds the task to the queue, it starts at a more "correct time", but I would love to know what happens here at more depth.
EDIT:
Let me clear things up - my question is, why starting the animation on post causes it to start, when starting the animation on the main thread does not.
post :post causes the Runnable to be added to the message queue,
Runnable : Represents a command that can be executed. Often used to run code in a different Thread.
run () : Starts executing the active part of the class' code. This method is called when a thread is started that has been created with a class which implements Runnable.
getView().post(new Runnable() {
#Override
public void run() {
getView().startAnimation(a);
}
});
code : getView().startAnimation(a);
in your code,
post causes the Runnable (the code will be run a in different thread) to add the message queue.
So startAnimation will be fired in a new thread when it is fetched from the messageQueue
[EDIT 1]
Why do we use a new thread instead of UI thread (main thread)?
UI Thread :
When application is started, Ui Thread is created automatically
it is in charge of dispatching the events to the appropriate widgets
and this includes the drawing events.
It is also the thread you interact with Android widgets with
For instance, if you touch the a button on screen, the UI thread
dispatches the touch event to the widget which in turn sets its
pressed state and posts an invalidate request to the event queue. The
UI thread dequeues the request and notifies the widget to redraw
itself.
What happens if a user press a button which will do longOperation ?
((Button)findViewById(R.id.Button1)).setOnClickListener(
new OnClickListener() {
#Override
public void onClick(View v) {
final Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
});
The UI freezes. The program may even crash.
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
}).start();
}
It breaks the android rule that never update UI directly from worker thread
Android offers several ways to access the UI thread from other threads.
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Handler
Like below,
View.post(Runnable)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
}
}).start();
}
Handler
final Handler myHandler = new Handler(Looper.getMainLooper());
(new Thread(new Runnable() {
#Override
public void run() {
final Bitmap b = loadImageFromNetwork();
myHandler.post(new Runnable() {
#Override
public void run() {
mImageView.setImageBitmap(b);
}
});
}
})).start();
}
For more info
http://android-developers.blogspot.com/2009/05/painless-threading.html
http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/
Is this being done on onCreate or onCreateView? If so, the app might not be in a state where the View is attached to the window. A lot of algorithms based on View metrics may not work since things like the View's measurements and position may have not been calculated. Android animations typically require them to run through UI math
View.post actually queues the animation on the View's message loop, so once the view gets attached to the window, it executes the animation instead of having it execute manually.
You are actually running things on the UI thread, but at a different time
Have a look here for a good answer. view.post() is the same as handler.post() pretty much. It goes into the main thread queue and gets executed after the other pending tasks are finished. If you call activity.runOnUiThread() it will be called immediately on the UI thread.
The problem I think could be the life-cycle method where you are calling the post() method. Are you doing it in onCreate()? if so look at what I found in the activity's onResume() documentation:
onResume()
Added in API level 1 void onResume () Called after
onRestoreInstanceState(Bundle), onRestart(), or onPause(), for your
activity to start interacting with the user. This is a good place to
begin animations, open exclusive-access devices (such as the
camera), etc.
https://developer.android.com/reference/android/app/Activity.html#onResume()
So, as Joe Plante said, maybe the view is not ready to start animations at the moment you call post(), so try moving it to onResume().
PD: Actually if you do move the code to onResume() then I think you can remove the post() call since you are already in the ui-thread and the view should be ready to start animations.

Stop Previously running thread which was created in previous class in android

I just need to stop a thread which was created in previous run time of the same application. This is the scenario. I'm retrieving data from database for the notification using thread in background, But when I start that application again, number of threads are increasing. I need to stop this. I think its better to stop the background running thread in onCreate() method of the application's main class. But noway to do it. Please help me on this thing as soon as possible.
Thanks and Best Regards,
Shehan.
Keep a static reference to the running Thread in your activity class. Inside your thread you need to have a boolean variable you can set or a method you can call that will cause your thread to complete. In onCreate() you can check if you have a running thread, and if so, tell it to stop. Here's a code example:
In your activity:
private static Thread myThread;
In your activity, when you create the thread:
if (myThread != null) {
if (myThread.isAlive()) {
myThread.running = false; // Tell the thread to stop running now
}
}
myThread = new Thread(...);
myThread.start();
In your thread:
public boolean running = true; // Initator of this thread should set this to false to make the thread complete
public void run() {
while (running) {
// do whatever your thread does in a loop
}
}
You can stop the ruuning threads onDestroy() of activity.
please find the below eg:
static boolean stopThread=false;
public myThread implements Ruunable{
public void run(){
while(true){
//your logic
if(stopThread)
break;
}
}
#Override
protected void onDestroy()
{
stopThread=true;
}

Android: CalledFromWrongThreadException thrown when broadcast intent is handled

Here is the basic life cycle of my application. It targets SDK version 8 by now, since I am still running Android 2.3.3 on my device.
The application starts, onResume() is called
The method show() is called to display cached data.
A background service gets started which downloads and stores data. It uses AsyncTask instances to accomplish its work.
One of the tasks stores downloaded data in a SQLite database.
A broadcast intent is sent in onPostExecute() when the storing task has finished.
The MapActivity receives the intent and handles it.
The method show() is called to display cached and new data.
Within the method show() the map view gets invalidated after the overlay has been added. This works fine when show() has been called from the MapActivity itself. It raises an exception, however, when the asynchonous task is the source of the method call (indirectly).
As far as I understand, I am at the UI thread when I trigger show() in both cases. Is this true?
public class CustomMapActivity extends MapChangeActivity {
private boolean showIsActive = false;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(IntentActions.FINISHED_STORING)) {
onFinishedStoring(intent);
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerReceiver(mReceiver, new IntentFilter(IntentActions.FINISHED_STORING));
}
#Override
protected void onResume() {
super.onResume();
show();
}
#Override
protected void onMapZoomPan() {
loadData();
show();
}
#Override
protected void onMapPan() {
loadData();
show();
}
#Override
protected void onMapZoom() {
loadData();
show();
}
private void onFinishedStoring(Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
boolean success = extras.getBoolean(BundleKeys.STORING_STATE);
if (success) {
show();
}
}
private void loadData() {
// Downloads data in a AsyncTask
// Stores data in AsyncTask
}
private void show() {
if (showIsActive) {
return;
}
showIsActive = true;
Uri uri = UriHelper.getUri();
if (uri == null) {
showIsActive = false;
return;
}
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
List<Overlay> mapOverlays = mapView.getOverlays();
CustomItemizedOverlay overlay = ItemizedOverlayFactory.getCustomizedOverlay(this, cursor);
if (overlay != null) {
mapOverlays.clear();
mapOverlays.add(overlay);
}
}
cursor.close();
mapView.invalidate(); // throws CalledFromWrongThreadException
showIsActive = false;
}
}
Here is the stack trace ...
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:3020)
at android.view.ViewRoot.invalidateChild(ViewRoot.java:647)
at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:673)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511)
at android.view.View.invalidate(View.java:5332)
at info.metadude.trees.activities.CustomMapActivity.showTrees(CustomMapActivity.java:278)
at info.metadude.trees.activities.CustomMapActivity.onMapPan(CustomMapActivity.java:126)
at info.metadude.trees.activities.MapChangeActivity$MapViewChangeListener.onChange(MapChangeActivity.java:50)
at com.bricolsoftconsulting.mapchange.MyMapView$1.run(MyMapView.java:131)
at java.util.Timer$TimerImpl.run(Timer.java:284)
Note: I use the MapChange project in order to receive notifications on map events.
EDIT:
From what I now read in the documentation about AsyncTask (scroll down a bit), I am not sure if I use it the correct way. As previously mentioned I start AsyncTask instances from within a Service class. In contrary, the documentation states ...
AsyncTask allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.
... which sounds as if AsyncTask should only be used within an Activity not within a Service?!
The reason for your crash is because of the way that the MapChange library you are using is implemented. Under the hood, this library uses Timer and TimerTask implementations to delay firing the change event and reduce the number of calls your application gets to onMapChanged(). However, you can see from the docs on Timer that it runs its tasks in created threads:
Each timer has one thread on which tasks are executed sequentially. When this thread is busy running a task, runnable tasks may be subject to delays.
Since the MapChange library does nothing to ensure that callbacks are posted to your application on the main thread (a serious bug IMO, especially on Android), you have to protect the code you call as a result of this listener. You can see this in the example MyMapActivity bundled with the library, everything from that callback gets funneled through a Handler which posts the calls back to the main thread for you.
In your application, the code inside onMapPan() and subsequently showTrees() is being called on a background thread so it is not safe to manipulate the UI there. Using either a Handler or runOnUiThread() from your Activity will guarantee your code is called in the right place.
With regards to your second questions about AsyncTask, there is nothing stopping you from using it inside of any application component, not just Activity. Even though it's a "background" component, by default a Service is still running on the main thread as well, so AsyncTask is still necessary to offload long-term processing to another thread temporarily.
If it's getting called on the wrong thread, then it's likely not on the UI thread. Have you tried this:
runOnUiThread(new Runnable() {
public void run() {
mapView.invalidate();
}});

Android - Best and safe way to stop thread

I want to know which is the best way to stop a thread in Android. I know I can use AsyncTask instead of it and that there is a cancel() method. I have to use Threads in my situation. Here is how I'm using Thread:
Runnable runnable = new Runnable() {
#Override
public void run() {
//doing some work
}
};
new Thread(runnable).start();
So, does anyone have any idea of which is the best way to stop a thread?
You should make your thread support interrupts. Basically, you can call yourThread.interrupt() to stop the thread and, in your run() method you'd need to periodically check the status of Thread.interrupted()
There is a good tutorial here.
This situation isn't in any way different from the standard Java. You can use the standard way to stop a thread:
class WorkerThread extends Thread {
volatile boolean running = true;
public void run() {
// Do work...
if (!running) return;
//Continue doing the work
}
}
The main idea is to check the value of the field from time to time. When you need to stop your thread, you set running to false. Also, as Chris has pointed out, you can use the interruption mechanism.
By the way, when you use AsyncTask, your apporach won't differ much. The only difference is that you will have to call isCancel() method from your task instead of having a special field. If you call cancel(true), but don't implement this mechanism, the thread still won't stop by itself, it will run to the end.
On Android the same rules apply as in a normal Java environment.
In Java threads are not killed, but the stopping of a thread is done in a cooperative way. The thread is asked to terminate and the thread can then shutdown gracefully.
Often a volatile boolean field is used which the thread periodically checks and terminates when it is set to the corresponding value.
I would not use a boolean to check whether the thread should terminate. If you use volatile as a field modifier, this will work reliable, but if your code becomes more complex, for instead uses other blocking methods inside the while loop, it might happen, that your code will not terminate at all or at least takes longer as you might want.
Certain blocking library methods support interruption.
Every thread has already a boolean flag interrupted status and you should make use of it. It can be implemented like this:
public void run() {
try {
while(!Thread.currentThread().isInterrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Source code taken from Java Concurrency in Practice. Since the cancel() method is public you can let another thread invoke this method as you wanted.
There is also a poorly named static method interrupted which clears the interrupted status of the current thread.
The Thread.stop() method that could be used to stop a thread has been deprecated; for more info see; Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?.
Your best bet is to have a variable which the thread itself consults, and voluntarily exits if the variable equals a certain value. You then manipulate the variable inside your code when you want the thread to exit. Alternately of course, you can use an AsyncTask instead.
Currently and unfortunately we can't do anything to stop the thread....
Adding something to Matt's answer we can call interrupt() but that doesn't stop thread... Just tells the system to stop the thread when system wants to kill some threads. Rest is done by system, and we can check it by calling interrupted().
[p.s. : If you are really going with interrupt() I would ask you to do some experiments with a short sleep after calling interrupt()]
Try Like this
Thread thread = new Thread() {
#Override
public void run() {
Looper.prepare();
while(true){
Log.d("Current Thread", "Running");
try{
Thread.sleep(1000);
}catch(Exeption exception){ }
}
}
};
thread.start();
thread.interrupt();
There are 2 following ways preferred to stop a thread.
Create a volatile boolean variable and change its value to false and check inside the thread.
volatile isRunning = false;
public void run() {
if(!isRunning) {return;}
}
Or you can use the interrupt() method which can be receive inside a thread.
SomeThread.interrupt();
public void run() {
if(Thread.currentThread.isInterrupted()) {return;}
}
I used this method.
Looper.myLooper().quit();
you can try.
The thing is you need to check whether the thread is running or not !?
Field:
private boolean runningThread = false;
In the thread:
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Thread.sleep((long) Math.floor(speed));
if (!runningThread) {
return;
}
yourWork();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
If you want to stop the thread you should make the below field
private boolean runningThread = false;
My requirement was slightly different than the question, still this is also a useful way of stopping the thread to be executing its tasks. All I wanted to do is to stop the thread on exiting the screen and resumes while returning to the screen.
As per the Android docs, this would be the proposed replacement for stop method which has been deprecated from API 15
Many uses of stop should be replaced by code that simply modifies some
variable to indicate that the target thread should stop running. The
target thread should check this variable regularly, and return from
its run method in an orderly fashion if the variable indicates that it
is to stop running.
My Thread class
class ThreadClass implements Runnable {
...
#Override
public void run() {
while (count < name.length()) {
if (!exited) // checks boolean
{
// perform your task
}
...
OnStop and OnResume would look like this
#Override
protected void onStop() {
super.onStop();
exited = true;
}
#Override
protected void onResume() {
super.onResume();
exited = false;
}
As we know that the Thread.stop() is deprecated in JAVA, under the hood the Thread.stop calls the interrupt() method on the thread to stop it, Interrupt is meant to be thrown from the methods which keep the thread waiting for some other thread to notify after the execution completes. Interrupt will cause nothing to the thread if it is not handled in the execution of a thread, like, if(Thread.interrupted())return;
So, all in all we need to basically manage the start and stop of the thread like calling the start() method like Thread.start() starts a while(true) inside the run() method of the thread and checks for interrupted status in each iteration and returns from the thread.
Please note that a thread will not die in the following situations:
The thread has not yet returned from the run().
Any of the objects owned by the thread is accessible. (This hints to null/dispose of the references for GC to do the rest)
This worked for me like this. Introduce a static variable in main activity and regularly check for it how i did was below.
public class MainActivity extends AppCompatActivity {
//This is the static variable introduced in main activity
public static boolean stopThread =false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread thread = new Thread(new Thread1());
thread.start();
Button stp_thread= findViewById(R.id.button_stop);
stp_thread.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View v){
stopThread = true;
}
}
}
class Thread1 implements Runnable{
public void run() {
// YOU CAN DO IT ON BELOW WAY
while(!MainActivity.stopThread) {
Do Something here
}
//OR YOU CAN CALL RETURN AFTER EVERY LINE LIKE BELOW
process 1 goes here;
//Below method also could be used
if(stopThread==true){
return ;
}
// use this after every line
process 2 goes here;
//Below method also could be used
if(stopThread==true){
return ;
}
// use this after every line
process 3 goes here;
//Below method also could be used
if(stopThread==true){
return ;
}
// use this after every line
process 4 goes here;
}
}
}
If there is thread class with a handler in your project, when you started from one of the fragment class if you wanted to stop here is the solution how to stop and avoid crashing the app when fragment removes from the stack.
This code is in Kotlin. It perfectly works.
class NewsFragment : Fragment() {
private var mGetRSSFeedsThread: GetRSSFeedsThread? = null
private val mHandler = object : Handler() {
override fun handleMessage(msg: Message?) {
if (msg?.what == GetRSSFeedsThread.GETRSSFEEDSTHREAD_SUCCESS) {
val updateXMLdata = msg.obj as String
if (!updateXMLdata.isNullOrEmpty())
parseUpdatePager(CommonUtils.getJSONObjectFromXML(updateXMLdata).toString())
} else if (msg?.what == GetRSSFeedsThread.GETRSSFEEDSTHREAD_SUCCESS) {
BaseActivity.make_toast(activity, resources.getString(R.string.pleaseTryAgain))
}
}
}
private var rootview: View? = null;
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
rootview = inflater?.inflate(R.layout.fragment_news, container, false);
news_listView = rootview?.findViewById(R.id.news_listView)
mGetRSSFeedsThread = GetRSSFeedsThread(this.activity, mHandler)
if (CommonUtils.isInternetAvailable(activity)) {
mGetRSSFeedsThread?.start()
}
return rootview
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true);
}
override fun onAttach(context: Context?) {
super.onAttach(context)
println("onAttach")
}
override fun onPause() {
super.onPause()
println("onPause fragment may return to active state again")
Thread.interrupted()
}
override fun onStart() {
super.onStart()
println("onStart")
}
override fun onResume() {
super.onResume()
println("onResume fragment may return to active state again")
}
override fun onDetach() {
super.onDetach()
println("onDetach fragment never return to active state again")
}
override fun onDestroy() {
super.onDestroy()
println("onDestroy fragment never return to active state again")
//check the state of the task
if (mGetRSSFeedsThread != null && mGetRSSFeedsThread?.isAlive!!) {
mGetRSSFeedsThread?.interrupt();
} else {
}
}
override fun onDestroyView() {
super.onDestroyView()
println("onDestroyView fragment may return to active state again")
}
override fun onStop() {
super.onStop()
println("onStop fragment may return to active state again")
}
}
Above code stops the running thread when you switch to any other fragment or activity from current fragment. also it recreates when you return to current fragment
Inside of any Activity class you create a method that will assign NULL to thread instance which can be used as an alternative to the depreciated stop() method for stopping thread execution:
public class MyActivity extends Activity {
private Thread mThread;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mThread = new Thread(){
#Override
public void run(){
// Perform thread commands...
for (int i=0; i < 5000; i++)
{
// do something...
}
// Call the stopThread() method.
stopThread(this);
}
};
// Start the thread.
mThread.start();
}
private synchronized void stopThread(Thread theThread)
{
if (theThread != null)
{
theThread = null;
}
}
}
This works for me without a problem.

Categories

Resources