bee*_*ear 5 java android connectivity android-networking android-wifi
我会直接了解我发现的一些事实/数据,如果你遇到/解决了类似的问题,请帮助我.
我发回的数据每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())有没有人有相同的解决方案?
希望我不会太晚,我有一个像你一样的问题.我的应用程序需要以一定的间隔(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
}
}
Run Code Online (Sandbox Code Playgroud)
注意该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;
}
}
Run Code Online (Sandbox Code Playgroud)
我也有一个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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后,但并非最不重要的是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);
Run Code Online (Sandbox Code Playgroud)
当我停止服务时,我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);
Run Code Online (Sandbox Code Playgroud)
此外,不要忘记向清单添加适当的权限和组件:
<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" />
Run Code Online (Sandbox Code Playgroud)
我想我已经涵盖了这一切,如果这有助于任何人解决他们的问题,我将很高兴.