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

来源:互联网 发布:产业并购基金 知乎 编辑:程序博客网 时间:2024/04/28 08:06
开启和关闭移动数据网络有两种方法:一种是通过操作系统的数据库改变APN(网络接入点),从而实现开启和关闭移动数据网络,另一种是通过反射调用系统(ConnectivityManager)的setMoblieDataEnabled方法,通过操作该方法开启和关闭系统移动数据,同时也可以通过反射调用getMoblieDataEnabled方法获取当前的开启和关闭状态。

 

第一种方式:

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

   1. 匹配类:

 

[java] view plaincopy
  1. //创建一个匹配类,用于匹配移动、电信、联通的APN  
  2. public final class APNMatchTools  
  3. {  
  4.   
  5.     // 中国移动cmwap  
  6.     public static String CMWAP = "cmwap";  
  7.   
  8.     // 中国移动cmnet  
  9.     public static String CMNET = "cmnet";  
  10.   
  11.     // 中国联通3gwap APN  
  12.   
  13.     public static String GWAP_3 = "3gwap";  
  14.   
  15.     // 中国联通3gnet APN  
  16.     public static String GNET_3 = "3gnet";  
  17.   
  18.     // 中国联通uni wap APN  
  19.     public static String UNIWAP = "uniwap";  
  20.   
  21.     // 中国联通uni net APN  
  22.     public static String UNINET = "uninet";  
  23.   
  24.     // 中国电信 ct wap APN  
  25.     public static String CTWAP = "ctwap";  
  26.   
  27.     // 中国电信ct net APN  
  28.     public static String CTNET = "ctnet";  
  29.   
  30.     public static String matchAPN(String currentName)  
  31.     {  
  32.   
  33.         if ("".equals(currentName) || null == currentName)  
  34.         {  
  35.   
  36.             return "";  
  37.         }  
  38.   
  39.         // 参数转为小写  
  40.         currentName = currentName.toLowerCase();  
  41.         // 检查参数是否与各APN匹配,返回匹配值  
  42.         if (currentName.startsWith(CMNET))  
  43.             return CMNET;  
  44.         else if (currentName.startsWith(CMWAP))  
  45.             return CMWAP;  
  46.         else if (currentName.startsWith(GNET_3))  
  47.             return GNET_3;  
  48.   
  49.         else if (currentName.startsWith(GWAP_3))  
  50.             return GWAP_3;  
  51.         else if (currentName.startsWith(UNINET))  
  52.             return UNINET;  
  53.   
  54.         else if (currentName.startsWith(UNIWAP))  
  55.             return UNIWAP;  
  56.         else if (currentName.startsWith(CTWAP))  
  57.             return CTWAP;  
  58.         else if (currentName.startsWith(CTNET))  
  59.             return CTNET;  
  60.         else if (currentName.startsWith("default"))  
  61.             return "default";  
  62.         else  
  63.             return "";  
  64.     }  
  65.   
  66. }  

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

[java] view plaincopy
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. import android.app.Activity;  
  5. import android.content.ContentValues;  
  6. import android.database.Cursor;  
  7. import android.net.Uri;  
  8. import android.util.Log;  
  9.   
  10. public class ApnSwitchTest extends Activity  
  11. {  
  12.   
  13.     Uri uri = Uri.parse("content://telephony/carriers/preferapn");  
  14.     
  15.     // 开启APN  
  16.     public void openAPN()  
  17.     {  
  18.         List<APN> list = getAPNList();  
  19.         for (APN apn : list)  
  20.         {  
  21.             ContentValues cv = new ContentValues();  
  22.   
  23.             // 获取及保存移动或联通手机卡的APN网络匹配  
  24.             cv.put("apn", APNMatchTools.matchAPN(apn.apn));  
  25.             cv.put("type", APNMatchTools.matchAPN(apn.type));  
  26.   
  27.             // 更新系统数据库,改变移动网络状态  
  28.             getContentResolver().update(uri, cv, "_id=?"new String[]  
  29.             {  
  30.                 apn.id  
  31.             });  
  32.         }  
  33.   
  34.     }  
  35.   
  36.     // 关闭APN  
  37.     public void closeAPN()  
  38.     {  
  39.         List<APN> list = getAPNList();  
  40.         for (APN apn : list)  
  41.         {  
  42.             // 创建ContentValues保存数据  
  43.             ContentValues cv = new ContentValues();  
  44.             // 添加"close"匹配一个错误的APN,关闭网络  
  45.             cv.put("apn", APNMatchTools.matchAPN(apn.apn) + "close");  
  46.             cv.put("type", APNMatchTools.matchAPN(apn.type) + "close");  
  47.   
  48.             // 更新系统数据库,改变移动网络状态  
  49.             getContentResolver().update(uri, cv, "_id=?"new String[]  
  50.             {  
  51.                 apn.id  
  52.             });  
  53.         }  
  54.     }  
  55.       
  56.     public static class APN  
  57.     {  
  58.         String id;  
  59.   
  60.         String apn;  
  61.   
  62.         String type;  
  63.     }  
  64.   
  65.     private List<APN> getAPNList()  
  66.     {  
  67.         // current不为空表示可以使用的APN  
  68.         String projection[] =  
  69.         {  
  70.             "_id, apn, type, current"  
  71.         };  
  72.         // 查询获取系统数据库的内容  
  73.         Cursor cr = getContentResolver().query(uri, projection, nullnullnull);  
  74.   
  75.         // 创建一个List集合  
  76.         List<APN> list = new ArrayList<APN>();  
  77.   
  78.         while (cr != null && cr.moveToNext())  
  79.         {  
  80.   
  81.             Log.d("ApnSwitch""id" + cr.getString(cr.getColumnIndex("_id")) + " \n" + "apn"  
  82.                     + cr.getString(cr.getColumnIndex("apn")) + "\n" + "type"  
  83.                     + cr.getString(cr.getColumnIndex("type")) + "\n" + "current"  
  84.                     + cr.getString(cr.getColumnIndex("current")));  
  85.   
  86.             APN a = new APN();  
  87.   
  88.             a.id = cr.getString(cr.getColumnIndex("_id"));  
  89.             a.apn = cr.getString(cr.getColumnIndex("apn"));  
  90.             a.type = cr.getString(cr.getColumnIndex("type"));  
  91.             list.add(a);  
  92.         }  
  93.   
  94.         if (cr != null)  
  95.             cr.close();  
  96.   
  97.         return list;  
  98.     }  
  99.   
  100. }<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)。这里肯定会涉及到一个获取系统当前开启和关闭移动数据状态的问题。那到底是怎样获取的,是通过什么样的形式的?其实道理很简单,就是通过调用系统的getMobileDataState和setMobileData(我是这么知道它是调用到这个方法的呢?亲们,如果你有android手机,把它插到电脑上,然后开启已经搭建好的android开发环境的eclpise,打开logcat面板,相应地在你手机的快捷开关上开启和关闭移动网络,然后看看在logcat面板上出现什么了)。

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


    /**     * 设置手机的移动数据     */    public static void setMobileData(Context pContext, boolean pBoolean) {        try {            ConnectivityManager mConnectivityManager = (ConnectivityManager) pContext.getSystemService(Context.CONNECTIVITY_SERVICE);            Class ownerClass = mConnectivityManager.getClass();            Class[] argsClass = new Class[1];            argsClass[0] = boolean.class;            Method method = ownerClass.getMethod("setMobileDataEnabled", argsClass);            method.invoke(mConnectivityManager, pBoolean);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();            System.out.println("移动数据设置错误: " + e.toString());        }    }    /**     * 返回手机移动数据的状态     *     * @param pContext     * @param arg     *            默认填null     * @return true 连接 false 未连接     */    public static boolean getMobileDataState(Context pContext, Object[] arg) {        try {            ConnectivityManager mConnectivityManager = (ConnectivityManager) pContext.getSystemService(Context.CONNECTIVITY_SERVICE);            Class ownerClass = mConnectivityManager.getClass();            Class[] argsClass = null;            if (arg != null) {                argsClass = new Class[1];                argsClass[0] = arg.getClass();            }            Method method = ownerClass.getMethod("getMobileDataEnabled", argsClass);            Boolean isOpen = (Boolean) method.invoke(mConnectivityManager, arg);            return isOpen;        } catch (Exception e) {            // TODO: handle exception            System.out.println("得到移动数据状态出错");            return false;        }    }</span>



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

<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

通过上面的代码可以知道,当开启移动网络时调用:

setMobileData(context,true),关闭调用setMobileData(context,false),通过getMobileDataStatus(context)方法返回的布尔值判断当移动数据网络前状态的开启和关闭。


2 0