问题
I have been stuck on it for days. I need to execute a function every minute. This function is making a POST call from the App to the Server and is transferring the location of the user per minute. The location coordinates are transferred for few hours, however, after few hours the transfer of location coordinates to the Server stops on its own. I am making use of WakefulBroadcastReceiver and IntentService to make sure that the CPU stays awake. I am also making use of Alarm to make sure that the function is executed every minute.
This is how my WakefulBroadcastReceiver looks like:
public class SimpleWakefulReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// This is the Intent to deliver to our service.
Intent service = new Intent(context, SimpleWakefulService.class);
// Start the service, keeping the device awake while it is launching.
Log.i("SimpleWakefulReceiver", "Starting service @ " +
SystemClock.elapsedRealtime());
startWakefulService(context, service);
}
}
This is what my IntentService looks like:
public class SimpleWakefulService extends IntentService {
public MainActivity obj;
public Alarm alarm;
public SimpleWakefulService() {
super("SimpleWakefulService");
}
@Override
protected void onHandleIntent(Intent intent) {
boolean flag = true;
while(flag){
Log.i("SimpleWakefulService", "Running service ");
alarm = new Alarm();
alarm.SetAlarm(SimpleWakefulService.this);
Log.i("Called alarm.SetAlarm","Called alarm.SetAlarm");
}
SimpleWakefulReceiver.completeWakefulIntent(intent);
// wl.release();
}
}
This is how my Alarm class looks like:
public class Alarm extends BroadcastReceiver
{
public MainActivity obj;
@Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager)
context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl =
pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
obj = new MMMainActivity();
obj.UpdateData();
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show();
wl.release();
}
public void SetAlarm(Context context)
{
Log.i("Inside SetAlarm","Inside SetAlarm");
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 1, pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
This is what the function(named as UpdataData()), that needs to be executed every minute looks like:
public void UpdateData() {
final boolean flag = true;
Log.i("Inside Update Data", "Inside Update Data");
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for(int i=0; i<1; i++){
try {
// Your code goes here
if (locationclient != null
&& locationclient.isConnected()) {
loc = locationclient.getLastLocation();
lat = loc.getLatitude();
lng = loc.getLongitude();
}
try { // Updating the latest location in the UI, just
// for convinience.
HttpClient httpClient = new DefaultHttpClient();
// Creating HTTP Post
HttpPost httpPost = new HttpPost(
"http://www.mywebsite.com/update");
List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>(
3);
// Building post parameters//
// key and value pair
Log.i("token", "token" + token);
Log.i("Latitude for III POST Call",
"Latitude for III POST Call" + lat);
Log.i("Longitude for III POST Call",
"Longitude for III POST Call" + lng);
nameValuePair.add(new BasicNameValuePair("token",
token));
nameValuePair.add(new BasicNameValuePair("lat",
Double.toString(lat)));
nameValuePair.add(new BasicNameValuePair("lng",
Double.toString(lng)));
Log.i("Made UpdateData Post Call",
"Made UpdateData Post Call");
// Url Encoding the POST parameters
try {
httpPost.setEntity(new UrlEncodedFormEntity(
nameValuePair));
} catch (UnsupportedEncodingException e) {
// writing error to Log
e.printStackTrace();
}
// Making HTTP Request
try {
HttpResponse response = httpClient
.execute(httpPost);
// writing response to log
Log.d("Http Response:", response.toString());
// Your code goes here
} catch (IOException e) {
// writing exception to log
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}// loop closed
}
});
thread.start();
}// UpdateData closed
Why is it that even after using all of these, the UpdateData() cannot be executed for an infinite time, every 60 seconds? Any help in this regard would be highly appreciated. Also note that the UpdateData() is executed every 60 seconds for few hours, but, after some time, its execution stops on its own and so the transfer of location coordinates, from the App to the Server.
EDIT: I have edited the SimpleWakefulService and added the required changes as suggested by one of the answer. Things worked well for few hours, however, post few hours, the service was killed automatically. I believe the services are not meant to be killed. Could anyone please explain this? SimpleWakefulService:
public class SimpleWakefulService extends IntentService implements
OnClickListener,ConnectionCallbacks, OnConnectionFailedListener,
LocationListener,GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
public static Location loc;
public static LocationClient locationclient;
public static double lat = 10, lng = 10;
public static String token;
public Alarm alarm;
public SimpleWakefulService() {
super("SimpleWakefulService");
}
@Override
protected void onHandleIntent(Intent intent) {
//Getting the value of token from another Class
token = ConfirmToken.uvalue;
Log.i("WakefulServiceutoken", "WakefulServicutoken" + token);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
final boolean flag = true;
while (flag) {
try {
// Your code goes here
if (locationclient != null
&& locationclient.isConnected()) {
loc = locationclient.getLastLocation();
lat = loc.getLatitude();
lng = loc.getLongitude();
}
try { // Updating the latest location in the UI, just
// for convinience.
HttpClient httpClient = new DefaultHttpClient();
// Creating HTTP Post
HttpPost httpPost = new HttpPost(
"http://www.mywebsite.com/update");
List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>(
3);
// Building post parameters//
// key and value pair
Log.i("token", "token" + token);
Log.i("Latitude for III POST Call",
"Latitude for III POST Call" + lat);
Log.i("Longitude for III POST Call",
"Longitude for III POST Call" + lng);
nameValuePair.add(new BasicNameValuePair("token",
token));
nameValuePair.add(new BasicNameValuePair("lat",
Double.toString(lat)));
nameValuePair.add(new BasicNameValuePair("lng",
Double.toString(lng)));
// Url Encoding the POST parameters
try {
httpPost.setEntity(new UrlEncodedFormEntity(
nameValuePair));
} catch (UnsupportedEncodingException e) {
// writing error to Log
e.printStackTrace();
}
// Making HTTP Request
try {
HttpResponse response = httpClient
.execute(httpPost);
// writing response to log
Log.d("Http Response:", response.toString());
// Your code goes here
} catch (IOException e) {
// writing exception to log
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(10000);
} catch (Exception e) {
}
}// While closed
//SimpleWakefulReceiver.completeWakefulIntent(intent);
//wl.release();
}
@Override
public void onDisconnected() {
// TODO Auto-generated method stub
}
@Override
public void onLocationChanged(Location arg0) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String arg0) {
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub
}
@Override
public void onConnectionFailed(ConnectionResult result) {
// TODO Auto-generated method stub
}
@Override
public void onConnected(Bundle arg0) {
// TODO Auto-generated method stub
}
@Override
public void onConnectionSuspended(int arg0) {
// TODO Auto-generated method stub
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
回答1:
First of all, your SimpleWakefulService does not look very wakefull, it should aqurie WakeLock but it doesnt. For example of such service look here:
https://github.com/commonsguy/cwac-wakeful/blob/master/wakeful/src/com/commonsware/cwac/wakeful/WakefulIntentService.java
Next thing, is update function. It is called in the context where PARTIAL_WAKE_LOCK is aquired, but the thread within it is executed asynchronously, that means also after wakelock is released. And that is whats causing problems.
Solution is to move your thread code from update function (thread is not needed) to WakefulIntentService as in above link.
来源:https://stackoverflow.com/questions/30334215/how-to-keep-the-cpu-of-android-phone-always-awake