I am developing an Android app that is recognising the activity the user us doing every 3 seconds (has to be that frequent by design) (e.g. static, walking, running). I have an Activity table in my database that increments the following values:
private int activeTime;
private int longestInactivityInterval;
private int currentInactivityInterval;
private int averageInactInterval;
Those are presented in a fragment. Currently, it is very "sensitive". For example, if the user is static (i.e. laying on their bed) and they pull their phone out of the pocket it will recognise activity like "walking". The history of recognised activities would look like that:
static
static
walking
static
static
How can I make sure that this incidental "walking" recognised activity is recognised as "static". Is there a way how I can correct that?
This is the class that is doing the Activity monitoring (incrementing values depending on what activity is recognised.
public class ActivityMonitor implements Observer, IActivityMonitor {
private User mUser;
private IActivityDataManager mDataManager;
public ActivityMonitor(IActivityDataManager dataManager) {
mDataManager = dataManager;
}
#Override
public void update(Observable observable, Object activity) {
monitorActivity(activity);
}
private void monitorActivity(Object activityClass) {
switch ((int) activityClass) {
case 0:
//activity = "walking";
case 1:
//activity = "running";
case 3:
//activity = "cycling";
mDataManager.incActiveTime();
mDataManager.clearCurrentInacInterval();
break;
case 2:
//activity = "static";
mDataManager.incCurrentInacInterval();
break;
}
}
I found a solution to the problem myself. I am using apache's common CircularFifoQueue with set size to 2.
This is how my solution looks like:
private void monitorActivity(Object activityClass) {
int activityInt = (int) activityClass;
correctionList.add(activityInt);
int correctResult = applyCorrection(activityInt);
if (correctResult == correctionList.size()) {
mDataManager.incActiveTime();
mDataManager.clearCurrentInacInterval();
} else {
mDataManager.incCurrentInacInterval();
}
}
private int applyCorrection(int classInt) {
int count = 0;
for (int item : correctionList) {
if (item == 0 || item == 1 || item == 3) {
count++;
}
}
return count;
}
Basically, it adds the classInt which could be (0,1,2 or 3) - walking = 0, running = 1, cycling = 3 and static = 2. The applyCorrection method looks through the queue with size 2 (this plays the role of the factor, 2 works great for me) and counts and checks the integers. If the returned count correctResult is 2 that means that the activity is for sure of time ACTIVE (1,2,3) and not STATIC (2).
Related
I have 4 buttons, that each one of them doe's a different action (lets say each action takes 2 minutes)
When I click both buttons (with few minutes between them), both of them still get inside the 'if' part, although the flag i put.
Here is part of my code:
southToNorth.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
north.incCounter();
north.setWaitingState(true);
pushToQueue(1);
if (isWorking==0) {
isWorking++;
start();
}
}
});
westToEast.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
east.incCounter();
east.setWaitingState(true);
pushToQueue(2);
if (isWorking==0) {
isWorking++;
start();
}
}
});
I Don't think that is a synchronization problem, i even put this code at the top of the start function:
private void start() {
if(isWorking>1)
return;
but still, both of them doe's all of the start function, what I'm trying to avoid.
(I have a global flag "int isWorking" initialized to zero )
Why both of them are getting inside the if part? How can I solve it?
Thank you very much!
A global flag should do it. You say you've tried it, but you haven't actually provided how you tried it, so I can't specifically help with that.
Make two variables and some static fields:
private static final int ACTION_NONE = -1;
private static final int ACTION_ONE = 0;
private static final int ACTION_TWO = 1;
private static final int ACTION_THREE = 2;
private static final int ACTION_FOUR = 3;
private boolean actionRunning = false;
private int queuedAction = ACTION_NONE;
When you try to run an action, check if there's currently an action running:
if (actionRunning) {
queuedAction = /* the corresponding static field */;
} else {
queuedAction = ACTION_NONE;
actionRunning = true;
}
Then, when whatever action you're using completes, run the appropriate queued action:
switch (queuedAction) {
case ACTION_ONE:
//run action 1
break;
case ACTION_TWO:
//etc
...
}
Im trying to build a highscore for a game. A Run is an ojbect made for this game.
The class looks like this:
public class Run {
private int level;
private int moves;
private int time;}
The array of the highscore Looks like this:
Run Highscoresaving[] = new Run[10];
Now i would like to sort this array. The most important value is a high Level, second a low amount of moves and third a short amount of time. Moves are just needed if the run reached the same Level and time is just needed if the run reached the same Level and had the same amout of moves.
You can use lambda expression:
List<Run> myRuns = //init
Collections.sort(myRuns, new RunComparator());
To do it you have to implement Comparable<> in your object like this:
public class Run implements Comparable<Run> {
private int level;
private int moves;
private int time;
}
public class RunComparator implements Comparator<Run>{
public int compare(Run o1, Run o2) {
if(o1.getLevel() == o2.getLevel()){
if(o1.getMoves() == o2.getMoves()){
return o1.getTime() - o2.getTime();
}
return o1.getMoves() - o2.getMoves();
}
return o1.getLevel() - o2.getLevel();
}
hope this helps
I am making an Android app that captures a user's e-mail through the displayEmailCaptureFragment() method. If I already captured the user's e-mail, I do not want to prompt the user to enter their e-mail again.
I declare the customerEmailAddress String right after my MainActivity but before the onCreate method:
public class MainActivity extends FragmentActivity implements View.OnClickListener, BillingProcessor.IBillingHandler,
EmailCapturedListener {
private MyPagerAdapter pageAdapter;
private Button mDownloadResumeButton;
private ImageButton mRightArrow, mLeftArrow;
private static final String EMAILKEY = "email_key";
public static final String EDITSKU = "professional_editing_service_1499";
public static final String EMAILSKU = "resume_template_pro_99";
private static final String RBPEMAIL = "rbproeditor#gmail.com";
private static final String RBPPASSWORD = "Redhawks123";
public String customerEmailAddress;
I then have an OnClick() method based on a user's response action within the app. Essentially, I am try to allow for a certain activity after the onClick if the user already entered their e-mail address. If they did not enter their e-mail address, then I prompt them to enter their e-mail and save it to shared preferences. I use a basic if - else statement, however I am still generating a null pointer exception even though I assign the customerEmailAddress string:
#Override
public void onClick(View v) {
int currentPosition = pager.getCurrentItem();
switch (v.getId()) {
case R.id.right_arrow:
pager.setCurrentItem(currentPosition + 1);
break;
case R.id.left_arrow:
pager.setCurrentItem(currentPosition - 1);
break;
case R.id.download_resume_button:
customerEmailAddress = mPrefs.getString(EMAILKEY, null);
if (customerEmailAddress.equals(null)){
displayEmailCaptureFragment();
}
else {
showPurchaseDialog();
}
break;
}
}
Any help is appreciated!
This code is wrong - you can't call equals(...) or any other method on a null object.
...
customerEmailAddress = mPrefs.getString(EMAILKEY, null);
if (customerEmailAddress.equals(null)){
...
Do like this instead:
customerEmailAddress = mPrefs.getString(EMAILKEY, null);
if (customerEmailAddress == null){
...
OR use TextUtils:
customerEmailAddress = mPrefs.getString(EMAILKEY, null);
if (TextUtils.isEmpty(customerEmailAddress)){
...
Particularly the Navigation between the Views over the ViewModels looks like that:
ShowViewModel<InfoViewModel>();
Or between normal Activities:
context.StartActivity(typeof(InfoActivity));
The problem I face now (actually I solved it in one of my latest projects by using Tinymessenger - its an event aggregator/messenger for loosely coupled communication) but I would like to know if theres an other way!
I'm creating an optionsmenu:
public abstract class BaseActivityWithoutTabs<T> : MvxActivity where T : class, IMvxViewModel
{
public override bool OnCreateOptionsMenu(IMenu menu)
{
return ActivitiesHelper.CreateOptionsMenu(menu);
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
return ActivitiesHelper.CreateOnOptionsItemSelectedEvent(item, this);
}
}
InfoActivity derives from this BaseActivityWithoutTabs.
In the ActivitiesHelper Class (from above code) I'm creating the menu and the events:
public class ActivitiesHelper
{
private const int einstellungenItemId = 0;
private const int infoItemId = 1;
public static bool CreateOptionsMenu(IMenu menu)
{
// GroupId, ItemId, OrderId
menu.Add(0, einstellungenItemId, 0, "Einstellungen").SetIcon(Android.Resource.Drawable.IcMenuManage);
menu.Add(0, infoItemId, 1, "Info").SetIcon(Android.Resource.Drawable.IcMenuInfoDetails);
return true;
}
public static bool CreateOnOptionsItemSelectedEvent(IMenuItem item, Context context)
{
var id = item.ItemId + 1; // (Id is zero-based :)
if (id == 1) // First Item
{
context.StartActivity(typeof(SettingsShowActivity));
}
else if (id == 2) // Second Item
{
context.StartActivity(typeof(InfoActivity)); //doesn't work...
}
return true;
}
}
As you see I do here "StartActivity".. it works for the first "SettingsShowActivity" but thats an PreferenceActivity, so there no reason why it should fail. The problem is, that I would like to Start here the InfoActivity(as you see in code - Second Item) and this doesn't work. It opens the Activity but the List doesn't gets filled.
But if I go to a ViewModel in my project and call: ShowViewModel<InfoViewModel>();it works fine but this is on that place (in the ActivitiesHelper Class) not available/possible!
public class InfoViewModel : MvxViewModel
{
public InfoViewModel()
{
Info info = new Info();
info.Key = "ITS A KEYY";
info.Value = "here we got a value";
ObservableCollection<Info> asd = new ObservableCollection<Info>();
asd.Add(info);
Infos = asd;
}
private ObservableCollection<Info> infos = new ObservableCollection<Info>();
public ObservableCollection<Info> Infos
{
get
{
return infos;
}
set
{
infos = value;
RaisePropertyChanged(() => Infos);
}
}
}
Any suggestions?
I have no idea what you are talking about. Seriously, you've just dumped a lot of stuff on the screen.
I think you've gotten yourself very confused - good luck trying to work out what on earth you've done.
One basic answer is that you can navigate to an Mvx-based Activity anywhere you want to simply by:
creating an MvxViewModelRequest - https://github.com/slodge/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross/ViewModels/MvxViewModelRequest.cs
converting the request to an Intent using the IMvxAndroidViewModelRequestTranslator singleton - https://github.com/slodge/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Droid/Views/IMvxAndroidViewModelRequestTranslator.cs
starting that Intent
However, I seriously suggest you step out of your current mess and consider a cleaner application flow.
One of the Activities in my app starts/binds to a service (also part of my app). I would like that service to continue running as long as the app as a whole is still in the foreground, regardless of which Activity is active. But I need to make sure that the service is stopped when the app as a whole is paused (home button/back button).
How can I do that on an application level rather than an Activity level?
The easiest way is to have a singleton which keeps a track of the state of each activity, e.g showing just one activity as an example:
public class ActivityStates {
private static ActivityStates ref = null;
private static int firstAct = ACTIVITY_GONE;
public static synchronized ActivityStates getInstance() {
if (ref == null) {
ref = new ActivityStates();
}
return ref;
}
public int getFirstAct() {
return firstAct;
}
public void setFirstAct(int arg) {
this.firstAct = arg;
}
}
..
and define some static constants that you can import
public static final int ACTIVITY_GONE = 0;
public static final int ACTIVITY_BACKGROUND = 1;
public static final int ACTIVITY_FOREGROUND = 2;
then in each activity have a method
private void setActivityState(int state){
ActivityStates as = ActivityStates.getInstance();
as.setFirstAct(state);
}
Then in your onResume(), onPause, onDestroy() you can set the activitiy's state when you enter these methods, e.g in onResume have
setActivityState(ACTIVITY_FOREGROUND)
in onDestroy() have
setActivityState(ACTIVITY_GONE)
Then in you service, or wherever you want , you can use the get methods to find out the state of each activity and decide what to do.