Android文档学习06_网络2

如果你的程序要执行大量的网络操作,你应该提供用户设置来允许用户控制你应用程序数据的习惯。 比如你的程序多久会进行数据同步,是否只有在拥有Wi-Fi的情况下才执行上传和下载操作,是否使用数据漫游等等。将这些控制变量提供给他们,当用户接近自己的(网络流量)限制时,就不太可能禁用你应用程序对后台数据的访问通道。因为他们可以精确的控制你的应用程序使用多少数据。


所以应用程序的一般策略是只有在Wi-Fi可用的情况下才会获取大量数据


检查网络连接一般使用以下类:

  • ConnectivityManager: 响应网络连接状态查询,同时能在网络连接状态发生改变时通知程序。
  • NetworkInfo:描述给定类型的网络接口状态(无论是移动网络还是Wi-Fi)

以下代码片段测试了Wi-Fi和移动网络连接,它决定了这些网络接口是否可用(即网络连接是否存在) 和/或 是否已经连接网络(即网络连接存在以及是否有可能建立socket通道并传输数据):


private static final String DEBUG_TAG = "NetworkStatusExample";
...      
ConnectivityManager connMgr = (ConnectivityManager) 
        getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI); 
boolean isWifiConn = networkInfo.isConnected();
networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean isMobileConn = networkInfo.isConnected();
Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn);
Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn);
 


需要在执行网络操作之前检查isConnectioned() (看该方法返回是否已经网络连接成功了),在连接成功了之后再执行操作(因为有可能你的移动网络不够稳定,手机处于飞行模式,限制后台数据等状态;译者注:在这种情况下,你可能会得到当前网络可用,但是无法连接的情况;)


更简洁的检查网络接口是否可用的方式如下: getActiveNetworkInfo()方法返回一个NetworkInfo实例,这个实例表示的是系统能够找到并连接的第一个网络接口。如果网络接 口是可以连接的,但是getNetworkInfo返回的是null(这表示当前网络连接无效)


public boolean isOnline() {
    ConnectivityManager connMgr = (ConnectivityManager) 
            getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
    return (networkInfo != null && networkInfo.isConnected());
}  
 


permission权限:

android.permission.INTERNET 允许用户打开网络通道。
android.permission.ACCESS_NETWORK_STATE允许程序访问网络相关信息。

intent filter:

可以为ACTION_MANAGE_NETWORK_USAGE action声明一个intent filter(在Android4.0中有介绍)表明你的应用程序定义了一个提供控制(网络)数据运用选项的activity。 ACTION_MANAGE_NETWORK_USAGE显示了管理特定程序的网络数据运行的设置。当你的应用程序有了一个“设置选项”的activity,用以允许用户控制网络使用,你应该为这个activity定义一个intent filter。在这个简单的例子中,这个action是由SettingActivity类控制的,这个activity显示了一个“设置选项”的UI给用户,让用户决定什么时候下载数据源。


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.networkusage"
    ...>
 
    <uses-sdk android:minSdkVersion="4" 
           android:targetSdkVersion="14" />
 
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 
    <application
        ...>
        ...
        <activity android:label="SettingsActivity" android:name=".SettingsActivity">
             <intent-filter>
                <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
                <category android:name="android.intent.category.DEFAULT" />
          </intent-filter>
        </activity>
    </application>
</manifest>


这里的SettingActivity,注意它实现了OnSharedPreferenceChangeListener,当用户改变了设置,就会触发java.lang.String) onSharedPreferenceChanged()方法,并在这方法中设置refresDisplay为true。这样导致当用户返回主activity时显示会刷新。



public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        // 加载XML设定文件(XML preferences file)
        addPreferencesFromResource(R.xml.preferences);
    }
 
    @Override
    protected void onResume() {
        super.onResume();
 
        // 每当键发生变化注册一个监听事件
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }
 
    @Override
    protected void onPause() {
        super.onPause();
 
       // 注销onResume()方法中设置的监听.  
       // 注销监听最好是当你的程序不使用它们以减少系统不必要的开销, 你可以在onPause()方法中做这件事        
       getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);    
    }
 
    // 当用户改变设置的选项,onSharedPreferenceChanged()重新启动主activity作为一个新任务,
    // 设置refreshDisplay为true以表明主activity应该更新它的显示, 主activity查询PreferenceManager得到最新的设置.
 
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {    
        // 设置refreshDisplay为true,这样当用户返回主activity,显示会根据新设置进行刷新.
        NetworkActivity.refreshDisplay = true;
    }
}


当用户在设置界面修改了选项时,通常都会对应用程序的行为产生影响。在这节代码片段中,应用在onStart()方法中检查设置选项,如果设置和设备的网络连接能够匹配(比如设置中是“Wi-Fi”并且设备也拥有Wi-Fi连接),应用就下载数据源并刷新显示。


public class NetworkActivity extends Activity {
    public static final String WIFI = "Wi-Fi";
    public static final String ANY = "Any";
    private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";
 
    // 是否有一个Wi-Fi连接.
    private static boolean wifiConnected = false; 
    // 是否有一个手机移动网络连接.
    private static boolean mobileConnected = false;
    // 显示是否需要刷新.
    public static boolean refreshDisplay = true;
 
    // 用户当前网络优先设置.
    public static String sPref = null;
 
    // BroadcastReceiver追踪网络连接变化.
    private NetworkReceiver receiver = new NetworkReceiver();
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        // 注册BroadcastReceiver追踪网络连接变化.
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        receiver = new NetworkReceiver();
        this.registerReceiver(receiver, filter);
    }
 
    @Override 
    public void onDestroy() {
        super.onDestroy();
        // 当应用销毁,注销BroadcastReceiver.
        if (receiver != null) {
            this.unregisterReceiver(receiver);
        }
    }
 
    // 如果网络连接和优先设置允许,刷新显示。
 
    @Override
    public void onStart () {
        super.onStart();  
 
        // 得到用户网络设置
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
 
        // 获取设置的字符串,第二个参数为当获取不到设置的值时默认使用的值.
        sPref = sharedPrefs.getString("listPref", "Wi-Fi");
 
        updateConnectedFlags(); 
 
        if(refreshDisplay){
            loadPage();    
        }
    }
 
    // 检查网络连接并设置wifiConnected和mobileConnected变量. 
    public void updateConnectedFlags() {
        ConnectivityManager connMgr = (ConnectivityManager) 
                getSystemService(Context.CONNECTIVITY_SERVICE);
 
        NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
        if (activeInfo != null && activeInfo.isConnected()) {
            wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
            mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
        } else {
            wifiConnected = false;
            mobileConnected = false;
        }  
    }
 
    // 使用AsyncTask子类从stackoverflow.com下载XML数据源.
    public void loadPage() {
        if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
                || ((sPref.equals(WIFI)) && (wifiConnected))) {
            // AsyncTask的子类
            new DownloadXmlTask().execute(URL);
        } else {
            showErrorPage();
        }
    }
...
 
}



简单的应用在onCreate方法中注册了BroadcastReceiver NetworkReceiver,并在onDestroy方法中将其注销。这比在manifest文件中声明<receiver>标签更轻量级

如果你在manifest中声明了一个<receiver>,并且确切的知道在哪里你需要用到它,你可以用int, int) setComponentEnabledSetting()方法适当的启用和禁用它


public class NetworkReceiver extends BroadcastReceiver {   
 
@Override
public void onReceive(Context context, Intent intent) {
    ConnectivityManager conn =  (ConnectivityManager)
        context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = conn.getActiveNetworkInfo();
 
    // 检查用户首选项和网络连接.基于这个结果,决定刷新界面或保持当前显示.
    // 如果用户偏好Wi-Fi, 检查设备是否拥有Wi-Fi连接.
    if (WIFI.equals(sPref) && networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
        // 如果设备有Wi-Fi连接,设置refreshDisplay为true
        // 这是因为当用户返回到应用时,显示应该被刷新.
        refreshDisplay = true;
        Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show();
 
    // 如果设置为任何网络并且这里有一个网络连接,设置refreshDisplay为true.
    } else if (ANY.equals(sPref) && networkInfo != null) {
        refreshDisplay = true;
 
    // 否则, 应用无法下载内容--可能是因为没有网络连接(mobile或Wi-Fi), 
    // 或者是应为用户首选项是Wi-Fi,但没有Wi-Fi连接.设置refreshDisplay为false。
    } else {
        refreshDisplay = false;
        Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show();
   




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值