我正在开发一个读取GYRO数据的APP,然后将X,Y,Z值保存在存储在SD卡中的excel文件中。 我正在使用JXL来实现excel写入,因为excel写入是资源占用我为它开始新的线程。 我的代码编译好了,但在手机上运行时出现错误,如下所示:
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)
以下是我的源代码:
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;
}
}
对于错误消息,问题应该在下面一行:
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]));
任何人都可以帮我找到这个bug吗? 以及如何解决这个问题? 如何在新线程中读取陀螺仪数据?
答案 0 :(得分:2)
发生 NullPointerException ,因为您没有保存从传感器检索的值。在OnSensorChanged()方法中,您只需设置文本,而不是将值复制到全局事件。因此,当您在run()方法中访问SensorEvent实例时,会发生异常。
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]));
}
然后更改以下部分
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]));
因为您同时执行此操作,所以最好实现缓冲区并将缓冲区写入excel文件。
的注意强>
代码将不工作,因为您没有在共享对象上提供任何并发度测量,在本例中为mValues
。即使声明它volatile
,onSensorChanged方法也会收到非常快的值,如果你不将它们保存在某个临时的地方并按顺序将它们写入excel文件,线程将丢弃大部分值。