我会直接了解我发现的一些事实/数据,如果你遇到/解决了类似的问题,请帮助我.
我发回的数据每5分钟到一个服务器,除非用户手动切换它砍掉的帮助下wakeful broadcast receiver
通过intent service
.另外我在做之前得到了wifi锁(我已经尝试过这个没有锁;也没有工作)
现在,从普通数据网络发回数据设备(2G/3G/4G)能正常工作,但对那些连接到WiFi网络在某种程度上得到我getActiveNetworkInfo()
的null
(甚至直接打到该网页的网址给出了hostname not found error
)这确实发生在HTC一(安装v.4.4.2)其他设备工作正常.
我们都知道,即使网络没有/可用,以前的官方连接管理器在返回过多的真/假条件方面也存在问题.我非常怀疑他们是否再次出现或只是一些定制的OEM jing-bang
警报被触发>> wakeful broadcast receiver >> get wifi locks >> sleep the thread for 3 secs inside the
获取锁后触发onReceive`以等待wifi恢复连接>>之后我的服务工作.
我正在权衡强制使用移动数据连接而不是wifi的可能性.(通过使用startUsingNetworkFeature()
)有没有人有相同的解决方案?
kiko283.. 5
希望我不会太晚,我有一个像你一样的问题.我的应用程序需要以一定的间隔(30米/ 1小时/ 2小时/ 4小时)将数据(从内部存储文件)发送到服务器.为了getActiveNetworkInfo()
给出正确的结果,你需要唤醒wifi(因为手机睡眠5-15分钟后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()); } } }
最后,但并非最不重要的是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);
此外,不要忘记向清单添加适当的权限和组件:
我想我已经涵盖了这一切,如果这有助于任何人解决他们的问题,我将很高兴.