实现开启和关闭android移动网络(做AppWidget开发的收获)

原创 2012年08月13日 18:44:30

    之前在做Android AppWidget这方面的开发,本人菜鸟一个,刚接触android不久。所以在开发的过程中不免遇到诸多难处,不过在解决问题中收获知识是一种非常刺激的体验。接下来是本人在开发开关android系统移动网络的过程所收获的知识,希望能够帮助有需要的爱好编程者(呵呵..本人是Java语言的忠实粉丝)。

    其实开启和关闭移动数据网络有两种方法:一种是通过操作系统的数据库改变APN(网络接入点),从而实现开启和关闭移动数据网络,另一种是通过反射调用系统(ConnectivityManager)的setMoblieDataEnabled方法,通过操作该方法开启和关闭系统移动数据,同时也可以通过反射调用getMoblieDataEnabled方法获取当前的开启和关闭状态。

 

第一种方式:

   通过APN的方式开启和关闭很威猛啊,为什么这么说呢,废话不多说,先看代码:

   1. 匹配类:

 

//创建一个匹配类,用于匹配移动、电信、联通的APN
public final class APNMatchTools
{

    // 中国移动cmwap
    public static String CMWAP = "cmwap";

    // 中国移动cmnet
    public static String CMNET = "cmnet";

    // 中国联通3gwap APN

    public static String GWAP_3 = "3gwap";

    // 中国联通3gnet APN
    public static String GNET_3 = "3gnet";

    // 中国联通uni wap APN
    public static String UNIWAP = "uniwap";

    // 中国联通uni net APN
    public static String UNINET = "uninet";

    // 中国电信 ct wap APN
    public static String CTWAP = "ctwap";

    // 中国电信ct net APN
    public static String CTNET = "ctnet";

    public static String matchAPN(String currentName)
    {

        if ("".equals(currentName) || null == currentName)
        {

            return "";
        }

        // 参数转为小写
        currentName = currentName.toLowerCase();
        // 检查参数是否与各APN匹配,返回匹配值
        if (currentName.startsWith(CMNET))
            return CMNET;
        else if (currentName.startsWith(CMWAP))
            return CMWAP;
        else if (currentName.startsWith(GNET_3))
            return GNET_3;

        else if (currentName.startsWith(GWAP_3))
            return GWAP_3;
        else if (currentName.startsWith(UNINET))
            return UNINET;

        else if (currentName.startsWith(UNIWAP))
            return UNIWAP;
        else if (currentName.startsWith(CTWAP))
            return CTWAP;
        else if (currentName.startsWith(CTNET))
            return CTNET;
        else if (currentName.startsWith("default"))
            return "default";
        else
            return "";
    }

}

2. 开启和关闭APN的方法在ApnSwitchTest类中实现,如下:

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;

public class ApnSwitchTest extends Activity
{

    Uri uri = Uri.parse("content://telephony/carriers/preferapn");
  
    // 开启APN
    public void openAPN()
    {
        List<APN> list = getAPNList();
        for (APN apn : list)
        {
            ContentValues cv = new ContentValues();

            // 获取及保存移动或联通手机卡的APN网络匹配
            cv.put("apn", APNMatchTools.matchAPN(apn.apn));
            cv.put("type", APNMatchTools.matchAPN(apn.type));

            // 更新系统数据库,改变移动网络状态
            getContentResolver().update(uri, cv, "_id=?", new String[]
            {
                apn.id
            });
        }

    }

    // 关闭APN
    public void closeAPN()
    {
        List<APN> list = getAPNList();
        for (APN apn : list)
        {
            // 创建ContentValues保存数据
            ContentValues cv = new ContentValues();
            // 添加"close"匹配一个错误的APN,关闭网络
            cv.put("apn", APNMatchTools.matchAPN(apn.apn) + "close");
            cv.put("type", APNMatchTools.matchAPN(apn.type) + "close");

            // 更新系统数据库,改变移动网络状态
            getContentResolver().update(uri, cv, "_id=?", new String[]
            {
                apn.id
            });
        }
    }
    
    public static class APN
    {
        String id;

        String apn;

        String type;
    }

    private List<APN> getAPNList()
    {
        // current不为空表示可以使用的APN
        String projection[] =
        {
            "_id, apn, type, current"
        };
        // 查询获取系统数据库的内容
        Cursor cr = getContentResolver().query(uri, projection, null, null, null);

        // 创建一个List集合
        List<APN> list = new ArrayList<APN>();

        while (cr != null && cr.moveToNext())
        {

            Log.d("ApnSwitch", "id" + cr.getString(cr.getColumnIndex("_id")) + " \n" + "apn"
                    + cr.getString(cr.getColumnIndex("apn")) + "\n" + "type"
                    + cr.getString(cr.getColumnIndex("type")) + "\n" + "current"
                    + cr.getString(cr.getColumnIndex("current")));

            APN a = new APN();

            a.id = cr.getString(cr.getColumnIndex("_id"));
            a.apn = cr.getString(cr.getColumnIndex("apn"));
            a.type = cr.getString(cr.getColumnIndex("type"));
            list.add(a);
        }

        if (cr != null)
            cr.close();

        return list;
    }

}<span style="font-family: 'Comic Sans MS'; "> </span>

  最后,别忘了在AndroidManifext.xml文件中添加访问权限<uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />

  亲们,从上面的代码中看出什么来了么,没错,通过APN的方式就是修改数据库,关闭APN其实就是给它随便匹配一个错误的APN。为什么说这种方法很生猛呢,当你通过这个方式关闭APN后,你在通过手机上的快捷开关开启移动数据网络时,是没效果的,也就是说开启不了,除非你再用同样的方法开启APN。

  这就奇怪了,关闭APN后,为什么再通过手机上的快捷开关(AppWidget)开启不了呢,这个问题就值得思考了,说明快捷开关其实并不是通过这个方式来开启和关闭移动网络的。道理很简单,想想那些快捷开关是怎么样根据开启和关闭移动网络,然后更换亮和暗的图标的呢(更新UI)。这里肯定会涉及到一个获取系统当前开启和关闭移动数据状态的问题。那到底是怎样获取的,是通过什么样的形式的?其实道理很简单,就是通过调用系统的getMoblieDataEnabled和setMoblieDataEnabled我是这么知道它是调用到这个方法的呢?亲们,如果你有android手机,把它插到电脑上,然后开启已经搭建好的android开发环境的eclpise,打开logcat面板,相应地在你手机的快捷开关上开启和关闭移动网络,然后看看在logcat面板上出现什么了)。

  既然知道是调用上面这两个方法了,我们是不是就可以直接调用这个两个方法实现了?NO,没这么简单,这个两个方法不能直接调用,必须通过反射机制调用(呵呵,没接触过java有关反射的知识的,或者是忘了的,可以去学习和温习一下)。

 

第二种方式:

  废话不多说,看下面的代码:

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;

public class MobileDataSwitchTest extends Activity
{

 // 移动数据开启和关闭
    public void setMobileDataStatus(Context context,boolean enabled)

    {

    ConnectivityManager conMgr = (ConnectivityManager)this.getSystemService(Context.CONNECTIVITY_SERVICE);

    //ConnectivityManager类

    Class<?> conMgrClass = null;

      //ConnectivityManager类中的字段
      Field iConMgrField = null;
      //IConnectivityManager类的引用
      Object iConMgr = null;
      //IConnectivityManager类
      Class<?> iConMgrClass = null;
      //setMobileDataEnabled方法
       Method setMobileDataEnabledMethod = null;
    try
      {

       //取得ConnectivityManager类
       conMgrClass = Class.forName(conMgr.getClass().getName());
       //取得ConnectivityManager类中的对象Mservice
       iConMgrField = conMgrClass.getDeclaredField("mService");
       //设置mService可访问
       iConMgrField.setAccessible(true);
       //取得mService的实例化类IConnectivityManager
       iConMgr = iConMgrField.get(conMgr);
       //取得IConnectivityManager类
    iConMgrClass = Class.forName(iConMgr.getClass().getName());

       //取得IConnectivityManager类中的setMobileDataEnabled(boolean)方法
    setMobileDataEnabledMethod = iConMgrClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);

       //设置setMobileDataEnabled方法是否可访问   
       setMobileDataEnabledMethod.setAccessible(true);
          //调用setMobileDataEnabled方法
          setMobileDataEnabledMethod.invoke(iConMgr, enabled);

    }

    catch(ClassNotFoundException e)
      {

    e.printStackTrace();
      }
    catch(NoSuchFieldException e)
      {

    e.printStackTrace();
      }

      catch(SecurityException e)
      {
       e.printStackTrace();

    }
      catch(NoSuchMethodException e)

    {
       e.printStackTrace();
      }

    catch(IllegalArgumentException e)
      {

    e.printStackTrace();
      }

    catch(IllegalAccessException e)
      {

    e.printStackTrace();
      }

    catch(InvocationTargetException e)

    {

    e.printStackTrace();

    }

    }

     

     //获取移动数据开关状态

     

    public boolean getMobileDataStatus(String getMobileDataEnabled)

    {

      ConnectivityManager cm;

    cm = (ConnectivityManager)this.getSystemService(Context.CONNECTIVITY_SERVICE);

       Class cmClass = cm.getClass();
       Class[] argClasses = null;
       Object[] argObject = null;
       Boolean isOpen = false;
    try
       {

    Method method = cmClass.getMethod(getMobileDataEnabled, argClasses);

        isOpen = (Boolean)method.invoke(cm, argObject);
       }catch(Exception e)
    {
        e.printStackTrace();
       }

    return isOpen;

    }
}

最后,别忘了在AndroidMannifest.xml文件里添加访问权限 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />,  <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

通过上面的代码可以知道,当开启移动网络时调用setMobileDataStatus(context,true),关闭调用setMobileDataStatus(context,false),通过getMobileDataStatus(String getMobileDataEnabled)方法返回的布尔值判断当移动数据网络前状态的开启和关闭。

 

  注:本人第一次发博客,如有不足之处恳请多多谅解,诚心接受大家的批评及采纳大家的意见!大家共同努力学习!!

android 关闭wifi和打开移动数据网络

  • 2016年11月30日 14:10
  • 1.99MB
  • 下载

实现开启和关闭android移动网络

开启和关闭移动数据网络有两种方法:一种是通过操作系统的数据库改变APN(网络接入点),从而实现开启和关闭移动数据网络,另一种是通过反射调用系统(ConnectivityManager)的setMobl...
  • fangzhibin4712
  • fangzhibin4712
  • 2014年05月22日 10:16
  • 11727

Android 5.0以上移动网络开关

Android 5.0以前使用ConnectivityManager通过反射两个方法setMobileDataEnabled和getMobileDataEnabled来控制移动网络开和关。 Andr...
  • llj0201
  • llj0201
  • 2017年01月03日 10:01
  • 1244

Android 6.0 自动开启移动数据流程

在M版本,触发建立默认的数据连接的机制跟以前的版本有比较大的变化,本文主要介绍触发建立数据连接的开始阶段,而建立data call的过程跟之前是一样的,只要条件准备好了发起就可以了。 ...
  • leesino
  • leesino
  • 2016年01月14日 14:37
  • 4051

Android判断网络是否打开,并打开设置网络界面

由于Android的SDK版本不同所以里面的API和设置方式也是有少量变化的,尤其是在Android 3.0 及后面的版本,UI和显示方式也发生了变化,现在就以打开网络设置为例,同大家分享一下,效果如...
  • wangjia55
  • wangjia55
  • 2012年08月30日 12:13
  • 20812

android开启和关闭移动网络

转自:http://blog.csdn.net/stevenhu_223/article/details/7860964 /** * 移动数据开启和关闭 * * @param c...
  • yueguanyun
  • yueguanyun
  • 2013年06月06日 10:22
  • 2232

Android判断网络连接是否可用,WiFi、移动数据是否打开等

Android判断网络连接是否可用,WiFi、移动数据是否打开等 添加权限 代码 //判断网络连接是否可用 public static boolean isNetworkAv...
  • shenyuanqing
  • shenyuanqing
  • 2015年10月19日 14:33
  • 7476

Android5.0以上系统的移动网络开关

笔者最近遇到一个非常有意思的bug,贴出来和大家分享下。 那是一个温暖的早晨,阳光晒的人很舒服。一封bug邮件像一片叶子飘到我的邮箱。一番交流,笔者确认负责的Widget开关在Android5.0以...
  • leirenbaobao
  • leirenbaobao
  • 2015年07月30日 21:03
  • 4422

Android中使用代码控制Wifi及数据连接网络开关

有时我们需要在APP中控制WIFI和数据连接的开关,在Android中,是有相应的接口可以实现这一功能的。 控制WIFI开关控制WIFI开关需要使用WifiManager这一系统服务。首先我们通过代...
  • ucxiii
  • ucxiii
  • 2015年12月10日 23:00
  • 6208

Android下同时使用WIFI与移动网络时保证优先使用移动网络

近期有个车载wifi音响项目涉及APP连接硬件,APP和硬件处于同一局域网,那么问题来了,如何保证APP在连接硬件wifi(wifi 做热点不能上网)的同时和开启移动网络(移动网络可以上网)也要能保证...
  • ivan_
  • ivan_
  • 2017年07月01日 18:03
  • 899
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:实现开启和关闭android移动网络(做AppWidget开发的收获)
举报原因:
原因补充:

(最多只允许输入30个字)