简体   繁体   中英

Killing a background thread when a the fragment is destroyed

i have an a fragment that have a background thread that update a progress bar value and change the progress bar drawable when the progress value reach a certain value when i try to start onther fragment in the same activity it case this error

    E/UncaughtException: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.support.v4.app.FragmentActivity.getResources()' on a null object reference
    at com.example.mego.adas.ui.CarFragment$PotProgressThread$1.run(CarFragment.java:831)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:7409)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.mego.adas, PID: 25935
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.support.v4.app.FragmentActivity.getResources()' on a null object reference
    at com.example.mego.adas.ui.CarFragment$PotProgressThread$1.run(CarFragment.java:831)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:7409)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

here is the code for the thread

    class PotProgressThread implements Runnable {

    @Override
    public void run() {
        while (potSensorValue <= 1025 && fragmentIsRunning) {

            if (fragmentIsRunning) {

                // Update the progress bar
                potProgressBarHandler.post(new Runnable() {
                    public void run() {
                        potProgressBar.setProgress((int) potSensorValue);
                        if (potSensorValue >= 800) {
                            potProgressBar.setProgressDrawable(getActivity().
                                    getResources().getDrawable(R.drawable.progressbarred));
                        } else {
                            potProgressBar.setProgressDrawable(getActivity().
                                    getResources().getDrawable(R.drawable.progressbarblue));

                        }
                    }
                });
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                break;
            }
        }
    }
}

Here where i cast start my thread in onCreateView() method

   @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {


    View rootView = inflater.inflate(R.layout.fragment_car, container, false);
    initializeScreen(rootView);

    //check the internet connection
     connectivityManager = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
     networkInfo = connectivityManager.getActiveNetworkInfo();

    if (networkInfo != null && networkInfo.isConnected()) {
        buildGoogleApiClient();

        //set up the firebase
        mFirebaseDatabase = FirebaseDatabase.getInstance();

        //get the references for the childes
        //the main child for the directions services
        carDatabaseReference = mFirebaseDatabase.getReference().child(constant.FIREBASE_CAR);

        //the childes for the direction root
        connectionStateDatabaseReference = mFirebaseDatabase.getReference()
                .child(constant.FIREBASE_CAR).child(constant.FIREBASE_CONNECTION_STATE);

        accidentStateDatabaseReference = mFirebaseDatabase.getReference()
                .child(constant.FIREBASE_CAR).child(constant.FIREBASE_ACCIDENT_STATE);

        startStateStateDatabaseReference = mFirebaseDatabase.getReference()
                .child(constant.FIREBASE_CAR).child(constant.FIREBASE_START_STATE);

        lightsStateDatabaseReference = mFirebaseDatabase.getReference()
                .child(constant.FIREBASE_CAR).child(constant.FIREBASE_LIGHTS_STATE);

        lockStateDatabaseReference = mFirebaseDatabase.getReference()
                .child(constant.FIREBASE_CAR).child(constant.FIREBASE_LOCK_STATE);

        mappingServicesDatabaseReference = mFirebaseDatabase.getReference()
                .child(constant.FIREBASE_CAR).child(constant.FIREBASE_MAPPING_SERVICES);

        sensorsValuesDatabaseReference = mFirebaseDatabase.getReference()
                .child(constant.FIREBASE_CAR).child(constant.FIREBASE_SENSORES_VALUES);

        connectionStateDatabaseReference.setValue(1);


    }
    //show Snackbar if there is no internet net connection
    else {
        if (carFragment != null) {

            //   Snackbar snackbar = Snackbar.make(carFragment, R.string.no_internet_connection, Snackbar.LENGTH_LONG);
            // snackbar.show();
        }
    }

    //get the date from the connected thread
    bluetoothHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            //if message is what we want
            if (msg.what == handlerState) {
                // msg.arg1 = bytes from connect thread
                String readMessage = (String) msg.obj;

                //keep appending to string until ~ char
                recDataString.append(readMessage);

                //determine the end of the line
                endOfLineIndex = recDataString.indexOf("~");
                if (fragmentIsRunning) {
                    refreshUI();
                }

            }
        }
    };

    //setup ans start the threads
    potThread = new Thread(new PotProgressThread());
    tempThread = new Thread(new TemperatureProgressThread());
    ldrThread = new Thread(new LdrProgressThread());


    fragmentIsRunning = true;
    potThread.start();
    tempThread.start();
    ldrThread.start();


    //set the buttons listener
    lightsButton.setOnClickListener(this);
    lockButton.setOnClickListener(this);
    disconnectButton.setOnClickListener(this);
    startButton.setOnClickListener(this);

    //setup the map fragment
    MapFragment mapFragment = (MapFragment) getActivity().getFragmentManager().findFragmentById(R.id.my_location_fragment_car);
    mapFragment.getMapAsync(this);

    // Inflate the layout for this fragment
    return rootView;
}

Here is the code on onDestoryview() method

fragmentIsRunning = false;
potThread.interrupt();

how can i kill it

Dalvik keeps all Thread references in the runtime so your thread will keep running unless it is terminated or completes (some reference ). So depending on where you start your thread, you may be creating more than one.

In your case Your thread execution is not completed and you change the fragment so your getActivity() will be null.

The solution is before getActivity() , check isAdded() is true or not, if not true, that means the fragment is already detached, call to getActivity() will return null.

Remember in the Thread, everywhere before you call getActivity() , you'd better to check isAdded() again, because user may exit the activity at anytime during the Thread is executing.

Other Solution

I am not sure but you can achieve by initialize Context globally and you that context in your thread.

Context mContext;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) 
{
     mContext = getActivity();
     ....
}

Now use this context in your thread.

class PotProgressThread implements Runnable {

    @Override
    public void run() {
        while (potSensorValue <= 1025 && fragmentIsRunning) {

            if (fragmentIsRunning) {

                // Update the progress bar
                potProgressBarHandler.post(new Runnable() {
                    public void run() {
                        potProgressBar.setProgress((int) potSensorValue);
                        if (potSensorValue >= 800) {
                            potProgressBar.setProgressDrawable(mContext.
                                    getResources().getDrawable(R.drawable.progressbarred));
                        } else {
                            potProgressBar.setProgressDrawable(mContext.
                                    getResources().getDrawable(R.drawable.progressbarblue));

                        }
                    }
                });
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                break;
            }
        }
    }
}

I hope you will get the solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM