0

For a school project I am trying to make an app that uses the accelerometer sensor of my phone and output if I am standing, walking or running. I have an exisiting app which I am trying to alter to fit for my needs. The problem is that I don't understand how I can have the service update the textView continously. Right now it only updates the textView whenever I press the "collect button". So how can I have it continously updating the UI? Basically what I want is this line of code to continously update the textView:

CollectorActivity.mCurrentLabel.setText(testLabel.get((int) a));

Here is the code:

My activity:

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();
}

}

My service:

 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;
}

}

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
  • Possible duplicate of [Android update activity UI from service](https://stackoverflow.com/questions/14695537/android-update-activity-ui-from-service) – Maciej Beimcik Sep 07 '18 at 05:07
  • I do not get it to work. Currently I am trying to have the String variable as static. Why does not the UI update whenever the variable is changed? Is it possible to make it so that the UI refreshes every second? Or that I can listen to a change in the variable? – user10309561 Sep 07 '18 at 06:21

0 Answers0