0

I am developing one APP of reading GYRO data, then save the X,Y,Z value in excel file stored in SD card. I am using the JXL to implement excel write, since the excel write is a resource hog I start new thread for it. my code compiled OK, but when running on phone, there is error, as following:

 06-20 17:15:45.328: W/dalvikvm(19897): threadid=13: thread exiting with uncaught             exception (group=0x41c30450)
 06-20 17:15:45.328: E/AndroidRuntime(19897): FATAL EXCEPTION: Thread-58127
 06-20 17:15:45.328: E/AndroidRuntime(19897): java.lang.NullPointerException
 06-20 17:15:45.328: E/AndroidRuntime(19897):   at hunk.hong.sonymobile.gyrotest.MainActivity$2.run(MainActivity.java:169)
 06-20 17:15:45.328: E/AndroidRuntime(19897):   at java.lang.Thread.run(Thread.java:856)

and below is my source code:

 public class MainActivity extends Activity implements SensorEventListener {

        private TextView TV;
        private TextView TV1;
        private Button button1;
        private SensorManager mSensorManager;
        private Sensor mSensor;
        private EditText mEditText;
        private SensorEvent mSensorEvent;
        private Thread mThread;
        private SensorEvent event;

        DatabaseHandler db = new DatabaseHandler(this);


        Timer timer = new Timer();
        Handler handler = new Handler(){
            public void handleMessage(Message msg){
                switch (msg.what){
                case 1:

                    //do someting
                    //setTitle("hear me?");
                    break;
                }
                super.handleMessage(msg);
            }
        };


        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);


            button1 = (Button)findViewById(R.id.button1);
            mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
            TV = (TextView)findViewById(R.id.action_settings);
            TV1 = (TextView)findViewById(R.id.textView1);
            mEditText = (EditText)findViewById(R.id.editText1);

            if (mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) == null){
                //sorry, there is no GYRO in your device
                TV.setText("sorry, there is no GYRO in your device!!!");
            }
            else{
                mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
                TV.setText("vendor:"+mSensor.getName()+"\n"+"version:"+mSensor.getVersion()+"\n"+"MAX Range:"+mSensor.getMaximumRange()
                        +"\n"+"Resulation:"+mSensor.getResolution());
            }

            button1.setOnClickListener(new OnClickListener(){
                @Override
                public void onClick(View v){
                    if(mThread == null){
                        mThread = new Thread(runnable);
                        mThread.start();//thread start
                    }
                    else{
                        //Toast.makeText(this, "thread is already running", Toast.LENGTH_LONG).show();
                    }
                }
            });


        }

        Runnable runnable = new Runnable(){
            @Override
            public void run(){

            String Fnamexls = "GyroTest"+".xls";
            File sdCard = Environment.getExternalStorageDirectory();
            File directory = new File (sdCard.getAbsolutePath()+"/GyroTest");
            directory.mkdir();
            File file = new File(directory,Fnamexls);
            WritableWorkbook workbook;
            try{
                int i=1;
                workbook = Workbook.createWorkbook(file);
                WritableSheet sheet = workbook.createSheet("First Sheet", 0);
                Label labelTitle1 = new Label(0,0,"X-rotation(R/S)");
                Label labelTitle2 = new Label(1,0,"Y-rotation(R/S)");
                Label labelTitle3 = new Label(2,0,"Z-rotation(R/S)");
                try{//write title
                    sheet.addCell(labelTitle1);
                    sheet.addCell(labelTitle2);
                    sheet.addCell(labelTitle3);
                }catch(RowsExceededException e){
                    e.printStackTrace();
                }catch (WriteException e){
                    e.printStackTrace();
                }
                for (i=1;i<=100;i++){//write 100 data in excel
                    Label labeli0 = new Label(0,i,Float.toString(event.values[0]));
                    Label labeli1 = new Label(1,i,Float.toString(event.values[1]));
                    Label labeli2 = new Label(2,i,Float.toString(event.values[2]));
                    try{
                        sheet.addCell(labeli0);
                        sheet.addCell(labeli1);
                        sheet.addCell(labeli2);
                    }catch (RowsExceededException e){
                        e.printStackTrace();
                        }catch (WriteException e){
                            e.printStackTrace();
                        }
                }

                workbook.write();
                try{
                    workbook.close();
                }catch(WriteException e){
                    e.printStackTrace();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
            }
        };

        protected void onResume()  
        {  
            super.onResume();  
            /*register the sensor listener to listen to the gyroscope sensor, use the 
            call backs defined in this class, and gather the sensor information as quick 
            as possible*/  
            mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),SensorManager.SENSOR_DELAY_UI);  //get sensor readout suitable for user interface
        }  
        //When this Activity isn't visible anymore  
        @Override  
        protected void onStop()  
        {  
            //unregister the sensor listener when application is not visible
            mSensorManager.unregisterListener(this);  
            super.onStop();  
        } 

        @Override  
        public void onAccuracyChanged(Sensor arg0, int arg1)  
        {  
            //Do nothing.  
        }  

        @Override  
        public void onSensorChanged(SensorEvent event)  
        {  
            //if sensor is unreliable, return void  
            if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)  
            {  
                return;  
            }  

            //else it will output the rotation values  
            TV1.setText("Rotation X  :"+ Float.toString(event.values[0]) +"\n"+  
                       "Rotation Y  :"+ Float.toString(event.values[1]) +"\n"+  
                       "Rotation Z  :"+ Float.toString(event.values[2])); 

        }  
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }

    }

And for the error message, the issue should be in below line:

Label labeli0 = new Label(0,i,Float.toString(event.values[0])); 
Label labeli1 = new Label(1,i,Float.toString(event.values[1])); 
Label labeli2 = new Label(2,i,Float.toString(event.values[2]));

can anybody help me to find the bug? and how to solve the issue? how can i read the Gyro data in the new thread?

thank you in advance!

Senthil
  • 1,244
  • 10
  • 25
hunk
  • 1
  • 1

1 Answers1

2

The NullPointerException occurs because you do not save the values that you retrieve from the sensors. In OnSensorChanged() method you just set the text and you do not copy the values to the global event. So when you access the instance of SensorEvent in run() method, an exception occurs.

private volatile float[] mValues;

@Override  
public void onSensorChanged(SensorEvent event)  
{  
    //if sensor is unreliable, return void  
    if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)  
    {  
        return;  
    }  

    mValues = event.values.clone();

    //else it will output the rotation values  
    TV1.setText("Rotation X  :"+ Float.toString(event.values[0]) +"\n"+  
               "Rotation Y  :"+ Float.toString(event.values[1]) +"\n"+  
               "Rotation Z  :"+ Float.toString(event.values[2])); 

}

and then change the following part also

Label labeli0 = new Label(0,i,Float.toString(mValues[0]));
Label labeli1 = new Label(1,i,Float.toString(mValues[1]));
Label labeli2 = new Label(2,i,Float.toString(mValues[2]));

Because you perform this concurrently, it is better that you implement a buffer and write the buffer to the excel file. CAUTION The code will not work because you do not provide any concurrency measurements on the shared objects, in this case mValues. Even by declaring it volatile, the method onSensorChanged will receive very fast values and the thread will discard most of the values if you do not save them somewhere temporary and sequentially write them to the excel file.

npal
  • 529
  • 4
  • 11
  • It is also possible to offload the sensor callback to a background thread, see [Acclerometer Sensor in Separate Thread](http://stackoverflow.com/a/17513504/192373) – Alex Cohn Oct 03 '13 at 09:45