Для школьного проекта я пытаюсь создать приложение, которое использует датчик акселерометра моего телефона и вывод, если я стою, хожу или бегаю. У меня есть приложение, которое я пытаюсь изменить, чтобы оно соответствовало моим потребностям. Проблема в том, что я не понимаю, как я могу заставить сервис постоянно обновлять textView. Прямо сейчас он только обновляет textView всякий раз, когда я нажимаю «кнопку сбора». Так как я могу постоянно обновлять интерфейс? По сути, я хочу, чтобы эта строка кода [CollectorActivity.mCurrentLabel.setText (testLabel.get ((int) a));] непрерывно обновляла textView.
Вот код:
Моя деятельность:
public class CollectorActivity extends Activity {
private enum State {
IDLE, COLLECTING, TRAINING, CLASSIFYING
};
private final String[] mLabels = { Globals.CLASS_LABEL_STANDING,
Globals.CLASS_LABEL_WALKING, Globals.CLASS_LABEL_RUNNING,
Globals.CLASS_LABEL_OTHER };
private RadioGroup radioGroup;
private final RadioButton[] radioBtns = new RadioButton[4];
private Intent mServiceIntent;
private File mFeatureFile;
public static TextView mCurrentLabel;
private State mState;
private Button btnDelete;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
radioGroup = (RadioGroup) findViewById(R.id.radioGroupLabels);
radioBtns[0] = (RadioButton) findViewById(R.id.radioStanding);
radioBtns[1] = (RadioButton) findViewById(R.id.radioWalking);
radioBtns[2] = (RadioButton) findViewById(R.id.radioRunning);
radioBtns[3] = (RadioButton) findViewById(R.id.radioOther);
btnDelete = (Button) findViewById(R.id.btnDeleteData);
mCurrentLabel = (TextView) findViewById(R.id.textView);
mState = State.IDLE;
mFeatureFile = new File(getExternalFilesDir(null),
Globals.FEATURE_FILE_NAME);
mServiceIntent = new Intent(this, SensorsService.class);
}
public void run() {
CollectorActivity.mCurrentLabel.setText(SensorsService.y);
}
public void onCollectClicked(View view) {
if (mState == State.IDLE) {
mState = State.COLLECTING;
((Button) view).setText(R.string.ui_collector_button_stop_title);
btnDelete.setEnabled(false);
radioBtns[0].setEnabled(false);
radioBtns[1].setEnabled(false);
radioBtns[2].setEnabled(false);
radioBtns[3].setEnabled(false);
int acvitivtyId = radioGroup.indexOfChild(findViewById(radioGroup
.getCheckedRadioButtonId()));
String label = mLabels[acvitivtyId];
Bundle extras = new Bundle();
extras.putString(Globals.CLASS_LABEL_KEY, label);
mServiceIntent.putExtras(extras);
startService(mServiceIntent);
} else if (mState == State.COLLECTING) {
mState = State.IDLE;
((Button) view).setText(R.string.ui_collector_button_start_title);
btnDelete.setEnabled(true);
radioBtns[0].setEnabled(true);
radioBtns[1].setEnabled(true);
radioBtns[2].setEnabled(true);
radioBtns[3].setEnabled(true);
stopService(mServiceIntent);
((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancelAll();
}
}
public void onDeleteDataClicked(View view) {
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())) {
if (mFeatureFile.exists()) {
mFeatureFile.delete();
}
Toast.makeText(getApplicationContext(),
R.string.ui_collector_toast_file_deleted,
Toast.LENGTH_SHORT).show();
}
}
@Override
public void onBackPressed() {
if (mState == State.TRAINING) {
return;
} else if (mState == State.COLLECTING || mState == State.CLASSIFYING) {
stopService(mServiceIntent);
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
.cancel(Globals.NOTIFICATION_ID);
}
super.onBackPressed();
}
@Override
public void onDestroy() {
// Stop the service and the notification.
// Need to check whether the mSensorService is null or not.
if (mState == State.TRAINING) {
return;
} else if (mState == State.COLLECTING || mState == State.CLASSIFYING) {
stopService(mServiceIntent);
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
.cancelAll();
}
finish();
super.onDestroy();
}
}
Мой сервис:
public class SensorsService extends Service implements SensorEventListener {
private static final int mFeatLen = Globals.ACCELEROMETER_BLOCK_CAPACITY + 2;
private File mFeatureFile;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private int mServiceTaskType;
private String mLabel;
private Instances mDataset;
private Attribute mClassAttribute;
private OnSensorChangedTask mAsyncTask;
private List<Double> testList = new ArrayList<Double>();
public static List<String> testLabel = new ArrayList<String>();
private TextView classLabel;
private static ArrayBlockingQueue<Double> mAccBuffer;
public static final DecimalFormat mdf = new DecimalFormat("#.##");
public static String y = "";
public double a;
@Override
public void onCreate() {
super.onCreate();
mAccBuffer = new ArrayBlockingQueue<Double>(
Globals.ACCELEROMETER_BUFFER_CAPACITY);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
mSensorManager.registerListener(this, mAccelerometer,
SensorManager.SENSOR_DELAY_FASTEST);
Bundle extras = intent.getExtras();
mLabel = extras.getString(Globals.CLASS_LABEL_KEY);
mFeatureFile = new File(getExternalFilesDir(null), Globals.FEATURE_FILE_NAME);
Log.d(Globals.TAG, mFeatureFile.getAbsolutePath());
mServiceTaskType = Globals.SERVICE_TASK_TYPE_COLLECT;
// Create the container for attributes
ArrayList<Attribute> allAttr = new ArrayList<Attribute>();
// Adding FFT coefficient attributes
DecimalFormat df = new DecimalFormat("0000");
for (int i = 0; i < Globals.ACCELEROMETER_BLOCK_CAPACITY; i++) {
allAttr.add(new Attribute(Globals.FEAT_FFT_COEF_LABEL + df.format(i)));
}
// Adding the max feature
allAttr.add(new Attribute(Globals.FEAT_MAX_LABEL));
// Declare a nominal attribute along with its candidate values
ArrayList<String> labelItems = new ArrayList<String>(3);
labelItems.add(Globals.CLASS_LABEL_STANDING);
labelItems.add(Globals.CLASS_LABEL_WALKING);
labelItems.add(Globals.CLASS_LABEL_RUNNING);
labelItems.add(Globals.CLASS_LABEL_OTHER);
testLabel.add(Globals.CLASS_LABEL_STANDING);
testLabel.add(Globals.CLASS_LABEL_WALKING);
testLabel.add(Globals.CLASS_LABEL_RUNNING);
mClassAttribute = new Attribute(Globals.CLASS_LABEL_KEY, labelItems);
allAttr.add(mClassAttribute);
// Construct the dataset with the attributes specified as allAttr and
// capacity 10000
mDataset = new Instances(Globals.FEAT_SET_NAME, allAttr, Globals.FEATURE_SET_CAPACITY);
// Set the last column/attribute (standing/walking/running) as the class
// index for classification
mDataset.setClassIndex(mDataset.numAttributes() - 1);
Intent i = new Intent(this, CollectorActivity.class);
// Read:
// http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
// IMPORTANT!. no re-create activity
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);
Notification notification = new Notification.Builder(this)
.setContentTitle(
getApplicationContext().getString(
R.string.ui_sensor_service_notification_title))
.setContentText(
getResources()
.getString(
R.string.ui_sensor_service_notification_content))
.setSmallIcon(R.drawable.greend).setContentIntent(pi).build();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notification.flags = notification.flags
| Notification.FLAG_ONGOING_EVENT;
notificationManager.notify(0, notification);
mAsyncTask = new OnSensorChangedTask();
mAsyncTask.execute();
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
mAsyncTask.cancel(true);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
mSensorManager.unregisterListener(this);
Log.i("","");
super.onDestroy();
}
private class OnSensorChangedTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... arg0) {
Instance inst = new DenseInstance(mFeatLen);
inst.setDataset(mDataset);
Instance inst2 = new DenseInstance(65);
int blockSize = 0;
FFT fft = new FFT(Globals.ACCELEROMETER_BLOCK_CAPACITY);
double[] accBlock = new double[Globals.ACCELEROMETER_BLOCK_CAPACITY];
double[] re = accBlock;
double[] im = new double[Globals.ACCELEROMETER_BLOCK_CAPACITY];
double max = Double.MIN_VALUE;
while (true) {
try {
// need to check if the AsyncTask is cancelled or not in the while loop
if (isCancelled () == true)
{
return null;
}
// Dumping buffer
accBlock[blockSize++] = mAccBuffer.take().doubleValue();
if (blockSize == Globals.ACCELEROMETER_BLOCK_CAPACITY) {
blockSize = 0;
testList = new ArrayList<Double>();
// time = System.currentTimeMillis();
max = .0;
for (double val : accBlock) {
if (max < val) {
max = val;
}
}
fft.fft(re, im);
for (int i = 0; i < re.length; i++) {
double mag = Math.sqrt(re[i] * re[i] + im[i]
* im[i]);
inst.setValue(i, mag);
testList.add(i,mag);
im[i] = .0; // Clear the field
}
// Append max after frequency component
inst.setValue(Globals.ACCELEROMETER_BLOCK_CAPACITY, max);
inst2.setValue(Globals.ACCELEROMETER_BLOCK_CAPACITY, max);
testList.add(max);
a = WekaClassifier.classify(testList.toArray());
testLabel.get((int) a);
y = testLabel.get(0);
CollectorActivity.mCurrentLabel.setText(testLabel.get((int) a));
Toast.makeText(getApplicationContext(), y,
Toast.LENGTH_SHORT).show();
inst.setValue(mClassAttribute, mLabel);
mDataset.add(inst);
Log.i("new instance", mDataset.size() + "");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
protected void onCancelled() {
Log.e("123", mDataset.size()+"");
if (mServiceTaskType == Globals.SERVICE_TASK_TYPE_CLASSIFY) {
super.onCancelled();
return;
}
Log.i("in the loop","still in the loop cancelled");
String toastDisp;
if (mFeatureFile.exists()) {
// merge existing and delete the old dataset
DataSource source;
try {
// Create a datasource from mFeatureFile where
// mFeatureFile = new File(getExternalFilesDir(null),
// "features.arff");
source = new DataSource(new FileInputStream(mFeatureFile));
// Read the dataset set out of this datasource
Instances oldDataset = source.getDataSet();
oldDataset.setClassIndex(mDataset.numAttributes() - 1);
// Sanity checking if the dataset format matches.
if (!oldDataset.equalHeaders(mDataset)) {
// Log.d(Globals.TAG,
// oldDataset.equalHeadersMsg(mDataset));
throw new Exception(
"The two datasets have different headers:\n");
}
// Move all items over manually
for (int i = 0; i < mDataset.size(); i++) {
oldDataset.add(mDataset.get(i));
}
mDataset = oldDataset;
// Delete the existing old file.
mFeatureFile.delete();
Log.i("delete","delete the file");
} catch (Exception e) {
e.printStackTrace();
}
toastDisp = getString(R.string.ui_sensor_service_toast_success_file_updated);
} else {
toastDisp = getString(R.string.ui_sensor_service_toast_success_file_created) ;
}
Log.i("save","create saver here");
// create new Arff file
ArffSaver saver = new ArffSaver();
// Set the data source of the file content
saver.setInstances(mDataset);
Log.e("1234", mDataset.size()+"");
try {
// Set the destination of the file.
// mFeatureFile = new File(getExternalFilesDir(null),
// "features.arff");
saver.setFile(mFeatureFile);
// Write into the file
saver.writeBatch();
Log.i("batch","write batch here");
Toast.makeText(getApplicationContext(), toastDisp,
Toast.LENGTH_SHORT).show();
} catch (IOException e) {
toastDisp = getString(R.string.ui_sensor_service_toast_error_file_saving_failed);
e.printStackTrace();
}
Log.i("toast","toast here");
super.onCancelled();
}
}
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
double m = Math.sqrt(event.values[0] * event.values[0]
+ event.values[1] * event.values[1] + event.values[2]
* event.values[2]);
// Inserts the specified element into this queue if it is possible
// to do so immediately without violating capacity restrictions,
// returning true upon success and throwing an IllegalStateException
// if no space is currently available. When using a
// capacity-restricted queue, it is generally preferable to use
// offer.
try {
mAccBuffer.add(new Double(m));
} catch (IllegalStateException e) {
// Exception happens when reach the capacity.
// Doubling the buffer. ListBlockingQueue has no such issue,
// But generally has worse performance
ArrayBlockingQueue<Double> newBuf = new ArrayBlockingQueue<Double>(
mAccBuffer.size() * 2);
mAccBuffer.drainTo(newBuf);
mAccBuffer = newBuf;
mAccBuffer.add(new Double(m));
}
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}