Counrdown timer with service not working in the fragment - android

I wanna implement a Countdown timer with updating TextView and a service so the counting can keep going if the app is in background, foreground or even fully closed.
I examined these codes in a simple project and they worked very well
Service
public class MyService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final Integer[] timeRemaining = {intent.getIntExtra("TimeValue", 0)};
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Intent intent1local = new Intent();
intent1local.setAction("Counter");
timeRemaining[0]--;
if (timeRemaining[0] <= 0) {
timer.cancel();
}
intent1local.putExtra("TimeRemaining", timeRemaining[0]);
sendBroadcast(intent1local);
}
},
0, 1000);
return super.onStartCommand(intent, flags, startId);
}
}
Main Activity
public class MainActivity extends AppCompatActivity {
private TextView textView;
private EditText editText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(this,
new String[]{FOREGROUND_SERVICE},
PackageManager.PERMISSION_GRANTED);
textView = findViewById(R.id.textView);
editText = findViewById(R.id.editText);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("Counter");
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Integer integerTime = intent.getIntExtra("TimeRemaining",
0);
textView.setText(integerTime.toString());
}
};
registerReceiver(broadcastReceiver, intentFilter);
}
public void startButton(View view) {
Intent intentService = new Intent(this, MyService.class);
Integer integerTimeSet =
Integer.parseInt(editText.getText().toString());
intentService.putExtra("TimeValue", integerTimeSet);
startService(intentService);
}
}
But when i implement these codes in an app with fragments (Service codes are in a seperate service class and i put MainActivity codes in a fragment), if you close the app, everything will gone off and you will get an error.
Please help me
I need your detailed advices.

Related

Running countdown timer faster when i back to activity

I make a service for countdown timer, in activity i put a text view for show time every seconds: 100 - 0, but when i leave activity and back to that. i see timer as run very fast, but i want to this run just every second. where is problem ?
MainActivity:
public static final String mBroadcastIntegerAction = "com.example.broadcast.integer";
private IntentFilter mIntentFilter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showTime = (TextView) findViewById(R.id.textView1);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(mBroadcastIntegerAction);
Intent serviceIntent = new Intent(this, AppServiceDay.class);
startService(serviceIntent);
}
#Override
public void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(mBroadcastIntegerAction)) {
int second = intent.getIntExtra("Time", 0);
showTime.setText("" + second);
}
}
};
#Override
protected void onPause() {
registerReceiver(mReceiver, mIntentFilter);
// unregisterReceiver(mReceiver);
super.onPause();
}
Service:
public class AppServiceDay extends Service {
CountDownTimer cdt;
public static Handler mHandler;
int downer = 1000;
int time = 100;
int mainTime = 100000;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
cdt = new CountDownTimer(mainTime, downer) {
#Override
public void onTick(long millisUntilFinished) {
time -= 1;
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(MainActivity.mBroadcastIntegerAction);
broadcastIntent.putExtra("Time", time);
sendBroadcast(broadcastIntent);
}
#Override
public void onFinish() {
time = 100;
this.start();
}
};
cdt.start();
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
onStartCommand is triggered everytime startService is called and in onStartCommand you are creating new countdown object,
Add a null check before creating new countdown object it will fix your duplicate timer running at same time.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
If(cdt == null) {
cdt = new CountDownTimer(mainTime, downer) {
#Override
public void onTick(long millisUntilFinished) {
time -= 1;
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(MainActivity.mBroadcastIntegerAction);
broadcastIntent.putExtra("Time", time);
sendBroadcast(broadcastIntent);
}
#Override
public void onFinish() {
time = 100;
this.start();
}
};
cdt.start();
}
return super.onStartCommand(intent, flags, startId);
}

Best practices for running worker threads for periodically updating the UI

What are the best practices for running worker threads in the background that periodically update UI elements in an activity. The goal here is to avoid any screen freezing on any kind of updates and if there are any specific guidelines/standards that should be followed.
Try Service for Background Work.
I have made an example for you.
Try this.
TestActivity.java
public class TestActivity extends AppCompatActivity {
private final String TAG = "TestActivity";
public final static String RECEIVER_ACTION = "com.action.MyReceiverAction";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_work);
registerMyReceiver();
startService(new Intent(this, BackgroundService.class));
}
MyReceiver myReceiver = new MyReceiver();
private void registerMyReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(RECEIVER_ACTION);
registerReceiver(myReceiver, intentFilter);
}
class MyReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "onReceive() called");
}
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myReceiver);
}
}
BackgroundService.java
public class BackgroundService extends Service {
private String TAG = "BackgroundService";
#Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate() called");
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind() called");
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand() called");
notifyToUI();
return super.onStartCommand(intent, flags, startId);
}
/**
* This Methd will notify your Activity
*/
private void notifyToUI()
{
Intent myIntent = new Intent();
myIntent.setAction(TestActivity.RECEIVER_ACTION);
sendBroadcast(myIntent);
}
}
Now at the end register BackgroundService in AndroidManifest.xml file
<service android:name=".BackgroundService"/>
Use AlarmManager (or some other timer) to periodically start a service. That service then updates the model, and notifies UI thread with for example LocalBroadcastManager. UI thread can then use BroadcastReceiver to catch the Intent and update itself.

Broadcast receiver is not working when app on foreground or active

I am building app regarding battery indicator and i am using code from this post.
Getting battery status even when the application is closed
it is working fine when app is closed, but when an app is active or on foreground it did not work or did not send any broadcast.
This is main activity from i start service
public class Main extends Activity {
private MyService service;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (service == null) {
Intent i = new Intent(this, MyService.class);
startService(i);
}
finish();
}
}
Following is the service code.
public class MyService extends Service{
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyService", "onStartCommand");
// do not receive all available system information (it is a filter!)
final IntentFilter battChangeFilter = new IntentFilter(
Intent.ACTION_BATTERY_CHANGED);
// register our receiver
this.registerReceiver(this.batteryChangeReceiver, battChangeFilter);
return super.onStartCommand(intent, flags, startId);
}
private final BroadcastReceiver batteryChangeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
checkBatteryLevel(intent);
}
};
private void checkBatteryLevel(Intent batteryChangeIntent) {
// some calculations
final int currLevel = batteryChangeIntent.getIntExtra(
BatteryManager.EXTRA_LEVEL, -1);
final int maxLevel = batteryChangeIntent.getIntExtra(
BatteryManager.EXTRA_SCALE, -1);
final int percentage = (int) Math.round((currLevel * 100.0) / maxLevel);
if(percentage==100)
{
Intent intent = new Intent(getBaseContext(), Last.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(intent);
}
// do not forget to unregister
unregisterReceiver(batteryChangeReceiver);
} }
And when following activity start i did not receive any broadcast.
public class Last extends Activity {
Button btnCancel;
Uri notification;
Ringtone r;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_last);
notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
btnCancel = (Button) findViewById(R.id.stopsound);
btnCancel.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
r.stop();
}
});
} }
As I understood,
when you start application in first time, you see nothing, just service is started and a broadcast receiver is registered. When battery level will be changed, the method checkBatteryLevel() is calling and the broadcast receiver will be unregistered. As result you have never received a new changing of battery level.

Running in background timer

I have a timer but I want it to also run in the background, I created a new Service, I think it works but I have a problem with it, I want also to change the layout attributes, like changing TextView text using setText method, I prefer doing it with BroadCastReceiver so I have the following code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
IntentFilter filter = new IntentFilter();
filter.addAction("SOME_ACTION");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
textView.setText("hey");
}
};
registerReceiver(receiver, filter);
buttonStart = (Button) findViewById(R.id.start);
buttonStart.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startService(new Intent(MainActivity.this, LocalService.class));
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
I registered here the Receiver so it will happen when I am broadcasting from the Service and change the text to "hey" - I wanted it just to check if the broadcast is working. on the Service I used a code that runs a timer and when it start it will broadcast the message, it is the first time I am using broadcasting receiver for sending actions and not just to wait until Bluetooth is on and stuff like this, here is my Service code:
public class LocalService extends Service
{
private static Timer timer = new Timer();
public IBinder onBind(Intent arg0)
{
return null;
}
public void onCreate()
{
super.onCreate();
startService();
}
private void startService()
{
timer.scheduleAtFixedRate(new mainTask(), 0, 5000);
}
private class mainTask extends TimerTask
{
public void run()
{
Intent intent = new Intent();
intent.setAction("SOME_ACTION");
sendBroadcast(intent);
}
}
public void onDestroy()
{
super.onDestroy();
}
}
Thanks for helping.

My service stop after the back button

I have a service and an activity that communicate.
When I click the button(I have galaxy s3 there is only one button) then my activity of course disapear and my service is keep running but if I click the back (touch) button then my service is destroyed.
How can I change that?I want the service to keep running untill the activity destroys it.
EDIT
Here is the code:
Service:
public class MyService extends Service
{
private static final String TAG = "BroadcastService";
public static final String BROADCAST_ACTION = "com.websmithing.broadcasttest.displayevent";
private final Handler handler = new Handler();
private Intent intent;
int counter = 0;
#Override
public void onCreate()
{
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
}
#Override
public void onStart(Intent intent, int startId)
{
// handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000); // 1 second
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
DisplayLoggingInfo();
handler.postDelayed(this, 1000); // 10 seconds
}
};
private void DisplayLoggingInfo() {
intent.putExtra("counter", String.valueOf(++counter));
sendBroadcast(intent);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
handler.removeCallbacks(sendUpdatesToUI);
super.onDestroy();
}
}
Activity:
public class MainActivity extends Activity {
private static final String TAG = "BroadcastTest";
private Intent intent;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, MyService.class);
startService(intent);
registerReceiver(broadcastReceiver, new IntentFilter(MyService.BROADCAST_ACTION));
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}
};
#Override
public void onDestroy() {
super.onPause();
unregisterReceiver(broadcastReceiver);
stopService(intent);
}
private void updateUI(Intent intent)
{
String counter = intent.getStringExtra("counter");
Log.d(TAG, counter);
TextView txtCounter = (TextView) findViewById(R.id.textView1);
txtCounter.setText(counter);
}
}
you can put your app in the background instead off finishing it.
#Override
public void onBackPressed() {
moveTaskToBack(true);
// super.onBackPressed();
}
Ofcourse your service stops, when you press the back button. The back button most calls finish() on the activity, and it is destroyed. When you press the other button (the home button), it just minimizes your app, and it will be only destroyed later, when the OS wants to free up space.
If you want to keep your service running, make it a foreground service, and dont stop it on activity destroy.

Categories

Resources