2017-09-15 1 views
1

안드로이드 센서 앱에서 다른 프로세스에서 지속적으로 실행되는 서비스 (포어 그라운드)가 있으며 별도의 센서 데이터 (가속도계, 자력계, GPS)를 기록합니다. 나는 여러 센서에 대한 다양한 CSV 파일에 데이터를 가져와 쓰려면 100ms의 타이머를 사용했습니다. 문제는 데이터 기록이 일관성이 없다는 것입니다. 즉 타이머가 제대로 작동하지 않습니다. 초당 10 개의 샘플을 기록해야하는 반면, 몇 분의 간격은 몇 100ms 또는 때때로 몇 초를 건너 뜁니다. 센서에 대한 사용자 정의 클래스를 정의했으며 올바르게 작동합니다.안드로이드 센서 데이터 수집이 타이머와 일관되게 작동하지 않습니다.

다음은 서비스에 대한 내 코드입니다 :

package com.example.ark.ark.Services; 

import android.app.Notification; 
import android.app.PendingIntent; 
import android.app.Service; 
import android.content.Context; 
import android.content.Intent; 
import android.content.SharedPreferences; 

import java.text.SimpleDateFormat; 

import android.os.Build; 
import android.os.Environment; 
import android.os.IBinder; 
import android.support.annotation.Nullable; 
import android.support.annotation.RequiresApi; 
import android.support.v7.app.NotificationCompat; 

import com.example.ark.ark.Constants; 
import com.example.ark.ark.R; 
import com.example.ark.ark.Sensors.Accelerometer; 
import com.example.ark.ark.Sensors.Gps; 
import com.example.ark.ark.Sensors.Magnetometer; 
import com.example.ark.ark.Sensors.Rotation; 
import com.example.ark.ark.activity.MainActivity; 

import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.util.*; 

import static com.example.ark.ark.Constants.*; 

/** 
* Created by ark on 12/8/17. 
*/ 

@RequiresApi(api = Build.VERSION_CODES.N) 
public class DataRecording extends Service { 
    private Magnetometer magnetometer; 
    private Accelerometer accelerometer; 
    private Gps gps; 
    private Rotation rot; 
    private Timer myTimer, gpsTimer; 
    //frequency variables 
    private int acc_mag_freq = 100; 
    private int gps_freq = 2000; 

    SimpleDateFormat time = new SimpleDateFormat(TIMESTAMP_FORMAT); 
    SimpleDateFormat time1 = new SimpleDateFormat("dd-MM-yyyy_HH:mm:ss"); 

    //Declaring file variables 
    private File sdDirectory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + DIRECTORY); 
    File accDirectory = new File(sdDirectory + Constants.DIRECTORY_ACC); 
    File magDirectory = new File(sdDirectory + Constants.DIRECTORY_MAG); 
    File gpsDirectory = new File(sdDirectory + Constants.DIRECTORY_GPS); 
    File rotationDirectory = new File(sdDirectory + Constants.DIRECTORY_ROTATION); 
    private File datafile_Rot; 
    private File dataFile_Acc; 
    private File dataFile_Mag; 
    private File dataFile_Gps; 
    private FileOutputStream dataOutputStream_Acc, dataOutputStream_Mag, dataOutputStream_Gps, dataOutputStream_Rot; 

    private StringBuilder data_Acc = new StringBuilder(); 
    private StringBuilder data_Mag = new StringBuilder(); 
    private StringBuilder data_Gps = new StringBuilder(); 
    private StringBuilder data_Rot = new StringBuilder(); 
    private String mode = new String(); 
    private String acc_name, mag_name, rot_name, gps_name, user = ""; 

    @Override 
    public void onCreate() { 
     Intent notify = new Intent(this, MainActivity.class); 
     PendingIntent pendingintent = PendingIntent.getActivity(this, 0, notify, 0); 

     Notification notification = new NotificationCompat.Builder(this) 
       .setSmallIcon(R.mipmap.icon_1_round) 
       .setContentTitle("Mobility") 
       .setContentText("Recording Data") 
       .setContentIntent(pendingintent).build(); 

     startForeground(1337, notification); 
     //Creating objects of the different sensor's class 
     magnetometer = new Magnetometer(this); 
     accelerometer = new Accelerometer(this); 
     gps = new Gps(this); 
     rot = new Rotation(this); 

     data_Gps.append("\n"); 
     data_Acc.append("\n"); 
     if (magnetometer.isMagAvailable()) { 
      data_Rot.append("\n"); 
      data_Mag.append("\n"); 
     } 


     super.onCreate(); 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     super.onStartCommand(intent, flags, startId); 

     if (intent != null && intent.getExtras() != null) { 
      user = intent.getExtras().getString("username"); 
      String t = intent.getExtras().getString("acc_mag_freq"); 
      String r = intent.getExtras().getString("gps_freq"); 
      mode = intent.getExtras().getString("mode"); 
      acc_mag_freq = Integer.parseInt(t); 
      gps_freq = Integer.parseInt(r); 
     } 

     //Creating variables for file names 
     acc_name = user + "_" + time1.format(new Date()) + "_" + Constants.DATA_FILE_NAME_ACC; 
     gps_name = user + "_" + time1.format(new Date()) + "_" + Constants.DATA_FILE_NAME_GPS; 
     mag_name = user + "_" + time1.format(new Date()) + "_" + Constants.DATA_FILE_NAME_MAG; 
     rot_name = user + "_" + time1.format(new Date()) + "_" + Constants.DATA_FILE_NAME_ROTATION; 

     dataFile_Acc = new File(accDirectory, acc_name); 
     if (magnetometer.isMagAvailable()) { 
      dataFile_Mag = new File(magDirectory, mag_name); 
      if (mode.equals("1")) 
       datafile_Rot = new File(rotationDirectory, rot_name); 
     } 
     dataFile_Gps = new File(gpsDirectory, gps_name); 

     try { 
      dataOutputStream_Acc = new FileOutputStream(dataFile_Acc, true); 
      if (magnetometer.isMagAvailable()) { 
       dataOutputStream_Mag = new FileOutputStream(dataFile_Mag, true); 
       if (datafile_Rot != null) 
        dataOutputStream_Rot = new FileOutputStream(datafile_Rot, true); 
      } 

      dataOutputStream_Gps = new FileOutputStream(dataFile_Gps, true); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     myTimer = new Timer(); 
     myTimer.schedule(new TimerTask() { 
      @Override 
      public void run() { 
       getDataSensors(); 
      } 

     }, 0, acc_mag_freq); 
     gpsTimer = new Timer(); 
     gpsTimer.schedule(new TimerTask() { 
      @Override 
      public void run() { 
       getDataGps(); 
      } 
     }, 0, gps_freq); 
     return START_STICKY; 
    } 

    public void getDataGps() { 
     data_Gps.append(time.format(new Date())); 
     data_Gps.append(","); 
     float[] gpsreading = gps.getReading(); 
     data_Gps.append(String.format("%.10f", gpsreading[0])); 
     data_Gps.append(","); 
     data_Gps.append(String.format("%.10f", gpsreading[1])); 
     data_Gps.append("\n"); 
     try { 
       dataOutputStream_Gps.write(data_Gps.toString().getBytes()); 

      data_Gps.setLength(0); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void getDataSensors() { 
     data_Acc.append(time.format(new Date())); 
     data_Acc.append(","); 
     if (magnetometer.isMagAvailable()) { 
      data_Mag.append(time.format(new Date())); 
      data_Mag.append(","); 
      if (mode == "1") { 
       data_Rot.append(time.format(new Date())); 
       data_Rot.append(","); 
      } 
     } 
     float[] acc = accelerometer.getLastReading(); 
     float[] mag = magnetometer.getLastReading(); 
     float[] rotVal = rot.getLastReading(); 
     //accelerometer data_Acc 
     data_Acc.append(String.format("%.3f", acc[0])); 
     data_Acc.append(","); 
     data_Acc.append(String.format("%.3f", acc[1])); 
     data_Acc.append(","); 
     data_Acc.append(String.format("%.3f", acc[2])); 
     //data_Acc.append(","); 
     if (magnetometer.isMagAvailable()) { 
      //magnetometer data_Acc 
      data_Mag.append(String.format("%.3f", mag[0])); 
      data_Mag.append(","); 
      data_Mag.append(String.format("%.3f", mag[1])); 
      data_Mag.append(","); 
      data_Mag.append(String.format("%.3f", mag[2])); 
      //data_Acc.append(","); 
      // write this data_Acc to file 
      data_Mag.append("\n"); 
      if (mode == "1") { 
       data_Rot.append(String.format("%.3f", rotVal[0])); 
       data_Rot.append(","); 
       data_Rot.append(String.format("%.3f", rotVal[1])); 
       data_Rot.append(","); 
       data_Rot.append(String.format("%.3f", rotVal[2])); 
       //data_Acc.append(","); 
       // write this data_Acc to file 
       data_Rot.append("\n"); 
      } 
     } 
     data_Acc.append("\n"); 
     try { 

      dataOutputStream_Acc.write(data_Acc.toString().getBytes()); 
      if (magnetometer.isMagAvailable()) { 
       dataOutputStream_Mag.write(data_Mag.toString().getBytes()); 
       if (mode == "1") { 
        dataOutputStream_Rot.write(data_Rot.toString().getBytes()); 
       } 
      } 
      data_Acc.setLength(0); 
      data_Rot.setLength(0); 
      data_Mag.setLength(0); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 
    } 

    @Nullable 
    @Override 
    public IBinder onBind(Intent intent) { 
     return null; 
    } 
} 
+0

partial_lock을 획득하셨습니까? https://developer.android.com/training/scheduling/wakelock.html 화면이 잠기면 CPU가 잠자기 상태가됩니다. 이를 위해서는 부분 잠금을 획득해야합니다. – utengr

+0

이러한 지연이 빈번하지 않은 경우 타이머가 정확한 시간 간격을 보장하지 않기 때문에 정상적인 것입니다. 매 20 밀리 초마다 발사하도록 요청하면 CPU로드 및 장치에서 진행중인 다른 작업에 따라 해당 간격으로 정확히 발사되지 않습니다. – utengr

+0

이러한 동작으로 인해 몇 밀리 초의 지연이 발생합니다. 일반적으로 활동 인식을 위해 허용되는 지연입니다. 자주 발생하면 부분 잠금을 사용하십시오. – utengr

답변

0

지금까지 내가 안드로이드 하드 실시간 이벤트를 지원하도록 설계되지 않았습니다, 그래서 당신이 어떤 방법으로 그것을 달성 할 수 있다고 생각하지 않습니다 알고.

어쨌든 난 당신이 내가 그 데이터 검색은 매 100 밀리 실행 보장하지 않습니다 알고 당신이에서 앱에서 이러한 것들을 사용할 수 있는지, alarms를 사용하고 foreground service으로 서비스를 정의하는 시도 할 수 있다고 생각하지만, 그건 좀 더 정기적으로 할 가능성이 있습니다.

+0

전경 서비스 만 사용하고 있습니다. –

관련 문제