android dev : is any specific multithreading codin

2019-09-06 12:01发布

问题:

my android project ( sensors capture , multithreads processing, and output writing into csv file ) is working fine on Nexus and other devices ( 4.4 kitkat, 4.3 / 4.2 Jellybean) ... but when testing it on Sony Xperia Z, it crashes...

tip: it doesn't crash running in Debugging Mode ....

I guess it's related to a multithreading issue, as dat are captured, processed and written into the output csv file , and the crash happens after running few secs...

is anything specific to Sony implementation I forgot ?

LogCat can be found at : https://gist.github.com/erwin/10535096

thanks for any tip .... I need to make it running on Sony devices ...

here is the main SwimActivity which will start 2 threads : samplingThread ( capturing sensors data into capture list)

        public class SwimActivity extends Activity implements OnSeekBarChangeListener  {    

        private SamplingThread          samplingThread;
        private InterpolationThread     interpolationThread;

        public volatile ArrayList<LinkedList<CapturedEvent>> captures = new ArrayList<LinkedList<CapturedEvent>>();  // filled by sampligThread
        public volatile ArrayList<LinkedList<CapturedEvent>> sensors = new ArrayList<LinkedList<CapturedEvent>>();   
        public volatile LinkedList<InterpolatedEvent> cachedData = new LinkedList<InterpolatedEvent>();

        class SwimHandler extends Handler {    // handle messages from interpolationThread
            @Override
            public void handleMessage(Message msg) {
              super.handleMessage(msg);
              if (this != null) {
                    Bundle bundle = msg.getData();
                    Integer msgKey = bundle.getInt("msgKey");               
                    switch(msgKey){
                    case SENSORS_READY:
                        showToast("all sensors ready..");
                        sensorsReady();
                        break;
                    case SAMPLING:
                        showToast("sampling..");
                        break;
                    case SAMPLING_COMPLETED:
                        samplingCompleted();
                        break;
                    }
              }

            }
        }
        public final SwimHandler mHandler = new SwimHandler();


        private void startSampling() {  //  user hit the start button on UI
            //  init output csv file
            // ....
                FileWriter fileWriter = new FileWriter( captureFileName, false );
                captureFile = new PrintWriter( fileWriter );

            // initialize ArrayList 
            // ........

            Log.i(TAG, "starting samplingThread");
            samplingThread = new SamplingThread(this, captures);
            samplingThread.setPriority( Thread.NORM_PRIORITY);
            samplingThread.start();  
        } 


        private void sensorsReady() {  // when message 'SENSORS_READY' received from interpolationThread
            cachedData.clear();

            Log.i(TAG, "sensors ready, starting interpolationThread");
            interpolationThread = new InterpolationThread(SwimActivity.this, captures, sensors, cachedData, ...  other params );
            interpolationThread.setPriority( Thread.NORM_PRIORITY + 1);
            interpolationThread.start();                            
         }
    }

and interpolationThread ( processing the captured data and writing interpolated data into a csv file )

        public class InterpolationThread extends Thread {
        // .....
        ArrayList<LinkedList<CapturedEvent>> captures;
        ArrayList<LinkedList<CapturedEvent>> sensors;
        LinkedList<InterpolatedEvent> cachedData;

        public InterpolationThread(SwimActivity activity, ArrayList<LinkedList<CapturedEvent>> ceList ..... {
            // ... init params
            running = true;
        }

        @Override
        public void run() {
            lastMessageTime = SystemClock.elapsedRealtime();  // millis
            if (interpolationTime == 0 ) { setInitialInterpolationTime(); }     
            lastMessageTime = SystemClock.elapsedRealtime();  // millis
            if (interpolationTime == 0 ) { setInitialInterpolationTime(); }     
            while(running ){                
                    interpolatedSensorData = interpolateAllSensors();    // interpolate && set sensorStatus - Vector<Integer>
                    addInterpolatedDataToCache(interpolatedSensorData);
                    processCachedData();
                    cleanUpCachedData();  // write completed interpolations into csv log file
            }
            running = false;
        }
        public void interrupt() {
            running = false;
            if( captureFile != null )
                captureFile.close();
        }

        // other processing methods

        public void cleanUpCachedData() {
            ListIterator<InterpolatedEvent> cacheIterator = cachedData.listIterator();
            while(cacheIterator.hasNext()) {
                InterpolatedEvent cachedEvent = cacheIterator.next(); 
                Vector<Vector3> cachedEventValues = cachedEvent.values;  // all sensors
                if (allInterpolationsCompleted(cachedEventValues)) { // all sensors got interpolated data
                    writeInterpolatedDataIntoLogFile(cachedEventValues);
                    cacheIterator.remove();  // remove current interpolatedEvent from cache()
                }
            }
        }

        public void writeInterpolatedDataIntoLogFile(Vector<Vector3>interpolatedSensorData) {   
            // .....        
            elapsedLogTime += samplingRate; 
            Vector3 orientation = calculateOrientation(interpolatedSensorData);
            // ...
            String data = "" + elapsedLogTime;              
            Iterator<Vector3>  sensorIterator = interpolatedSensorData.iterator();  
            while(sensorIterator.hasNext() ) {
                Vector3 values = (Vector3) sensorIterator.next();
                int sensorIndex = interpolatedSensorData.indexOf(values);
                if (sensorIndex == 1 && !gyro)  {
                    Vector3 zeroValues = new Vector3(); // insert gyro = zero
                    for (int i = 0; i < 3; i++) { data = data + ";" + nf.format(zeroValues.toArray()[i]);}      //gyro  0   
                    for (int i = 0; i < 3; i++) { data = data + ";" + nf.format(zeroValues.toArray()[i]);}      // linearAccel 0        
                } else if (sensorIndex == 2 && !linearAccel)  {
                    Vector3 zeroValues = new Vector3(); // insert gyro = zero
                    for (int i = 0; i < 3; i++) { data = data + ";" + nf.format(zeroValues.toArray()[i]);}                  
                    for (int i = 0; i < 3; i++) { data = data + ";" + nf.format(values.toArray()[i]); } // add linearAccel data     
                }

                else 
                    for (int i = 0; i < 3; i++) { data = data + ";" + nf.format(values.toArray()[i]); }                     
            }   
            for (int i = 0; i < 3; i++) { data = data + ";" + nf.format(orientation.toArray()[i]); }

            captureFile.println( data );        
            }
        }
    }

回答1:

I don't know why yhe previous run() method was running fine in the Nexus (Android4.4), but I modified the run() method in the samplingThread :

previous method ( not running on Sony Xperia ( Android 4.3 ) :

@Override
public void run() {
    while(running ){}
    running= false;
}

modified method (running fine in all devices) :

Object LOCK = new Object(); // just something to lock on
@Override
public void run() {
    while(running ){ 
        synchronized (LOCK) {
            LOCK.notifyAll();
        }
    }
    running= false;
}

I also dropped the thread priority settings, as it seem not to be taken in account... It seems that the samplingThread was not giving up some time to the interpolationThread to get the sampled data ending in a deadlock