我会直接介绍一些我发现的事实/数据,如果您遇到/解决了类似的问题,请帮我。
我每5分钟将数据发送回服务器,除非用户借助wakeful broadcast receiver
通过intent service
手动将其关闭。另外,我在执行操作之前先获得了wifi锁(我已经尝试过不带锁的功能;也不起作用)
现在,在从常规数据网络(2G/3G/4G)发送回数据的设备上,这可以正常工作,但是在连接到wifi网络的设备上,我莫名其妙地将getActiveNetworkInfo()
称为null
(即使直接点击网络URL也会得到hostname not found error
),这肯定会在以下情况下发生HTC One(安装了v.4.4.2)其他设备也可以正常工作。
wakeful broadcast receiver >> get wifi locks >> sleep the thread for 3 secs inside the
onReceive`,以等待wifi恢复连接>>然后完成我的服务。 startUsingNetworkFeature()
)是否有人对此有解决方案? 最佳答案
希望我还不晚,像你一样,我遇到了一个问题。我的应用程序需要以一定的时间间隔(30m/1h/2h/4h)将数据(从内部存储文件)发送到服务器。为了使getActiveNetworkInfo()
得到正确的结果,您需要唤醒wifi(因为在5-15分钟的电话 sleep 后wifi会关闭)。这给我带来了很多麻烦,但是这是我的解决方案的工作原理:
首先,我有一个WakefulBroadcastReceiver
,当我需要唤醒手机时会被调用:
/** Receiver for keeping the device awake */
public class WakeUpReceiver extends WakefulBroadcastReceiver {
// Constant to distinguish request
public static final int WAKE_TYPE_UPLOAD = 2;
// AlarmManager to provide access to the system alarm services.
private static AlarmManager alarm;
// Pending intent that is triggered when the alarm fires.
private static PendingIntent pIntent;
/** BroadcastReceiver onReceive() method */
@Override
public void onReceive(Context context, Intent intent) {
// Start appropriate service type
int wakeType = intent.getExtras().getInt("wakeType");
switch (wakeType) {
case WAKE_TYPE_UPLOAD:
Intent newUpload = new Intent(context, UploadService.class);
startWakefulService(context, newUpload);
break;
default:
break;
}
}
/** Sets alarms */
@SuppressLint("NewApi")
public static void setAlarm(Context context, int wakeType, Calendar startTime) {
// Set alarm to start at given time
alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, WakeUpReceiver.class);
intent.putExtra("wakeType", wakeType);
pIntent = PendingIntent.getBroadcast(context, wakeType, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// For android 4.4+ the method is different
if (android.os.Build.VERSION.SDK_INT >=
android.os.Build.VERSION_CODES.KITKAT) {
alarm.setExact(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis() + 5000, pIntent);
} else {
alarm.set(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis() + 5000, pIntent);
}
// The + 5000 is for adding symbolic 5 seconds to alarm start
}
}
请注意
public static void setAlarm(Context, int, Calendar)
函数,我使用该函数设置警报(请参阅主应用程序)。接下来,服务本身不是
IntentService
,而是Service
:/** Service for uploading data to server */
public class UploadService extends Service {
private static final String serverURI = "http://your.server.com/file_on_server.php";
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
WifiLock wfl;
private Intent currentIntent;
private SharedPreferences sharedPrefs;
private int updateInterval;
private boolean continueService;
/** Service onCreate() method */
@Override
public void onCreate() {
super.onCreate();
// Initialize wifi lock
wfl = null;
// Initialize current Intent
currentIntent = null;
// Create separate HandlerThread
HandlerThread thread = new HandlerThread("SystemService",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
// Get shared variables values if set
sharedPrefs = getSharedPreferences("serviceVars", MODE_PRIVATE);
updateInterval = sharedPrefs.getInt("sendInterval", 60); // in your case 5
continueService = sharedPrefs.getBoolean("bgServiceState", false);
}
/** Service onStartCommand() method */
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// If continuing, set new alarm
if (continueService) {
Calendar nextStart = Calendar.getInstance();
nextStart.set(Calendar.SECOND, 0);
// Set alarm to fire after the interval time
nextStart.add(Calendar.MINUTE, updateInterval);
WakeUpReceiver.setAlarm(this, WakeUpReceiver.WAKE_TYPE_UPLOAD,
nextStart);
}
// Get current Intent and save it
currentIntent = intent;
// Acquire a wifi lock to ensure the upload process works
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wfl = wm.createWifiLock(WifiManager.WIFI_MODE_FULL, "WifiLock");
if (!wfl.isHeld()) {
wfl.acquire();
}
// For each start request, send a message to start a job and give
// start ID so we know which request we're stopping when we finish
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If service gets killed, it will restart
return START_STICKY;
}
/** Handler that receives messages from the thread */
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
/** Executes all service operations */
@Override
public void handleMessage(Message msg) {
// First wait for 5 seconds
synchronized (this) {
try {
wait(5 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
// Start checking if internet is enabled
boolean hasInternet = false;
long endTime = System.currentTimeMillis() + 55 * 1000;
// Check every second (max 55) if connected
while (System.currentTimeMillis() < endTime) {
if (hasInternet(UploadService.this)) {
hasInternet = true;
break;
}
synchronized (this) {
try {
wait(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Connected to internet or 60 (5 + 55) seconds passed
if (hasInternet) {
// Connect to server
connectToServer(serverURI, fileName);
} else {
// Can't connect, send message or something
}
// Stop service
stopSelf(msg.arg1);
}
}
/** Checks if phone is connected to Internet */
private boolean hasInternet(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = null;
if (cm != null) {
ni = cm.getActiveNetworkInfo();
}
return ni != null && ni.getState() == NetworkInfo.State.CONNECTED;
}
/** Service onDestroy() method */
@Override
public void onDestroy() {
// Release wifi lock
if (wfl != null) {
if (wfl.isHeld()) {
wfl.release();
}
}
// Release wake lock provided by BroadcastReceiver.
WakeUpReceiver.completeWakefulIntent(currentIntent);
super.onDestroy();
}
/** Performs server communication */
private void connectToServer(String serverUri, String dataFileName) {
// this function does my network stuff
}
/** Service onBind() method - Not used */
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
我也有一个
BOOT
BroadcastReceiver
,所以如果设置了警报然后重新启动了电话,它将再次运行服务:/** Receiver for (re)starting alarms on device reboot operations */
public class BootReceiver extends BroadcastReceiver {
WakeUpReceiver alarm = new WakeUpReceiver();
/** BroadcastReceiver onReceive() method */
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
WakeUpReceiver.setAlarm(context, WakeUpReceiver.WAKE_TYPE_UPLOAD,
Calendar.getInstance());
}
}
}
最后,但并非最不重要的一点是,在Main
Activity
中,我通过启动接收器来启动服务:// Start upload service now
Calendar timeNow = Calendar.getInstance();
WakeUpReceiver.setAlarm(this, WakeUpReceiver.WAKE_TYPE_UPLOAD, timeNow);
// Enable BootReceiver to (re)start alarm on device restart
getPackageManager().setComponentEnabledSetting(
new ComponentName(this, BootReceiver.class),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
当我停止服务时,我也停止了
BOOT
接收器:// Disable BootReceiver to (re)start alarm on device restart
getPackageManager().setComponentEnabledSetting(
new ComponentName(this, BootReceiver.class),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
此外,请不要忘记添加适当的权限和组件来体现:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<receiver
android:name=".BootReceiver"
android:enabled="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".WakeUpReceiver" />
<service
android:name=".UploadService"
android:enabled="true"
android:label="ServerUpload"
android:launchMode="singleInstance" />
我想我涵盖了所有内容,如果这可以帮助任何人解决他们的问题,我将感到很高兴。