Create a Scheduled service in android - java

I need to create a schedule service in android with java. I have tried some codes , but all time after build the application it doesn't run. My logic is simple , I want to make a service to check the existence of a file in the bluetooth folder path, If this file is there , so this service will run another application , I need this with a schedule which run every 2 minutes.
Until now that's great, but now I have an error The method startActivity(Intent) is undefined for the type MyTimerTask. I have tried this code...
public class MyTimerTask extends TimerTask {
java.io.File file = new java.io.File("/mnt/sdcard/Bluetooth/1.txt");
public void run(){
if (file.exists()) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName("com.package.address","com.package.address.MainActivity"));
startActivity(intent);
}
}
}
Could someone please help me with this.

There are two ways to achieve your requirement.
TimerTask
Alarm Manager Class
TimerTask has a method that repeats the activity on the given particular time interval. look at the following sample example.
Timer timer;
MyTimerTask timerTask;
timer = new Timer();
timerTask = new MyTimerTask();
timer.schedule ( timerTask, startingInterval, repeatingInterval );
private class MyTimerTask extends TimerTask
{
public void run()
{
...
// Repetitive Activity goes here
}
}
AlarmManager does same thing like TimerTask but as it occupies lesser memory to execute tasks.
public class AlarmReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
try
{
Bundle bundle = intent.getExtras();
String message = bundle.getString("alarm_message");
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
catch (Exception e)
{
Toast.makeText(context, "There was an error somewhere, but we still received an alarm", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
AlarmClass,
private static Intent alarmIntent = null;
private static PendingIntent pendingIntent = null;
private static AlarmManager alarmManager = null;
// OnCreate()
alarmIntent = new Intent ( null, AlarmReceiver.class );
pendingIntent = PendingIntent.getBroadcast( this.getApplicationContext(), 234324243, alarmIntent, 0 );
alarmManager = ( AlarmManager ) getSystemService( ALARM_SERVICE );
alarmManager.setRepeating( AlarmManager.RTC_WAKEUP, ( uploadInterval * 1000 ),( uploadInterval * 1000 ), pendingIntent );

Related

Can't cancel a notification after updating it

I'm developing a countdown app, and currently trying to show a notification when you exit the app while the countdown is running. Correspondingly, I want the notification to disappear when the user returns to the app.
So far I've managed to make it work for a simple notification with static text, do the following: in MainActivity.java, in onStop(), I create an intent and initiate the service with startService(intent). Symmetrically, in onStart() I run stopService(intent) so that when you return to the app the service gets canceled. This works like a charm, the notification appears and disappears when it must.
The next step has been trying to make the notification show a text that varies (it will say "X minutes remaining"). According to the info out there, to update an existing notification you have to create a new one, give it the same ID as the existing one, and call .notify of a NotificationManager. When I do this the notification indeed gets updated correctly (the text changes as expected), BUT: now, returning to the main activity does not cancel the notification. The icon stays up there and doesn't get interrupted.
I've been trying to solve this for hours and hours. I've also tried hacks like sending signals via shared preferences to tell the service to stop, but for some reason, it seems to completely ignore the command stopself() too.
Does anybody have a suggestion of what could be the cause? Any help would be greatly appreciated. Here is the relevant code:
MainActivity.java:
#Override
protected void onStart() {
super.onStart();
Intent serviceIntent = new Intent(getBaseContext(), CounterService.class);
stopService(serviceIntent);
}
protected void onStop() {
super.onStop();
Intent serviceIntent = new Intent(getBaseContext(), CounterService.class);
startService(serviceIntent);
}
CounterService.java:
public class CounterService extends Service {
Notification notification;
NotificationManager notificator;
Intent intentNoti;
CountDownTimer counter;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
intentNoti = new Intent(this, MainActivity.class);
final PendingIntent pending = PendingIntent.getActivity(this, 0, intentNoti, 0);
final Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.common_full_open_on_phone);
//Countdown
counter = new CountDownTimer (30000, 1000) {
public void onTick(long millisUntilFinished) {
String time = String.valueOf(System.currentTimeMillis());
notification = new Notification.Builder(CounterService.this)
.setContentTitle("Name")
.setContentText(time)
.setSmallIcon(R.drawable.icon_start)
.setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pending)
.setOngoing(true).build();
notificator = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificator.notify(1001, notification);
}
public void onFinish() {
}
}.start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
counter.cancel();
}
}
First create a Timer like this
private Timer timer;
private TimerTask timerTask;
public void startTimer() {
timer = new Timer();
timerTask = new TimerTask() {
public void run() {
// Add your code
}
};
timer.schedule(timerTask, 1000, 1000); //
}
Also you need to stop your timer.
So
public void stoptimertask() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
Call StartTimer and StopTimer in OnStartCommand() and onDestroy() respectively. Add these lines in onDestroy()
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("restartservice");
broadcastIntent.setClass(this, Restarter.class);
this.sendBroadcast(broadcastIntent);
it can be handled in multiple ways, you have not stopped your timer
Note:- posting code in Kotlin
1)
override fun onDestroy() {
counter.cancel()
}
in your activity
override fun onResume() {
super.onResume()
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancelAll()
}

Encapsulating alarm creation code in a different class than the Activity

I'm creating my first Android Notifications app, so I'm very much a beginner. I have a class, Notification.java, that asks the user for the time and date. Using these data, it creates an alarm that is triggered at the specified date and time.
Here is my code for Notification.java
public class Notification extends Activity {
private PendingIntent pendingIntent;
private SetAlarm alarm;
private Date date;
private Time time;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm);
findViewById(R.id.setTime).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setAlarmTime();
}
});
findViewById(R.id.setDate).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setAlarmDate();
}
});
findViewById(R.id.checkBox).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
createAlarm();
}
});
}
private void setAlarmTime() {
}
private void setAlarmDate() {
}
private void createAlarm() {
alarm = new SetAlarm();
}
}
The createAlarm() method is supposed to actually create the alarm using the information that the user has provided (i.e. time and date). However, I understand that I need the following code block to create the alarm?
private void setTheAlarm() {
Intent alarmIntent = new Intent(SetAlarm.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(SetAlarm.this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval;
/* Set the alarm to the date specified by user */
/* Repeating on every x minutes interval */
}
However, the Notification.java is where I am extending 'Activity'. It is also where I have the 'pendingIntent; code.
So essentially, how can I move the alarm creation code into a separate class when the code dealing with the Activity is in an entirely different class?
Thanks for the help. I hope my question is clear enough.
Not exactly clear if that is what you want, but if I understand you correct, you need the alarmManager inside an extra class to reach it from everywhere? You could make a static one like this:
public class MyAlarmManager{
private static AlarmManager mAlarmManager;
private static PendingIntent mPendingIntent;
//start alarm
public static void setAlarm(Context context, int alarmId, long alarmTime) {
if (mAlarmManager== null) {
mAlarmManager= (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
Intent startAlarmIntent = new Intent(context, YouReceiver.class);
if(mPendingIntent==null){
mPendingIntent = PendingIntent.getBroadcast(context, alarmId,
startAlarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
//check the version because of doze mode since MM
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
alarmTime, mPendingIntent);
} else {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime, mPendingIntent);
}
}
//stop alarm
public static void stopAlarm(Context context, int id) {
if (mAlarmManager == null) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
Intent stopAlarmIntent = new Intent(context, YourReceiver.class);
if(mPendingIntent==null){
mPendingIntent= PendingIntent.getBroadcast(context, id, stopAlarmIntent, 0);
}
mAlarmManager.cancel(mPendingIntent);
mPendingIntent.cancel();
}
}
Then you can call it like:
MyAlarmManager.setAlarm(this, id, interval);
and stop it:
MyAlarmManager.stopAlarm(this, id);
You can do this from every class by passing the context and the identical id . The alarm id must be the same as you passed by starting the alarm, otherwise it will not work. Notice that above MarshMallow, there are some changes for AlarmManager and it´s possible that it does not work in every case. If your app get´s killed or goes into idle mode, the alarm won´t be triggered in every circumstance. To handle doze mode, see this:https://developer.android.com/training/monitoring-device-state/doze-standby.html
And be aware of any third party app and battery managers, that could kill your app. Also, Huawei devices have their own battery management besides the doze mode.
If this is not what you wanted, come back. Can´t guarantee that there is no error because I have overseen something, it´s from scratch.

Android - Call a function from outside an activity (through AlarmManager and Notification)

Ok, so I have a main activity called 'Main.java'. This main activity starts an AlarmManager which fires an intent leading to 'AlarmReceiver.java'.
This 'AlarmReceiver.java' then creates a notification which has two buttons on it. One of the buttons is a deletion button, and so when the user clicks on that button, another intent is fired, leading it to 'DelPair.java'.
In DelPair.java, I modify a table in a Database, but then I need the UI of Main.java to reflect this change. I have created two functions in Main.java called updateArrayFromDB() and updateUIFromArray() to do this for me:
updateArrayFromDB() will sync an ArrayList created in Main.java to a
certain table in the DB.
updateUIFromArray() will change the UI of
Main.java to represent the ArrayList that has just been changed.
The problem is that I cannot call these two functions from DelPair.java (they don't exist in that space). I have come across Serializables in trying to find an answer but I don't know enough to know if they apply here or exactly how to implement them across the AlarmManager and the NotificationManager.
How can I access these methods from DelPair.java?
In Main.java:
public void updateArrayFromDB(){
//... The code for this is long and irrelevant
}
public void updateUIFromArray(){
//... The code for this is long and irrelevant
}
private void SendNotification() {
Intent intent = new Intent(this, AlarmReceiver.class);
//...
PendingIntent sender = PendingIntent.getBroadcast(this, 2 , intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, 5000, notif_freq, sender);
}
In AlarmReceiver.java:
Intent delPairI = new Intent(context, DelPair.class);
PendingIntent delPairPI = PendingIntent.getService(context, 0, delPairI, PendingIntent.FLAG_UPDATE_CURRENT);
Notification noti;
noti = new Notification.Builder(context)
//...
.addAction(R.drawable.ic_delete_icon, "Delete the thing", delPairPI)
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, noti);
and then in DelPair.java:
public class DelPair extends IntentService {
//...
#Override
protected void onHandleIntent(final Intent intent) {
//...
Intent it = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
getApplicationContext().sendBroadcast(it);
handler.post(new Runnable() {
#Override
public void run() {
//... here is where I update the database, which works perfectly
//now need to update the UI and array in Main.java
updateArrayFromDB(); //these lines
updateUIFromArray(); //obviously don't work
}
});
}
}
Why not use broadcasts ? in onHandleIntent just send a broadcast
Intent i = new Intent();
i.setAction(CUSTOM_INTENT);
//put relevant data in intent
getApplicationContext().sendBroadcast(i);
The broadcast receiver:
public class IncomingReceiver extends BroadcastReceiver {
private MainActivity act;
public IncomingReceiver(MainActivity main){
this.act = act;
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(CUSTOM_INTENT)) {
System.out.println("GOT THE INTENT");
// call the method on act
}
}
}
In your activity onResume - register new IncomingReceiver, onPause unregister
private IncomingReceiver receiver;
public void onCreate(Bundle bOs){
//other codes
receiver = new IncomingReceiver(this);
}
#Override
protected void onResume() {
IntentFilter filter = new IntentFilter();
filter.addAction(CUSTOM_INTENT);
registerReceiver(receiver, filter);
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(receiver);
super.onPause();
}
Since you need to have an updated UI based on database changes, you can call updateArrayFromDB() and updateUIFromArray() in the onResume() method of your activity so the UI gets updated each time the user enters the activity.

Android sticky service is beeing killed loosing all information

I have service which is basically timer. It receives object with location data, start time, user id etc, and every seconds it increments stop value. I'd like to have this service running non-stop until stopped in application. I've read that i need to start this service as sticky, so i did that. But I've noticed that after my main application is beeing killed by system or user, service restarts and lose all information (about current timers running etc - I have there array with list of objects).
Idea of that service was that:
user clicks button in app -> service is starting and counting time changing information in notification bar and sending broadcast to main application -> I wish to continue updating notification bar even if app is killed by user or system.
My class below:
public class TimerService extends Service{
private NotificationCompat.Builder builder;
private static JsonHistoryList activities;
private Intent intent;
private Handler handler;
private Runnable sendUpdateToUi = new Runnable() {
#Override
public void run() {
sendBroadcast();
handler.postDelayed(this, 1000);
}
};
private NotificationManager mNotificationManager;
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(ACTION_ADD)){
JsonHistory item = (JsonHistory) intent.getSerializableExtra(HISTORY_ARG);
new NetworkAsyncTask().execute(ACTION_ADD_ID, item);
}else if(action.equals(ACTION_DELETE)){
int id = intent.getIntExtra(CATEGORY_ID_ARG, -1);
if(id > 0){
new NetworkAsyncTask().execute(ACTION_DELETE_ID, id);
}
}else if(action.equals(ACTION_CLEAR)){
activities.clear();
}
}
};
public TimerService() {
handler = new Handler();
}
private void sendBroadcast() {
Long time = new Date().getTime();
for(JsonHistory item: activities){
ContentValues values = new ContentValues();
values.put(History.C_STOP, time);
String[] selectionArgs = {String.valueOf(item.id)};
getContentResolver().update(History.URI, values, History.C_ID + "=?", selectionArgs);
item.stop = time;
}
intent.putExtra(ACTIVITY_LIST_ARG, activities);
Intent bIntent = new Intent(this, MainActivity.class);
bIntent.putExtra(CATEGORY_ARG, activities);
builder.setContentText(String.format(getString(R.string.notification_bar_message), activities.size()));
Notification barNotif = builder.build();
mNotificationManager.notify(SERVICE_ID, barNotif);
sendBroadcast(intent);
}
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_ADD);
filter.addAction(ACTION_DELETE);
filter.addAction(ACTION_CLEAR);
registerReceiver(receiver, filter);
intent = new Intent(ACTION);
handler.removeCallbacks(sendUpdateToUi);
handler.postDelayed(sendUpdateToUi, 1000);
activities = new JsonHistoryList();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if(intent != null && intent.hasExtra(TimerService.ACTIVITY_LIST_ARG)){
ArrayList<JsonHistory> temp = (ArrayList<JsonHistory>) intent.getSerializableExtra(TimerService.ACTIVITY_LIST_ARG);
if(temp != nu;; && temp.size() > 0)activities.addAll(temp);
}
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent bIntent = new Intent(this, MainActivity.class);
PendingIntent pbIntent = PendingIntent.getActivity(this, 0, bIntent, 0);
builder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(getString(R.string.app_name))
.setContentText(String.format(getString(R.string.notification_bar_message), activities.size()))
.setAutoCancel(true)
.setOngoing(true)
.setContentIntent(pbIntent);
Notification barNotif = builder.build();
this.startForeground(SERVICE_ID, barNotif);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
handler.removeCallbacks(sendUpdateToUi);
stopForeground(true);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private class NetworkAsyncTask extends AsyncTask<Object, Void, String>{
Gson gson;
public NetworkAsyncTask() {
super();
gson = new Gson();
}
#Override
protected String doInBackground(Object... params) {
Integer actionId = (Integer) params[0];
String result = null;
switch (actionId){
case ACTION_ADD_ID:
break;
case ACTION_DELETE_ID:
break;
default:
result = null;
break;
}
return result;
}
}
}
Thanks for any replies
When you stop the service it is true it loses its information if the application is destroyed. That is because that instance of the service is tied to that particular instance of the application.
In my opinion, an easy fix would be to store the information you still need in some type of persistent storage (SQLite, Internal/External Memory, Shared Preferences)
Then, every time you start your service with a new application launch just be sure to reload the information you want from whichever persistent storage method you choose.
Also, assuming you don't want this service to continue if the application is killed by the user, be sure to send an intent to the service to stop it like this:
intent = new Intent(this, BackgroundLocationService.class);
stopService(intent);

Code is fine(?), but app is running slow on Android (service+ intents)

So I've got 3 java files :
ServiceActivity - main activity where everything starts ( static int i is defined earlier in this file)
Elserwis - it is the service (it has a timer where I've passed the variable i -> it will be the hour since when the timer must turn on)
Sekundo - the intent where user puts the hour => >variable i<
Here is the fragment of code from main activity -> ServiceActivity:
private OnClickListener startListener = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(getApplicationContext(), Sekundo.class);
startActivityForResult(intent,1337);
}
};
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data ) {
/* Place out code to react on Activity-Result here. */
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1337){
i=data.getIntExtra("result",5);
Toast tost = Toast.makeText(getApplicationContext(), "ELO"+data.getIntExtra("result",0)+data.getIntExtra("result1",0), 1000);
tost.show();
startService(new Intent(SerwisActivity.this,Elserwis.class));
}
}
I think the problem is in the end, where startService lays (as a subfunction of onActivityResult)
If you need any other fragment of code I can paste it here, but the question is:
My app is running very slowly at the beginning when the timer starts, and the Toast shows for over 1 minute. Anyone know why?
EDIT:
public class Elserwis extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
okresowePowiadomienie();
Toast.makeText(getApplicationContext(),"Service LAUNCHED!", 1000).show();
}
Date data33 = new Date(111,11,SerwisActivity.i,2,25);
int d = data33.getDate();
Timer timer = new Timer();
public void okresowePowiadomienie(){
TimerTask timerTask = new TimerTask(){
public void run() {
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher,"OKRes",System.currentTimeMillis());
Intent notIntent = new Intent(getApplicationContext(), SerwisActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notIntent, 0);
notification.setLatestEventInfo(getApplicationContext(),"Powiadomienie x:","Kliknij aby d:usunac ;)t:"+d,contentIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(1335, notification);
// } };
}};
timer.scheduleAtFixedRate(timerTask ,data33 , 120000); }
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
Toast.makeText(this, "Service dead!", Toast.LENGTH_LONG).show();
}
}
thats just alpha version of my code but final will be similar ( now it only passes information about the day to my service -> in final version it should pass hour and minute)
The "Service LAUNCHED!" toast stays on for ages, it crashes most of the time on AVD, on my real smartphone it just takes long but still it should work smoothly...
Basically the problem started when i moved startService from onClick() function TO the onActivityResult. It needs to stay there because service uses the int i (user types types int i in the new intent) to set the data for my timer(timer is in the Elserwis). I've updated my first post with the service code so u can get what i mean
I'm GUESSING that startService itself is not causing any blocking.
I'm GUESSING that you have code in startService that takes awhile to complete and causes your application UI to lock up.
If this is the case, then what you would need to do is create a new thread inside your service before running the code that causes the delay.
You need to keep any long-running blocks of code in a separate thread to not block the UI. I would be interested in the code that is in Elserwis.class because that would help identify where the problem actually lies. Or if you look at your code and figure it out based on what I said, then you need not post any more code.

Categories