前台服务有定时器问题
我正在开发一个应用程序,用于按给定的时间间隔检查与服务器的连接。 我使用带有通知的前台服务。问题是,只要手机处于唤醒状态(屏幕打开),一切都可以正常工作。从我按下电源按钮打开屏幕的那一刻起,服务就开始表现得很奇怪。 我制作了一个精简版的服务来向您展示。
ForegroundService.java:
package service.App;
import android.R.drawable;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.IBinder;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;
public class ForegroundService extends Service {
static final String ACTION_FOREGROUND = "com.example.android.apis.FOREGROUND";
static final String ACTION_BACKGROUND = "com.example.android.apis.BACKGROUND";
private static final Class<?>[] mStartForegroundSignature = new Class[] {int.class, Notification.class };
private static final Class<?>[] mStopForegroundSignature = new Class[] { boolean.class };
private Method mStartForeground;
private Method mStopForeground;
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
private Timer timer = new Timer();
long interv=10000;
int timeout=3000;
Intent notificationIntent;
PendingIntent contentIntent;
Notification notification;
CharSequence text;
SimpleDateFormat df;
void invokeMethod(Method method, Object[] args) {
try {
mStartForeground.invoke(this, mStartForegroundArgs);
} catch (InvocationTargetException e) {
Log.w("ApiDemos", "Unable to invoke method", e);
} catch (IllegalAccessException e) {
Log.w("ApiDemos", "Unable to invoke method", e);
}
}
void startForegroundCompat(int id, Notification notification) {
Scan();
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
invokeMethod(mStartForeground, mStartForegroundArgs);
return;
}
}
void stopForegroundCompat(int id) {
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
try {
mStopForeground.invoke(this, mStopForegroundArgs);
} catch (InvocationTargetException e) {
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
} catch (IllegalAccessException e) {
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
}
return;
}
}
@Override
public void onCreate() {
notificationIntent = new Intent(this, ForegroundService.class);
contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,0);
try {
mStartForeground = getClass().getMethod("startForeground",mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground",mStopForegroundSignature);
} catch (NoSuchMethodException e) {
return;
}
}
@Override
public void onDestroy() {
stopForegroundCompat(R.string.foreground_service_started);
if (timer != null) {
timer.cancel();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleCommand(intent);
return START_STICKY;
}
void handleCommand(Intent intent) {
if (ACTION_FOREGROUND.equals(intent.getAction())) {
text = getText(R.string.foreground_service_started);
notification = new Notification(R.drawable.icon, text, System
.currentTimeMillis());
contentIntent = PendingIntent.getActivity(this, 0, new Intent(this,
Start.class), 0);
notification.setLatestEventInfo(this,
getText(R.string.local_service_label), text, contentIntent);
startForegroundCompat(R.string.foreground_service_started,
notification);
} else if (ACTION_BACKGROUND.equals(intent.getAction())) {
stopForegroundCompat(R.string.foreground_service_started);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void Scan() {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Socket s = null;
int p = 81;
long time;
String url="www.google.com";
SimpleDateFormat df;
InetAddress ipaddress;
try {
ipaddress = InetAddress.getByName(url);
try {
s = new Socket();
s.connect(new InetSocketAddress(url, p), timeout);
time = System.currentTimeMillis();
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log.i("Server Monitor",
"A server is running on port " + p + " "
+ "@ IP address "
+ ipaddress.getHostAddress()
+ ". Date/Time: "
+ df.format(new Date(time)));
s.close();
} catch (IOException e) {
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
long when = System.currentTimeMillis();
Notification notification = new Notification(drawable.ic_dialog_alert,"Server Monitor", when);
Context context = getApplicationContext();
CharSequence contentTitle = "Server Monitor";
CharSequence contentText = "No server on port." + p;
notification.setLatestEventInfo(context,contentTitle, contentText, contentIntent);
notification.defaults |= Notification.DEFAULT_SOUND;
final int HELLO_ID = 1;
mNotificationManager.notify(HELLO_ID, notification);
}
} catch (UnknownHostException e) {
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
long when = System.currentTimeMillis();
Notification notification = new Notification(drawable.ic_dialog_alert,"Server Monitor", when);
Context context = getApplicationContext();
CharSequence contentTitle = "Server Monitor";
CharSequence contentText = "Could not find host.";
notification.setLatestEventInfo(context,contentTitle, contentText, contentIntent);
notification.defaults |= Notification.DEFAULT_SOUND;
final int HELLO_ID = 1;
mNotificationManager.notify(HELLO_ID, notification);
}
if (s != null) {
try {
s.close();
} catch (IOException ioEx) {
Log.i("Server Monitor", "Unable to close socket "+ s);
}
}
}
}, 0, interv);
}
}
因此该服务每 10 秒检查端口 81 处与 www.google.com 的连接。我将其放在端口 81 上以使其失败并测试通知。当失败时,它会显示一条通知。从我打开屏幕的那一刻起,一分钟或多分钟内都没有任何通知,然后它会立即向我提供所有通知。以下是启动服务的活动。
Start.java:
package service.App;
import service.App.R;
import service.App.ForegroundService;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class Start extends Activity{
private Button ButtonStartService;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ButtonStartService = (Button)findViewById(R.id.ButtonStartService);
ButtonStartService.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(ForegroundService.ACTION_FOREGROUND);
intent.setClass(Start.this, ForegroundService.class);
startService(intent);
}
});
}
}
所以我在这里做错了什么?这是我的应用程序中非常重要的一部分,因此这个错误确实必须修复。有人可以帮我吗?
I am developing an application that checks connectivity to a server at given interval.
I use a foreground service with notifications for this. The problem is that everything works fine as long as the phone is awake (screen turned on). From the moment I turn of the screen by pressing the power button the service starts to behave strange.
I made a stripped down version of my service to show you.
ForegroundService.java:
package service.App;
import android.R.drawable;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.IBinder;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;
public class ForegroundService extends Service {
static final String ACTION_FOREGROUND = "com.example.android.apis.FOREGROUND";
static final String ACTION_BACKGROUND = "com.example.android.apis.BACKGROUND";
private static final Class<?>[] mStartForegroundSignature = new Class[] {int.class, Notification.class };
private static final Class<?>[] mStopForegroundSignature = new Class[] { boolean.class };
private Method mStartForeground;
private Method mStopForeground;
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
private Timer timer = new Timer();
long interv=10000;
int timeout=3000;
Intent notificationIntent;
PendingIntent contentIntent;
Notification notification;
CharSequence text;
SimpleDateFormat df;
void invokeMethod(Method method, Object[] args) {
try {
mStartForeground.invoke(this, mStartForegroundArgs);
} catch (InvocationTargetException e) {
Log.w("ApiDemos", "Unable to invoke method", e);
} catch (IllegalAccessException e) {
Log.w("ApiDemos", "Unable to invoke method", e);
}
}
void startForegroundCompat(int id, Notification notification) {
Scan();
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
invokeMethod(mStartForeground, mStartForegroundArgs);
return;
}
}
void stopForegroundCompat(int id) {
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
try {
mStopForeground.invoke(this, mStopForegroundArgs);
} catch (InvocationTargetException e) {
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
} catch (IllegalAccessException e) {
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
}
return;
}
}
@Override
public void onCreate() {
notificationIntent = new Intent(this, ForegroundService.class);
contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,0);
try {
mStartForeground = getClass().getMethod("startForeground",mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground",mStopForegroundSignature);
} catch (NoSuchMethodException e) {
return;
}
}
@Override
public void onDestroy() {
stopForegroundCompat(R.string.foreground_service_started);
if (timer != null) {
timer.cancel();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleCommand(intent);
return START_STICKY;
}
void handleCommand(Intent intent) {
if (ACTION_FOREGROUND.equals(intent.getAction())) {
text = getText(R.string.foreground_service_started);
notification = new Notification(R.drawable.icon, text, System
.currentTimeMillis());
contentIntent = PendingIntent.getActivity(this, 0, new Intent(this,
Start.class), 0);
notification.setLatestEventInfo(this,
getText(R.string.local_service_label), text, contentIntent);
startForegroundCompat(R.string.foreground_service_started,
notification);
} else if (ACTION_BACKGROUND.equals(intent.getAction())) {
stopForegroundCompat(R.string.foreground_service_started);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void Scan() {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Socket s = null;
int p = 81;
long time;
String url="www.google.com";
SimpleDateFormat df;
InetAddress ipaddress;
try {
ipaddress = InetAddress.getByName(url);
try {
s = new Socket();
s.connect(new InetSocketAddress(url, p), timeout);
time = System.currentTimeMillis();
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log.i("Server Monitor",
"A server is running on port " + p + " "
+ "@ IP address "
+ ipaddress.getHostAddress()
+ ". Date/Time: "
+ df.format(new Date(time)));
s.close();
} catch (IOException e) {
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
long when = System.currentTimeMillis();
Notification notification = new Notification(drawable.ic_dialog_alert,"Server Monitor", when);
Context context = getApplicationContext();
CharSequence contentTitle = "Server Monitor";
CharSequence contentText = "No server on port." + p;
notification.setLatestEventInfo(context,contentTitle, contentText, contentIntent);
notification.defaults |= Notification.DEFAULT_SOUND;
final int HELLO_ID = 1;
mNotificationManager.notify(HELLO_ID, notification);
}
} catch (UnknownHostException e) {
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
long when = System.currentTimeMillis();
Notification notification = new Notification(drawable.ic_dialog_alert,"Server Monitor", when);
Context context = getApplicationContext();
CharSequence contentTitle = "Server Monitor";
CharSequence contentText = "Could not find host.";
notification.setLatestEventInfo(context,contentTitle, contentText, contentIntent);
notification.defaults |= Notification.DEFAULT_SOUND;
final int HELLO_ID = 1;
mNotificationManager.notify(HELLO_ID, notification);
}
if (s != null) {
try {
s.close();
} catch (IOException ioEx) {
Log.i("Server Monitor", "Unable to close socket "+ s);
}
}
}
}, 0, interv);
}
}
So this service checks connectivity with www.google.com at port 81 every 10 seconds. I put this on port 81 to make it fail and test the notifications. When it fails it shows a notification. From the moment I turn of the screen there are no notifications for one or more minutes, and then it gives me all the notifications at once. Below is the activity that starts the service.
Start.java:
package service.App;
import service.App.R;
import service.App.ForegroundService;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class Start extends Activity{
private Button ButtonStartService;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ButtonStartService = (Button)findViewById(R.id.ButtonStartService);
ButtonStartService.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(ForegroundService.ACTION_FOREGROUND);
intent.setClass(Start.this, ForegroundService.class);
startService(intent);
}
});
}
}
So i am doing anything wrong here? This is a really important piece of my application so this bug really has to be fixed. Can someone help me please?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当处于睡眠模式(CPU 断电)时,Android 将不会执行应用程序代码。
为了避免这种情况,您可以使用 AlarmManager 类来安排手机启动一个意图,使其从睡眠状态减弱,并使用自定义广播接收器捕获它:
http://developer.android.com/reference/android/app/AlarmManager.html
然后,您应该使用 PowerManager 类获取 WakeLock,以确保至少保持 CPU 运行,以便执行您的应用程序代码,并在不再需要时释放它(这将允许手机返回睡眠模式以避免无用的电池使用):
http://developer.android.com/reference/android/os/PowerManager.html
当然,您也可以在服务启动后立即获取 WakeLock,并保留它直到服务关闭,但这种方法对电池不太友好。
When in sleep mode (CPU powered off), Android will not execute application code.
To avoid it, you could use the AlarmManager class to schedule an intent to be launched by the phone weakening it from sleep, catching it using a custom broadcast receiver:
http://developer.android.com/reference/android/app/AlarmManager.html
Then, you should acquire a WakeLock using the PowerManager class, to ensure that at least the CPU will be maintained on in order to allows your application code to be performed, and releasing it when not needed anymore (this will allows the phone to returns in sleep mode to avoid a useless battery usage):
http://developer.android.com/reference/android/os/PowerManager.html
Of course, you could also simply obtain a WakeLock as soon as your service is started keeping it until your service is closed, but this approach isn't very battery friendly.