Android | 判断连接的网络是否可用以及是否连接网络

一、查看当前手机的网络状态,需要获取ConnectionManager

    1. ConnectionManager方式
 /**
     * 判断当前是否有网络连接,但是如果该连接的网络无法上网,也会返回true
     * @param mContext
     * @return
     */
    public static boolean isNetConnection(Context mContext) {
        if (mContext!=null){
            ConnectivityManager connectivityManager = 
                          (ConnectivityManager) mContext.
                          getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            boolean connected = networkInfo.isConnected();
            if (networkInfo!=null&&connected){
                if (networkInfo.getState()== NetworkInfo.State.CONNECTED){
                    return true;
                }else{
                    return false;
                }
            }
        }
        return false;
    }

    1. NetworkCapabilities类方式(6.0以上)

NetworkCapabilities是API 21新增加的一个工具类,这类本身没有太多内容,主要是用来描述网络状态和传输类型,具体的内容请查阅相关文档,这里就不多介绍了。NetworkCapabilities提供了方法,用来判断当前网络是否可用,而且是不耗时的方法。


  /**
     * 判断当前网络是否可用(6.0以上版本)
     * 实时
     * @param context
     * @return
     */
    public static boolean isNetSystemUsable(Context context) {
        boolean isNetUsable = false;
        ConnectivityManager manager = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            NetworkCapabilities networkCapabilities =
                    manager.getNetworkCapabilities(manager.getActiveNetwork());
            if (networkCapabilities != null) {
                isNetUsable = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
            }
        }
        return isNetUsable;
    }




二、有网络连接情况下,检测网络能否正常上网

注意:此方法需要在子线程调用,否则报错:android.os.NetworkOnMainThreadException



 /**
     * 功能:检测当前URL是否可连接或是否有效,
     * 描述:最多连接网络 x次, 如果 x 次都不成功,视为该地址不可用
     * @return true是可以上网,false是不能上网
     */
    private static URL url;
    private static HttpURLConnection con;
    private static int state = -1;
    public static boolean isNetOnline() {
        // Android 4.0 之后不能在主线程中请求HTTP请求
        int counts = 0;
        boolean isNetsOnline = true;
        while (counts < 2) {
            try {
                url = new URL("https://www.baidu.com");
                con = (HttpURLConnection) url.openConnection();
                state = con.getResponseCode();
                Log.e("FragmentNet", "isNetOnline counts: " + counts + "=state: " + state);
                if (state == 200) {
                    isNetsOnline = true;
                }
                break;
            } catch (Exception ex) {
                isNetsOnline = false;
                counts++;
                Log.e("FragmentNet", "isNetOnline URL不可用,连接第 " + counts + " 次");
                continue;
            }
        }
        return isNetsOnline;

    }


三、ping 网络方式

注意: ping网址是最最常用的一种判断网络的方式,也是通用方法。这种方法最大的劣势是,耗时很长,我曾计算过,ping一次的时间大约是10s,两次是11s,每增加一次就多耗时1s。虽然这种方法耗时较长,但这是目前最常用的方法,而且没有更好的方法取代。

有时候我们连接上一个没有外网连接的WiFi或者有线就会出现这种极端的情况,
目前Android SDK还不能识别这种情况,一般的解决办法就是ping一个外网

    /**
     * @category 判断是否有外网连接(普通方法不能判断外网的网络是否连接,比如连接上局域网)
     * @return
     */
    public static final boolean ping() {

        String result = null;
        try {
            String ip = "www.baidu.com";// ping 的地址,可以换成任何一种可靠的外网
            Process p = Runtime.getRuntime().exec("ping -c 3 -w 100 " + ip);// ping网址3次
            // 读取ping的内容,可以不加
            InputStream input = p.getInputStream();
            BufferedReader in = new BufferedReader(new InputStreamReader(input));
            StringBuffer stringBuffer = new StringBuffer();
            String content = "";
            while ((content = in.readLine()) != null) {
                stringBuffer.append(content);
            }

//            Log.d("------ping-----", "result content : " + stringBuffer.toString());
            // ping的状态
            int status = p.waitFor();
            if (status == 0) {
                result = "success";
                return true;
            } else {
                result = "failed";
            }
        } catch (IOException e) {
            result = "IOException";
        } catch (InterruptedException e) {
            result = "InterruptedException";
        } finally {
//            Log.d("----result---", "result = " + result);
        }
        return false;
    }
  • 虽然现在主流手机系统都是6.0以上,但是总有一些“老爷机”还坚挺的使用5.0甚至是4.4以上的系统。为了适配问题,方法1依然是主流的方法,这也是Android开发最麻烦的地方。

  • 另外,ping的方法可以判断当前网络的可用情况。

     process.waitFor() 返回0,当前网络可用
     process.waitFor() 返回1,需要网页认证的wifi
     process.waitFor() 返回2,当前网络不可用

-关于需要网页认证的wifi:

警惕360wifi!!!


360wifi本身其实是不需要认证的,连接上网络之后就可以直接使用。但是用方法进行判断时,
process.waitFor()返回的却是1。有一些手机系统(比如魅族),在监测到当前wifi需要网页认证时,
会自动打开浏览器。这本身是一个很人性化的设计,然而会被某些企业利用,在连接上wifi之后,
自动跳转到广告页面。

所以大家如果用360wifi进行验证,自求多福,那毕竟是360啊。


四、解决android.os.NetworkOnMainThreadException

1.在Android 4.0以上,网络连接不能放在主线程上,不然就会报错android.os.NetworkOnMainThreadException。但是4.0下版本可以不会报错。

2.在Android4.0以后,会发现,只要是写在主线程(就是Activity)中的HTTP请求,运行时都会报错,这是因为Android在4.0以后为了防止应用的ANR(Aplication Not Response)异常,Android这个设计是为了防止网络请求时间过长而导致界面假死的情况发生。

image.png

解决此问题有两种解决的方法:

1.可以再Activity的onCreate()方法中加入这样一段代码,适用于网络请求数据量很小的话,如下

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}

2.启动一条子线程进行你的网络请求,推荐使用这种

// Android 4.0 之后不能在主线程中请求HTTP请求
new Thread(new Runnable(){
         @Override
         public void run() {
               cachedImage = asyncImageLoader.loadDrawable(imageUrl, position);
               imageView.setImageDrawable(cachedImage);
         }
 }).start();

你可能感兴趣的:(Android | 判断连接的网络是否可用以及是否连接网络)