无法通过无线网络从后台服务来访问互联网 [英] Unable to access Internet via WiFi from a Background service

查看:274
本文介绍了无法通过无线网络从后台服务来访问互联网的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我会直接到一些事实/数字我发现请帮助我,如果你面对/解决类似的问题。

I'll get straight onto some facts/figures I discovered pls help me if you've faced/solved a similar problem.

我发回的数据每5分钟到一个服务器,除非用户手动切换它关闭了清醒广播接收器通过意图帮助服务。另外,我得到的wifi锁在做之前,(我试过这个已经没有锁;不工作要么)

I send back data every 5 minutes to a server unless the user manually toggles it Off with the help of a wakeful broadcast receiver through a intent service. Plus I get wifi locks before doing (I've tried this already without locks; doesnt work either)

现在的设备发回的常规数据的网络数据(2G / 3G / 4G)能正常工作,但对那些连接到WiFi网络莫名其妙地让我一个 getActiveNetworkInfo()(甚至直接打到网站的URL给出了一个主机名未找到错误)这确实发生在的HTC One(与v.4.4.2安装)其他设备做做工精细。

Now on devices sending back data from regular data networks (2G/3G/4G) this works fine but on those connected to a wifi network somehow gets me a getActiveNetworkInfo() as null (Even directly hitting the web URL gives a hostname not found error) this surely happens on HTC One (with v.4.4.2 installed) others devices do work fine.

  • 我们都知道了previous官方的连接管理器已经在返回即使网络不/提供太多的真/假条件有问题。我很怀疑他们是否已经出现反复,或者只是一些自定义的OEM京爆炸

  • we all know about the previous official connectivity manager have had issues in returning too much true / false condition even if network was not/available. I highly doubt if they've cropped up again or is just some custom OEM jing-bang

报警被炒鱿鱼>>激发了清醒广播接收器GT;>得到的wifi锁>>睡眠线程内3秒的 onReceive`获得锁,以等待的WiFi恢复连接>>后做了以后我的服务工作。

the alarm gets fired >> fires up the wakeful broadcast receiver >> get wifi locks >> sleep the thread for 3 secs inside theonReceive` after getting locks in order to wait for wifi to resume connectivity >> do my service work afterwards.

我体重强制使用移动数据连接,而不是无线的可能性。 (通过使用 startUsingNetworkFeature())有没有人有相同的解决方案?

am weighing the possibility of forcing use of mobile data connection instead of wifi. (by using startUsingNetworkFeature()) Does anyone have a solution for the same?

推荐答案

希望我不是太晚了,我有一个问题,就像你的。我的应用程序发送数据(从内部存储文件)服务器在一定的时间间隔(30米/ 1H / 2H / 4H)需要。对于 getActiveNetworkInfo()给予正确的结果,你需要唤醒的WiFi(因为此前的手机wifi的睡眠5-15分钟关闭)。这给了我很大的麻烦,但这里的如何我的解决方案如下:

Hope I'm not too late, I had a problem just like yours. My app needed to send data (from internal storage file) to server at certain intervals (30m/1h/2h/4h). For getActiveNetworkInfo() to give proper result, you need to wake the wifi (because after 5-15 min of phone sleep wifi turns off). That gave me a lot of trouble, but here's how my solution works:

首先,我有一个 WakefulBroadcastReceiver 被调用,当我需要唤醒电话:

First, I have a WakefulBroadcastReceiver that gets called when I need to wake the phone:

/** 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
    }
}

注意公共静态无效setAlarm(背景下,INT,日历)功能,我使用该功能来设置报警(见主要应用)。

Note the public static void setAlarm(Context, int, Calendar) function, I use that function to set the alarms (see Main application).

接下来,服务本身并不是一个 IntentService ,只是服务

Next, the service itself isn't an IntentService, just 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;
    }
}

我也有一个启动 的BroadcastReceiver ,因此,如果闹钟设置,然后手机重新启动,就可以运行服务再次:

I also have a BOOT BroadcastReceiver, so if alarm is set and then phone is rebooted it will run service again:

/** 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());
        }
    }
}

最后,但并非最不重要的主活动,我通过启动接收器启动该服务:

Last, but not least in the Main Activity, I start the service by starting receivers:

// 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);

当我停止服务,我停止启动接收器也:

// 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);

此外,不要忘了添加适当的权限和组件来体现:

Additionally, don't forget to add proper permissions and components to manifest:

<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" />

我想我介绍这一切,我会很高兴,如果这有助于任何人解决他们的问题。

I think I covered it all, I'll be glad if this helps anyone solve their problems.

这篇关于无法通过无线网络从后台服务来访问互联网的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆