Android代码连接Wifi时被系统切换到其他Wifi的问题

首先说下Android代码连接Wifi的几个步骤:(以下涉及到具体API函数自查哈,写的时候凭借印象大致写了下)

转载请注明出处:

胖虎http://blog.csdn.net/ljphhj

1.首先要开启Wifi连接开关,mWifiManager.setWifiEnabled(true)

2.通过获取List<ScanResult>来获取到Wifi连接列表。(mWifiManager.getScanResults)

3.获取List<WifiConfiguration>列表。(mWifiManager.getConfiguredNetworks)

4. (1)创建配置要连接的WifiConfiguration(包括加密方式,SSID, 密码, [优先级]<-这个是这篇博文要说的重点)【如果选了这种方式,才进行第5步】  or (2)你连接第3步获取的Wifi配置列表中的一个NetworkId.(直接跳到第6步)

5.mConnectNetworkId = mWifiManager.addNetwork(WifiConfiguration),添加这个配置到Wifi Config (其实那个文件路径: /data/misc/wifi/wpa_supplicant.conf [ps: 这个文件是网上一堆"查看Wifi密码神器"的根基,包括万能Wifi钥匙噢!])

6.mWifiManager.enableNetwork(netId, true);

7.然后这边你需要等待Wifi连接上(两种方式,一种用广播,一种就是轮询咯,自己选择)

进入正题:

存在的问题(我也是请教别人得知的,有些地方可能不一定准确,如果有大神看到此博文,可以进行补充或者指正,谢谢):

Android 4.0之后加入了Roaming的机制,Android 5.0后又加入了另一个机制:auto join的机制, 两个机制大致差不多,就是当有一个SSID的信号强度,加密方式,或者其他因素计算出来的一个值(就是配置文件中的优先级的概念)比你要连接的Wifi的优先级数值要高的时候,会尝试去连接优先级较高的那个Wifi。

了解了这个存在问题,看看我们现在连接一个Wifi会遇到的问题(Android Version >= 4.0)

个人比较喜欢用图来解释,写博文随便画个图,方便大家理解。

从图中,想必可以知道这个问题出现的原因其实主要是:优先级列表,这个东东在我们Wifi断开跟某个SSID连接的时候,系统读取了一个优先级连接,判断出一个要连接的SSID,而我们只想连接我们的SSID,这样此时相当于有两个线程同时在进行,一但我们的SSID先连接上,System的连接晚我们一步连接上,就会导致我们刚连接上的SSID,马上就断开了。

有网友会自作聪明将要连接的SSID 它的WifiConfiguration的优先级配置很高(最高:100000),保证让它成为配置文件优先级最高的一个。认为这样的话,该SSID就会被系统认可,连接上我们先连接的SSID,但其实这个地方,你不能保证你写入优先级的时候在系统把配置文件中的优先级列表取出来之前。)

最后我个人的解决方案是:用跟系统设置模块相同的连接wifi的方式(即调用Connect来连接Wifi, 有时间可以去看下这块的代码,WifiSettings.java中的submit方法里面是连接逻辑,connect方法也在那里,我个人觉得应该是个队列类似的,这样的话你连接的操作和系统连接的操作应该是有先后关系的,而且Connect方法会更新一下优先级【最后连接上的Wifi优先级比较高】,所以我们要连接的SSID便获取到了最高的优先级)

解决方案:反射出系统设置连接的API(@hide)

/**
     * 通过反射出不同版本的connect方法来连接Wifi
     *
     * @author jiangping.li
     * @param netId
     * @return
     * @since MT 1.0
     *
     */
    private Method connectWifiByReflectMethod(int netId) {
        Method connectMethod = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            Logger.i(TAG, "connectWifiByReflectMethod road 1");
            // 反射方法: connect(int, listener) , 4.2 <= phone‘s android version
            for (Method methodSub : mWifiManager.getClass()
                    .getDeclaredMethods()) {
                if ("connect".equalsIgnoreCase(methodSub.getName())) {
                    Class<?>[] types = methodSub.getParameterTypes();
                    if (types != null && types.length > 0) {
                        if ("int".equalsIgnoreCase(types[0].getName())) {
                            connectMethod = methodSub;
                        }
                    }
                }
            }
            if (connectMethod != null) {
                try {
                    connectMethod.invoke(mWifiManager, netId, null);
                } catch (Exception e) {
                    e.printStackTrace();
                    Logger.i(TAG, "connectWifiByReflectMethod Android "
                            + Build.VERSION.SDK_INT + " error!");
                    return null;
                }
            }
        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) {
            // 反射方法: connect(Channel c, int networkId, ActionListener listener)
            // 暂时不处理4.1的情况 , 4.1 == phone‘s android version
            Logger.i(TAG, "connectWifiByReflectMethod road 2");
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH
                && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            Logger.i(TAG, "connectWifiByReflectMethod road 3");
            // 反射方法:connectNetwork(int networkId) ,
            // 4.0 <= phone‘s android version < 4.1
            for (Method methodSub : mWifiManager.getClass()
                    .getDeclaredMethods()) {
                if ("connectNetwork".equalsIgnoreCase(methodSub.getName())) {
                    Class<?>[] types = methodSub.getParameterTypes();
                    if (types != null && types.length > 0) {
                        if ("int".equalsIgnoreCase(types[0].getName())) {
                            connectMethod = methodSub;
                        }
                    }
                }
            }
            if (connectMethod != null) {
                try {
                    connectMethod.invoke(mWifiManager, netId);
                } catch (Exception e) {
                    e.printStackTrace();
                    Logger.i(TAG, "connectWifiByReflectMethod Android "
                            + Build.VERSION.SDK_INT + " error!");
                    return null;
                }
            }
        } else {
            // < android 4.0
            return null;
        }
        return connectMethod;
    }

Method connectMethod = connectWifiByReflectMethod(netId);
        if (connectMethod == null) {
            Logger.i(TAG,
                    "connect wifi by enableNetwork method, Add by jiangping.li");
            // 通用API
            mWifiManager.enableNetwork(netId, true);
        }

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-20 17:18:30

Android代码连接Wifi时被系统切换到其他Wifi的问题的相关文章

java运行代码连接mysql时提示:找不到类错误

使用IntelliJ IDEA Community Edition进行代码编写.. 使用一下代码连接mysql时出现了:java.lang.ClassNotFoundException: com.mysql.jdbc.Driver错误 然后就很好奇,import都能导入数据. 后来用idea工具打开以前的练习,发现架包也存在. 但是新建的练习就没有把架包弄进来.然后出现了这类错误.. 原因是:使用idea工具开发时,如果之前练习有添加相应的数据,那么在external libraries中是能显

Android中连接蓝牙设备时遇到createRfcommSocketToServiceRecord的UUID问题和BluetoothSocket的connect失败

[问题] 折腾: [记录]编写Android中的蓝牙模块驱动和底层HART设备 期间,参考: Bluetooth | Android Developers – ManagingAConnection 参考“Connecting as a client”中的: tmp = device.createRfcommSocketToServiceRecord(MY_UUID); 遇到UUID不懂的问题. 然后随便去 http://www.guidgenerator.com/online-guid-gen

怎样在Win7系统建立并开启Wifi热点

http://jingyan.baidu.com/article/48a42057a03cf7a9242504d0.html还在担心手机卡流量太少了吗?不妨试试在Win7系统下建立并开启WiFi热点,有了WiFi,你就可以畅玩支持WiFi的移动设备了. 工具/原料 笔记本(Win7系统) WiFi设备 步骤/方法 1 首先,确定你的笔记本已经开启了无线. 点击电脑左下角的开始,在搜索程序和文件栏输入cmd. 2 在上图中找到Windows命令处理程序cmd.exe,右击选择以管理员身份运行. 3

Android设备连接Unity Profiler性能分析器

Unity提供两种方式让Developer的Android设备连接Profiler进行性能分析: 1.通过wifi,Android设备和计算机处于同一个Wlan中. 2.通过USB ADB 一般情况我们的计算机都是网线,所以我们采用ADB的方式.相比与wifi,ADB也更及时的反应设备性能. 官方的英文文档如下: http://docs.unity3d.com/Manual/Profiler.html For ADB profiling, follow these steps: Attach y

Android连接wifi,调用系统API【转】

本文转载自:http://blog.csdn.net/aaa1050070637/article/details/54136472 直接上代码,简单粗暴,一看就懂 [java] view plain copy import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.ScanResult; impor

Android自动连接指定的wifi,免密码或指定密码

一.运行时的状态 遇到一个这样的要求:“不进行扫描操作,怎么对指定的免密码WIFI进行连接(之前没有连接过)”,于是动手写了一个Demo,如图所示未连接成功时的状态,第一个编辑框让用户输入SSID,第二个编辑框输入密码,密码可以根据实例情况输入,也可以不输入密码,因为有些Wifi免密码.这里的免密码不是指可以破解wifi密码.注意图片中手机顶部的wifi图标,是没有的,说明此时并没有打开手机的wifi.在手机上运行状态如下所示: 输入SSID,点击连接后的状态,当手机的wifi没有打开时,程序将

如何处理android程序变为后台程序,系统回收资源,再次打开时,程序因为null指针等崩溃

home键等原因,程序会变为后台程序,系统会更具需要,可能回收资源,再打开时候,就会因为资源回收,再调用oncreate,没有Intent参数而导致程序崩溃.   这种情况,我们可以处理的方式有两种,一是用: @Override     protected void onSaveInstanceState(Bundle outState) {      // TODO Auto-generated method stub      super.onSaveInstanceState(outSta

Android平台播放语音时支持听筒、喇叭之间切换

AnyChat for Android SDK默认是通过喇叭进行播放声音. AnyChat r4112版本新增接口,可以在听筒.喇叭之间进行播放声音的切换. AnyChatCoreSDK.mAudioHelper.SwitchPlayMode(0); 复制代码 如果需要指定切换到听筒,则调用API: AnyChatCoreSDK.mAudioHelper.SwitchPlayMode(AnyChatAudioHelper.PLAY_MODE_RECEIVER); 复制代码 如果需要指定切换到喇叭

Android系统切换语言的时候APP无法更新资源文件的解决方法

你的APP支持多语言环境,假如它正在后台运行,此时用户去更换系统语言,等系统语言换好后直接从后台打开它,此时用户会发现你的界面语言没有和系统语言保持一致:为什么?主要是界面资源没有重新加载 如果你是属于自己在APP内设置语言切换,那么就可以直接在你设置切换的那个activity里做处理,重新启动一次该activity就可以了,但是如果你的APP和我类似本身是没有切换语言功能的,只是跟随系统的,那么你不可能在所有的activity里处理吧!所以我这里就直接在application中重新启动一次ap