无法从后台服务通过WiFi访问Internet

 tha1es 发布于 2023-01-03 11:06

我会直接了解我发现的一些事实/数据,如果你遇到/解决了类似的问题,请帮助我.

我发回的数据每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);

此外,不要忘记向清单添加适当的权限和组件:









    
        
    




我想我已经涵盖了这一切,如果这有助于任何人解决他们的问题,我将很高兴.

撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有