I'm coding a 'simple' notificator which consists on calling to a website, checking the response and notifying if there's something new.
I'm using a Service to do the http operations and I'd like AlarmManager to repeat the call to the Service with a given frequency. I've been checking tutorials like this and other examples and, since I want the service to be scheduled either whenever the user leaves the settings screen (the only Activity it has so far) and after BOOT is completed, so I created a class to wrap the scheduling code.
public class Scheduler {
public static boolean cancelScheduledService(Context ctx, Intent serviceIntent) {
boolean success = true;
Log.v("novUmbria", "Scheduler.cancelScheduledService");
try {
AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
am.cancel(
PendingIntent.getBroadcast(
ctx, 0,
new Intent(ctx, NotificadorService.class),
// si ya existe, no genera un 2º
PendingIntent.FLAG_CANCEL_CURRENT
)
);
Log.v("novUmbria", "Scheduler.cancelScheduledService Servicio cancelado");
} catch (Exception e) {
Log.e("novUmbria", "Scheduler.cancelScheduledService Excepción: " + e.getMessage());
success = false;
}
return success;
}
public static boolean scheduleService(Context ctx, Intent serviceIntent, long interval) {
boolean success = true;
Log.v("novUmbria", "Scheduler.scheduleService Servicio ");
try {
Calendar cal = Calendar.getInstance();
SimpleDateFormat timeformat = new SimpleDateFormat("HH:mm");
// timeformat.setTimeZone(TimeZone.getTimeZone("Europe/Madrid"));
AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(
// am.setInexactRepeating(
// AlarmManager.ELAPSED_REALTIME_WAKEUP,
AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
interval,
PendingIntent.getBroadcast(
ctx, 0,
new Intent(ctx, NotificadorService.class),
// si ya existe, no genera un 2º
PendingIntent.FLAG_CANCEL_CURRENT
)
);
Log.v("novUmbria", "Scheduler.scheduleService Servicio programado a las "
+ timeformat.format(cal.getTime())
+ " cada " + (interval / 60000) + " minutos"
);
startService(ctx, serviceIntent);
Log.v("novUmbria", "Scheduler.scheduleService Servicio iniciado"
);
} catch (Exception e) {
Log.e("novUmbria", "Scheduler.scheduleService Excepción: " + e.getMessage());
success = false;
}
return success;
}
public static boolean startService(Context ctx, Intent serviceIntent) {
boolean success = true;
Log.v("novUmbria", "Scheduler.startService");
try {
ctx.startService(serviceIntent);
Log.v("novUmbria", "Scheduler.startService Servicio iniciado");
} catch (Exception e) {
Log.e("novUmbria", "Scheduler.startService Excepción: " + e.getMessage());
success = false;
}
return success;
}
}
Here's the call to the scheduler from the settings Activity
//Settings Activity
#Override
protected void onStop() {
Log.v("novUmbria", "SettingsActivity.onStop");
Intent serviceIntent = new Intent(getApplicationContext(), NotificadorService.class);
Scheduler.cancelScheduledService(getApplicationContext(), serviceIntent);
long frequency = 1000 * 60 / 2;
Scheduler.scheduleService(getApplicationContext(),
serviceIntent,
frequency
);
Log.v("novUmbria", "SettingsActivity.onStop scheduleService");
super.onStop();
}
Thing is: logcat tells me the service gets scheduled (or, better said, that it doesn't raise an Exception) and it gets executed for the first time. But, after that, no matter how long or short the interval is, it never repeats. I've tried several flags RTC, RTC_WAKEUP, ELAPSED_REALTIME etc, but I got nothing.
My testing device is a Nexus 4 fully updated. I've even rebooted it, so I checked the BOOT_COMPLETE receiver worked ok, but it never repeats the service calls.
Any ideas on where's the problem?
Thanks in advance.
I've found the answer here.
Apparently, when you want to schedule a SERVICE, you don't use PendingIntent.getBroadcast but PendingIntent.getService.
Just that little change and it's repeating as it should.
Hope this helps someone else :)
Related
I am trying to create a notification service in my android app that always keeps listening to my RabbitMQ server for new messages. I want it to be able to send notifications even from background. Basically I am trying to create a notification communication between two client side application (App1 and App2) through Rabbit MQ and send notifications to both the apps in case of an event.
I have implemented it using JOB Service class but it is not consistent and it stops after sometime. Can someone please help me in understanding the architecture in a better way. How can I achieve something like Firebase Messaging Service but through Rabbit MQ?
Sample code that I have used below:
public class StoreOrderJobService extends JobService {
private static final String TAG = "JobService";
Random random = new Random();
SharedPrefManager prefManager;
private boolean jobCancelled = false;
#Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d(TAG, "Job Started");
prefManager = new SharedPrefManager(this);
subscribeStore(prefManager.getUserId(), jobParameters);
return true;
}
private void subscribeStore(String storeId, JobParameters parameters) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(HOST_IP);
factory.setAutomaticRecoveryEnabled(false);
String queueName = prefManager.getSessionId();
if (queueName != null) {
Thread subscribeStoreThread = new Thread(new Runnable() {
#Override
public void run() {
Log.d(TAG, "Job Started");
try {
if (jobCancelled) {
return;
}
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
Log.d("OrderService", "Session Id " + queueName);
channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName, "store_test", storeId);
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
Log.d("OrderService", "Received message " + message);
Envelope envelope = delivery.getEnvelope();
String routingKey = envelope.getRoutingKey();
if (routingKey.equals(storeId)) {
channel.basicAck(envelope.getDeliveryTag(), true);
String message_new = new String(delivery.getBody(), "UTF-8");
Gson gson = new Gson();
OrderSubscribePayload payload = gson.fromJson(message_new, OrderSubscribePayload.class);
Log.d("order Service", "Order Id " + payload.getOrderId());
sendOrderNotification(random.nextInt(), payload);
}
};
channel.basicConsume(queueName, false, deliverCallback, consumerTag -> {
});
} catch (TimeoutException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
}
}
});
subscribeStoreThread.start();
}
}
private void sendOrderNotification(int id, OrderSubscribePayload payload) {
Log.d("Service", "sendOrderNotification " + payload.getOrderId());
Intent contextIntent = new Intent(this, OrderDetails.class);
Bundle args = new Bundle();
args.putSerializable("orderDetails", (Serializable) payload);
contextIntent.putExtra("Bundle", args);
int iUniqueId = (int) (System.currentTimeMillis() & 0xfffffff);
PendingIntent pIntent = PendingIntent.getActivity(this, iUniqueId, contextIntent, 0);
Notification n = new NotificationCompat.Builder(this, ManagedApplication.CHANNEL_ORDER_ID)
.setContentTitle("New Order")
.setContentText("Received New Order")
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pIntent)
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.setColor(getResources().getColor(R.color.color_primary))
.setCategory(NotificationCompat.CATEGORY_REMINDER)
.build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE);
notificationManager.notify(id, n);
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
Log.d(TAG, "Job Cancelled");
jobCancelled = true;
return true;
}
}
I am calling this job on users login as below:
private void startNotificationJob() {
ComponentName componentName = new ComponentName(this, StoreOrderJobService.class);
JobInfo info = new JobInfo.Builder(123, componentName)
.setPersisted(true)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPeriodic(15 * 60 * 1000)
.build();
JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
int result = jobScheduler.schedule(info);
if (result == JobScheduler.RESULT_SUCCESS) {
Log.d("JOB Scheduler", "Job Scheduled");
} else Log.d("JOB Scheduler", "Job Scheduled Failed");
}
I have implemented it using JOB Service class but it is not consistent and it stops after sometime.
Nothing will be keeping your process running, which you will need for your desired functionality. Nothing will be keeping the CPU powered on all the time, which also will be needed for your desired functionality.
Please bear in mind that what you want is rather harmful to the battery life.
How can I achieve something like Firebase Messaging Service but through Rabbit MQ?
Use a foreground service, with a continuous partial WakeLock, in a separate process (android:process manifest attribute) than the UI of your app. You may also need code to deal with re-establishing your MQ connection as the device changes connectivity (e.g., from WiFi to mobile data) or loses and then regains connectivity.
You will also need to ask your users to go into the Settings app and try to opt your app out of all battery optimizations. Note that this will not be possible on all devices.
You will also need to ask your users to never kill your app's task. The separate process may help on some devices if users forget, but that behavior seems to vary by device.
And you will need to take into account that your solution will not be reliable, because some device manufacturers to prevent developers from doing the sorts of things that you want to do, as those things are bad for battery life.
Since I'm struggling a lot with the Android Oreo background restriction, I was asking myself if working with the AlarmManager is even the best way of timing Job execution to e.g. 03:00 AM. I saw some people use JobScheduler, but it seems it's not that suitable for executing tasks every day at a given time.
I was trying just AlarmManager with a BroadcastReceiver, then inserted the BroadcastReceiver in a (in theory) self-starting service, but since an app isn't able to call startService() when in background this also doesn't work the way it should (and also seems kinda wrong).
Am I missing something? What's the current way to go?
Obviously there are ways, because otherwise Messengers, Games and other Apps won't be able to work the way they do.
public class BackgroundTaskWorker extends Worker {
public BackgroundTaskWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#Override
public Result doWork() {
Log.i("WORKING","DOING SOME WORK");
Context con = getApplicationContext();
SharedPreferences preferences = con.getSharedPreferences(MainActivity.sharedPrefs, Context.MODE_PRIVATE);
SharedPreferences.Editor editPrefs = preferences.edit();
int day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
String s_day = preferences.getString("DAY","0");
int old_day = Integer.parseInt(s_day);
if(old_day == 0){
Log.i("WORKING","old_day default");
editPrefs.putString("DAY",Integer.toString(day));
editPrefs.commit();
return Result.success();
}
else if(day == old_day) {
Log.i("WORKING", "day=old_day default");
return Result.success();
}
else {
Log.i("WORKING","old_day change");
editPrefs.putString("DAY",Integer.toString(day));
editPrefs.commit();
Log.d("BISASAM","triggered");
DateFormat date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.GERMANY);
Date dat = new Date();
Log.d("TRIGGERDATE",date.format(dat));
editPrefs.putString("REC", "Receiver called "+date.format(dat));
NotificationCompat.Builder builder= new NotificationCompat.Builder(con,"ID");
builder.setContentTitle("ALARM FIRED");
builder.setContentText("WORKER");
builder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
builder.setSmallIcon(R.drawable.kreuz);
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
Log.d("BUILDCHECK","correct");
CharSequence name = "NotChannel";
String desc = "Test Channel for Planer";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel("NOT",name,importance);
channel.setDescription(desc);
NotificationManager notManager = con.getSystemService(NotificationManager.class);
notManager.createNotificationChannel(channel);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(con);
builder.setChannelId("NOT");
notificationManager.notify(1,builder.build());
}
//TODO Test Tageswechsel Wiederholende Tasks
String today = preferences.getString("0",null);
String tomorrow = preferences.getString("1",null);
String next_week = preferences.getString("7",null);
String next_month = preferences.getString("30",null);
if(today != null) {
String[] repetitive = today.split(" ");
for (int j = 1; j < repetitive.length; j += 2) {
Log.d("PIKACHU",repetitive[j-1]);
switch(repetitive[j]){
case "1":
if(tomorrow!=null)
tomorrow += ","+ repetitive[j-1]+" "+repetitive[j];
else
tomorrow=repetitive[j-1]+" "+repetitive[j];
break;
case "7":
if(next_week!=null)
next_week += ","+ repetitive[j-1]+" "+repetitive[j];
else
next_week=repetitive[j-1]+" "+repetitive[j];
break;
case "30":
if(next_month!=null)
next_month += ","+ repetitive[j-1]+" "+repetitive[j];
else
next_month=repetitive[j-1]+" "+repetitive[j];
break;
default:
}
}
}
Log.d("PUTTING",tomorrow);
Log.d("PUTTING",next_week);
Log.d("PUTTING",next_month);
editPrefs.putString("1",tomorrow);
editPrefs.putString("7",next_week);
editPrefs.putString("30",next_month);
editPrefs.commit();
ArrayList<String> month = new ArrayList<>();
for (int i = 0; i < Jobs.month_length; i++) {
month.add(preferences.getString(Integer.toString(i),""));
}
for (int i=1;i<Jobs.month_length;i++){
month.set(i-1,month.get(i));
}
month.set(30,"");
for(int i=0;i<Jobs.month_length;i++){
editPrefs.putString(Integer.toString(i),month.get(i));
}
Log.d("COMMITED",month.toString());
editPrefs.commit();
}
// Indicate success or failure with your return value:
return Result.success();
}
}
private void registerWorker(){
unregisterWorker();
PeriodicWorkRequest request= new PeriodicWorkRequest.Builder(BackgroundTaskWorker.class,
20, TimeUnit.MINUTES)
.addTag("AUFGABEN_PLANER_BACK")
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork("AUFGABEN_PLANER_BACK", ExistingPeriodicWorkPolicy.KEEP, request);
}
private void unregisterWorker(){
WorkManager.getInstance().cancelAllWorkByTag("AUFGABEN_PLANER_BACK");
}
registerWorker is called everytime MainActivity gets started (=> at the app start)
Use WorkManager for Scheduling task in background and foreground
Example for Periodic Request
PeriodicWorkRequest request= new PeriodicWorkRequest.Builder(WorkerClass.class,
24, TimeUnit.HOURS).setInitialDelay(THE_DELAY,TimeUnit.SECONDS).addTag("TAG").build()
WorkManager.getInstance().enqueueUniquePeriodicWork("TAG", ExistingPeriodicWorkPolicy.KEEP, request);
Create a worker class
public class WorkerClass extends Worker {
#Override
public Worker.WorkerResult doWork() {
// Do the work here
// Indicate success or failure with your return value:
return WorkerResult.SUCCESS;
// (Returning RETRY tells WorkManager to try this task again
// later; FAILURE says not to try again.)
}
}
Now call this class by
Example for One Time request
OneTimeWorkRequest request= new OneTimeWorkRequest.Builder(WorkerClass .class)
.setInitialDelay(delayedTime, TimeUnit.MILLISECONDS)
.addTag("TAG")
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork("TAG", ExistingPeriodicWorkPolicy.KEEP, request);
where delayedTime is calculated time to do task
add this in build.gradle
implementation 'android.arch.work:work-runtime:2.1.0-alpha02'
check the latest release doc
https://developer.android.com/jetpack/androidx/releases/work
also you can convert your time
Android / Java convert String date to long type
I am building a simple Android app to check if active internet connection is available on my phone. For checking this I am using a service which is running into background every 30 seconds and "pings" the Google's DNS server to check if there is a response.
This is my class used for checking internet status:
public class NetworkStatus {
private static final String GOOGLE_DNS_SERVER = "8.8.8.8";
private static final String CLOUDFLARE_DNS_SERVER = "1.1.1.1";
private static final String TAG = "OUTGOING-NET-STATUS";
private static final String RETRY_TAG = "DNS-CHECK";
boolean pingDnsServerSuccessful() {
boolean success = false;
int count = 0;
final int MAX_TRIES = 15;
while (!success && count++ < MAX_TRIES) {
Log.d(RETRY_TAG, "Retry value: " + count + " out of " + MAX_TRIES);
success = isDnsServerReachable(CLOUDFLARE_DNS_SERVER) || isDnsServerReachable(GOOGLE_DNS_SERVER);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (success) {
Log.d(TAG, "Outgoing Internet Traffic is Enabled");
} else {
Log.d(TAG, "Error reaching Outgoing Traffic");
}
return success;
}
private boolean isDnsServerReachable(String dnsServer) {
int connectionTimeout = 250;
try {
return InetAddress.getByName(dnsServer).isReachable(connectionTimeout);
} catch (Exception e) {
Log.d(TAG, "Exception: Error while pinging " + dnsServer + " DNS server: " + e);
}
return false;
}
}
and this is the code which triggers the background timer within the service:
public void startTimer() {
//set a new Timer
timer = new Timer();
networkStatus = new NetworkStatus();
notificationManager = new NotificationManager();
//initialize the TimerTask's job
initializeTimerTask();
//schedule the timer, to wake up every 30 seconds
timer.schedule(timerTask, 1000, 30000); //
}
/**
* it sets the timer to print the counter every x seconds
*/
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
Log.i("in timer", "in timer ++++ " + (counter++));
if (networkStatus.pingDnsServerSuccessful()) {
Log.i(PING_TAG, "Active Internet Connection");
if (!notificationManager.getLastSentNotificationType().equals(NotificationType.INTERNET_UP)) {
Log.i(NOTIFICATION_TAG, "Internet ON");
notificationManager.sendNotification(getApplicationContext(), NotificationType.INTERNET_UP);
}
} else {
Log.i(PING_TAG, "No Internet Connection");
if (!notificationManager.getLastSentNotificationType().equals(NotificationType.INTERNET_DOWN)) {
Log.i(NOTIFICATION_TAG, "Internet OFF");
notificationManager.sendNotification(getApplicationContext(), NotificationType.INTERNET_DOWN);
}
}
}
};
}
Everything works fine for a random amount of time (minutes/hours) when suddenly the DNS server can't be reached anymore when app is running in background and phone is locked. Activating the phone's screen is immediately resulting into a success while pinging the server.
Here are some logs reflecting the behaviour:
Logs
Does anybody have a clue why is this happening? I highly doubt that Google or Cloudflare DNS server becomes unresponsive...
Many Thanks!
This is Doze mode. To save power, background requests are limited to a small window every 15 minutes or so for requests. In addition, background processes can be killed at any time.
I'm not sure what you're actually trying to do, but there are 100% better ways to do it. For example, JobScheduler allows you to schedule a job to go off only if the internet is connected. No need to ping a server manually, and no need to do all the work to avoid Doze.
I have created a location tracking app, which writes to a local SQLite database every time the location is changed.
The app unfortunately crashes after about 7-8 hours while tracking, unfortunately this does not happen when I have connected the device to a debugger, so there is no log which I can attach.
Some more maybe useful information:
The app crashes before it is waken up from the background(can see that clearly in the tracked data), so I can exclude this bug from other apps
Tried to write into textfiles instead of the database without any success(Just ran about 3 hours before crashing)
Changing tracking interval(5s normal 1s fastest interval): Same result app crashes also after 7-8 hours
Here are some code snippets:
Location change event
#Override
public void onLocationChanged(Location location) {
if(location == null){
location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(location == null) {
return;
}
}
Log.d(TAG, location.toString());
double currentLatitude = location.getLatitude();
double currentLongitude = location.getLongitude();
ActivitylogRepo activityRepo = new ActivitylogRepo(this);
Activitylog activity = new Activitylog();
activity.activity = "Position";
activity.timestamp = getDateTime();
activity.value2 = String.valueOf(currentLatitude);
activity.value3 = String.valueOf(currentLongitude);
activityRepo.insert(activity);
}
Database insert command
public int insert(Activitylog activitylog) {
//Open connection to write data
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Activitylog.KEY_activity, activitylog.activity);
values.put(Activitylog.KEY_timestamp, activitylog.timestamp);
values.put(Activitylog.KEY_value1, activitylog.value1);
values.put(Activitylog.KEY_value2, activitylog.value2);
values.put(Activitylog.KEY_value3, activitylog.value3);
values.put(Activitylog.KEY_value4, activitylog.value4);
// Inserting Row
long activitylog_id = db.insert(Activitylog.TABLE, null, values);
db.close(); // Closing database connection
return (int) activitylog_id;
}
Initializing service
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(20 * 1000) // 20s in ms
.setFastestInterval(5 * 1000); // 5s in ms
I have something that will help you to catch your crash report even when you're not attached to the debugger - thus helping you to get to the root of the problem! I've posted this as an answer so I can format it nicely.
The class below will handle uncaught exceptions, packing them up into an email and placing a notification on your phone (you can adjust this to whatever you need)
public class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private Context mContext;
private java.lang.Thread.UncaughtExceptionHandler mDefaultUEH;
public UncaughtExceptionHandler(Context context, java.lang.Thread.UncaughtExceptionHandler defaultUEH) {
mContext = context;
mDefaultUEH = defaultUEH;
}
#Override
public void uncaughtException(Thread thread, Throwable ex) {
// Make error into something more readable
String timestamp = android.text.format.DateFormat.getLongDateFormat(mContext).format(
new Date(System.currentTimeMillis()));
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
ex.printStackTrace(printWriter);
String stacktrace = result.toString();
printWriter.close();
// Create email intent for error
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/html");
emailIntent.putExtra(Intent.EXTRA_EMAIL, "email address");
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Crash Report " + timestamp);
emailIntent.putExtra(Intent.EXTRA_TEXT, stacktrace);
// Make into pending intent for notifcation
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
Intent.createChooser(emailIntent, "Send report with.."),
Intent.FLAG_ACTIVITY_NEW_TASK);
// here create a notification for the user
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
builder.setContentTitle("Crash Caught");
builder.setContentText("Send to Developer");
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
builder.setSmallIcon(R.drawable.ic_notification);
// Finally display the notification!
NotificationManager mNotificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1337, builder.build());
// re-throw critical exception further to the os (important)
mDefaultUEH.uncaughtException(thread, ex);
}
}
Set this up in your Application class like this:
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
/*
* Set up uncaught exception handler
*/
java.lang.Thread.UncaughtExceptionHandler defaultUEH =
Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new
UncaughtExceptionHandler(this, defaultUEH));
}
}
I don't recommend including this code in your release version! At that point, you can use the Developer Console to get crash reports.
I am a New B to Android. I have been Able to get the Battery Status/Level with the Following Code:
private void BattStatus() {
BroadcastReceiver batteryLevelReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
context.unregisterReceiver(this);
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
int level = -1;
if (rawlevel >= 0 && scale > 0) {
level = (rawlevel * 100) / scale;
}
batteryLevel = level;
BattStatus.setText("Battery Level : " + batteryLevel + "%");
}
};
IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(batteryLevelReceiver, batteryLevelFilter);
}
I would Like to Store the Battery Level In A text file (Using a thread). Code :
public final Runnable DBThread = new Runnable() {
String AllInfo = batteryLevel+"%"+" , "+new SimpleDateFormat("HH:mm , dd.MM.yy ").format(new Date());
public void run() {
try {
Log.d("DBThread","Battery :"+batteryLevel);
Log.d("DBThread","Updating DB");
myDbHelper.CreateAndWriteFile(sdDir+"/", AllInfo );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 2000);
Log.d("DBThread","Updated DB");
Log.d("DBThread",AllInfo);
}
Unfortunately the Battery Status/Level returns 0% in the text file, when I test it using the Log function in the thread it returns the correct value.
Please could some one be so kind to tell me what I am doing wrong or what I am not doing, and maybe provide me with a code snippet as I am new to Development.And Sorry If My Post is incorrect First timer on Stack Overflow :)
Thank you very much!
This is not a Thread. This is a Runnable, which is a piece of code that is made to run in a Thread.
In your case, it runs in the handler thread, most likely the UI Thread.
You probably start your thread before receiving the battery status, hence writing the default value (0) to the file.
You don't need a thread for that. You can write to the file immediately after your receive the broadcast, in the onReceive method.
Edit
There are a few things that don't work in your code. You unregister the broadcast receiver, hence you don't receive the battery level after the first time.
You write the batteryLevel value without knowing if it has indeed been modified
You write every 2 seconds without knowing there has been a change.
I would suggest that you don't unregister the BR, so you receive all battery level change. Then, in the onReceive, you append to the file the date and new value.