I have an app in which when a user's post gets liked, I want the user to get a notification.
I can use the ChildValueEventListener but that is too fast.
I don't want the user to get bombarded with notifications every time a 'like' happens. Because if another user constantly keeps 'liking' and 'unliking' a post, the post author user will be bombarded with notifications.
My plan is to run the SingleValueEventListener inside a Runnable/Handler and check for notifications every 20 seconds. Something like this below:
Handler handler = new Handler();
int delay = 20000; // 20 seconds
handler.postDelayed(new Runnable(){
public void run(){
databaseRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChild("USER_NOTIFICATION") {
// new notification exists - alert user
}
handler.postDelayed(this, delay);
}
}, delay);
I have two questions. 1) Is it okay to do this? I mean, is it expensive fetch for data every x seconds? 2) Is it okay to run that piece of code inside a Service so that user can still get notifications even when the app is closed or killed?
You're in one go negating the biggest advantage of the Firebase Database (its realtime updates), and reintroducing a big disadvantage it solves (each time you will now download all data, instead of only getting incremental updating).
You're likely better off instead throttling the number of changes you surface to your users in the client-side code. So use a regular ChildValueEventListener and simply throttle the updates on the client.
E.g.
public void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
if (System.currentTimeMillis() - lastShownTimestamp > 20000) {
// TODO: show latest data on screen
lastShownTimestamp = System.currentTimeMillis();
}
}
Related
I am creating a game which uses "Energy points" as a currency to do certain actions in the game (you have to spend energy points to do certain tasks). When the player reaches zero energy points, or does not have enough energy to do a certain task, I they should wait a few hours in order to continue, or watch a video in order to get some quick points.
This should have the following features:
I've created a PopupDialog using the following code. The function showPopupDialog() is naturally called if the condition energyCost < energyPoints.
public void showPopupDialog(){
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle("Not Enough Energy!");
dialog.setMessage("You don't have enough Energy Points to do this!
Would you like to watch a video to get more Energy?");
((AlertDialog.Builder) dialog).setPositiveButton("Watch", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//ad plays here
energyPoints = energyPoints + 500;
ep.setText(energyPoints+"");
}
});
((AlertDialog.Builder) dialog).setNegativeButton("Wait", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
energyPoints = energyPoints+500;
ep.setText(energyPoints+"");
}
}.start();
}
});
dialog.show();
}
I would like to know how to make the following modifications:
The countdown timer should persist even though the app is closed or I navigate away from the activity. So that when I come back in 4 hours, some energy points will be restored.
You cannot click on "Wait" (thus triggering another timer) while a current timer is in progress. You have to wait for the alloted time before you can click it again.
The game sends a notification when the waiting is over so that the player knows to continue.
To be accurate the easiest way would be a server/client interaction so that you can't just manipulate the time by setting it to 4h later.
If manipulating is okay for you - just read/write the latest time set in an external file.
Without knowing a lot of the code, I will suggest a concept.
Use the timer itself for a presentational purpose, but for a real working logic, create a timestamp of "last poinst added", or something like that.
This will allow you to, every time you need to use, show or get actual points, grab the last timestamp, compare it with the current time, and act accordingly. For example, I check the last one, and when compared, the difference is 3h. If every ten minutes I have 5 points, I'll do 3*60/10 * 5 = total points earned.
This will allow to just focus on the fact that time has passed, instead of making a timer.
Then, when the application closes, you store the last timestamp, and when reopened, compare it again and act accordingly.
I've created a javafx application which includes a time-tracking function that tracks the amount of time the application has been open(run) for. I know about System.currentTimeMillis(), but I was wondering if it was possible to create a button (that serves no function as a button - I just needed to use a JFX button which looks nice) that shows(prints) the amount of time spent in the app. Something like a real-time counter where the time increases by itself.
Something similar to this: https://www.youtube.com/watch?v=f8LOflGG8g8
Except, however, instead of using animations, using text instead.
Just use an AnimationTimer to update the text:
public class MyApp extends Application {
#Override
public void start(Stage primaryStage) {
long startTime = System.currentTimeMillis();
Label timerLabel = new Label();
new AnimationTimer() {
#Override
public void handle(long now) {
long elapsedMillis = System.currentTimeMillis() - startTime ;
timerLabel.setText(Long.toString(elapsedMillis / 1000));
}
}.start();
// lay out UI etc etc
}
}
Create a Thread class
Start it whenever you like, and pass the current time as an argument to the above class (System.currentTimeMillis())
Inside the thread, have a loop, and a Thread.sleep(1000); at the end. Every time the loop goes, have it subtract the time you passed along in step 2 from the current time like this: System.currentTimeMillis() - startTime
Use the proper async GUI update methods to update the button you want. You can divide your calculated time by 1000 to get the seconds, another 60 to get the minutes, and another 60 to get the hours.
I am a newbie to android development so bear with me. I have scoured the site and implemented several suggested answers but I am still running into a problem. I want to iterate through an object array and display the contents of the array with delay to allow user interaction(The user gets to say if the object and the text displayed is what they were looking for by clicking on a yes or no button). My objects however display last first and then start zooming real fast in a seemingly endless loop. Here is the method I call to load the images:
private void displayInstructions() {
for (Emergency_Instructions instruction : instructions) {
final Emergency_Instructions instruction2 = instruction;
final Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
public void run() {
displayimages(instruction2.getStep(), instruction2.getStepImage());
handler.postDelayed(this, 5000);
}
}, 5000);
}
void displayimages(String text, Bitmap image)
{
instructiontext.setText(text);
instructionbmp.setImageBitmap(image);
}
Any help will be greatly appreciated
You create multiple Handlers where you need only one. You tell each one to post a Runnable to the current thread's message queue, to be run after the same delay. That delay expires at pretty much the same time for all the tasks, so they are then executed one right after another, as fast as the queue can go. Each of those tasks also posts a message via the handler, to be run after the same delay. Once that delay expires, that will produce a second group of messages posted rapidly one right after the other, as fast as the device can go.
If you just want to schedule what is effectively a slide show, you might do it like this:
private void displayInstructions() {
final Handler handler = new Handler();
int delay = 0;
int step = 5000;
for (Emergency_Instructions instruction : instructions) {
final Emergency_Instructions instruction2 = instruction;
handler.postDelayed(new Runnable() {
public void run() {
displayimages(instruction2.getStep(), instruction2.getStepImage());
// handler.postDelayed(this, 5000);
}
}, delay);
delay += step;
}
}
Note there that each task is posted with a larger delay than the last -- this is a delay with respect to when the message it posted, not with respect to when the preceding message was displayed.
With that said, I'm doubtful that this is really what you want to do, or at least that it is all you want to do. As it stands, this approach will cause all the messages to be displayed (eventually) regardless of any user interaction. At minimum, you will probably want to provide for subsequent messages to be canceled in the event that the user accepts one, or cancels the overall operation.
I'm writing an android app which should take pictures in a user-defined interval (20 sec - 1 min). It should take the pictures even while it is running in background or while the device is sleeping. The app will run for a very long time period. If it is necessary to wake up the device, it should put back to sleep as soon as possible to save batterie life. After taking a picture the app will process some additional work (comparison of two pictures).
I read some stuff about sheduling alarms (http://developer.android.com/training/scheduling/alarms.htm), creating Services (also # android training) and Android AsyncTasks, Java threads (http://www.mergeconflict.net/2012/05/java-threads-vs-android-asynctask-which.html)
... but I'm still not sure what is the best way to achieve this.
My questions are:
Should I use thread or a task to take the pictures in background?
(the comparison of the two pictures might take longer than a few
milliseconds but i don't know anything about the cpu load of this
operation)
Should I use an alarm to wake the device up or are there any alternative solutions?
How can both (alarms and thread/task) work together? (Include the Alarm in the Task/Thread?)
Many thanks for your help in advance.
As to our question I know I can help get started with the aspect of repeating the picture taking task at a user defined time interval. For such a task you can user a Timer to achieve this. The code would look something like this:
mTmr = new Timer();
mTsk = new TimerTask() {
#Override
public void run() {
//Take picture or do whatever you want
}
};
mTmr.schedule(mTsk, 0, USER_DEFINED_EXECUTION_INTERVAL);
schedule begins the timer. The first parameter of schedule used here is the task to run which is mTsk. The second parameter is the delay until the first execution (in milliseconds), in this case no delay. The third parameter is what you'll want to manipulate which is the interval of executions. The parameter is the time between executions so if it were 20 seconds you'd pass in 20,000. If it were a minute it would be 60,000. You can get this value from the user using any method you'd like.
To keep the timer running make sure you don't call mTmr.cancel in onPause because for your case you want to keep the timer running while the user isn't on the app. Not calling cancel means the timer will hold it's resources until the app is closed by the user.
OR you can look at this How to schedule a periodic task in Java? If you'd like to use ScheduledExecutorService instead of a Timer.
I have made this app - Lenx. It uses Camera extensively and I am processing image in the background. I have used AsyncTask to process the image and it has never given any problems. The app also has a timer which starts the process after certain interval. The logic that I have used is very simple.
I have not used Camera2 API yet, so the code might be deprecated. I created CameraPreview class which implements Camera.PreivewCallback.
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (data == null) {
return;
}
int expectedBytes = previewWidth * previewHeight *
ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
if (expectedBytes != data.length) {
Log.e(TAG, "Mismatched size of buffer! Expected ");
mState = STATE_NO_CALLBACKS;
mCamera.setPreviewCallbackWithBuffer(null);
return;
}
if (mProcessInProgress || mState == STATE_PROCESS_IN_PROGRESS) {
mCamera.addCallbackBuffer(data);
return;
}
if (mState == STATE_PROCESS) {
mProcessInProgress = true;
processDataTask = new ProcessDataTask();
processDataTask.execute(data);
}
}
public void startProcessing() {
mState = STATE_PROCESS;
}
And my AsyncTask is something like this
private class ProcessDataTask
extends
AsyncTask<byte[], Void, Boolean> {
#Override
protected Boolean doInBackground(byte[]... datas) {
mState = STATE_PROCESS_IN_PROGRESS;
Log.i(TAG, "background process started");
byte[] data = datas[0];
long t1 = java.lang.System.currentTimeMillis();
// process your data
long t2 = java.lang.System.currentTimeMillis();
Log.i(TAG, "processing time = " + String.valueOf(t2 - t1));
mCamera.addCallbackBuffer(data);
mProcessInProgress = false;
return true;
}
#Override
protected void onPostExecute(Boolean result) {
mState = STATE_PROCESS_WAIT;
}
}
onPreviewFrame() will always get called as long as the camera preview is running. You need to take the data and process it only when you trigger something. So simply change the state of a variable, in this case, mState, and based on the state, call your AsyncTask.
I done simple timer that count the difference between time of clicking of button, and current time. Every second (1000ms).
The main part is :
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
MainActivity.this.timerHandler.postDelayed(this,1000);
long mlSecondToGo;
mlSecondToGo = System.currentTimeMillis() - MainActivity.this.clickedButtonTime;
MainActivity.this.timerTextView.setText(Long.toString(mlSecondToGo));
}
};
Whole code : https://gist.github.com/anonymous/7830279
I wonder why it the "1000ms" delay of the handler:
MainActivity.this.timerHandler.postDelayed(this,1000);
is delayed of 1-3 every time I call it.
I mean the TextView shows:
1001 then 1002 then 3004 and so on.
I made the video of it (using of Android's 4.4 screenrecord command from ADB)
http://youtu.be/TyFyS6k5L5c
Thank you very much for an answer.