Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4973355
  • 博文数量: 1696
  • 博客积分: 10870
  • 博客等级: 上将
  • 技术积分: 18357
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-30 15:16
文章分类
文章存档

2017年(1)

2016年(1)

2015年(1)

2013年(1)

2012年(43)

2011年(17)

2010年(828)

2009年(568)

2008年(185)

2007年(51)

分类: 嵌入式

2010-12-02 18:15:03

Reading NetworkInterfaceType can take over 20 seconds!

We have an app where we need to determine whether the phone has an internet connection, and whether it is on WiFi or cellular. We do this step when the app launches or whenever it reactivates after tombstoning.

To determine the type of connection, we use , as in:
using Microsoft.Phone.Net.NetworkInformation; 
 
NetworkInterfaceType currentInterface =  NetworkInterface.NetworkInterfaceType; 
NetworkInterfaceType is an enum that identifies the connection type: WiFi, Ethernet (via USB to a PC), cellular or none.

We were running into an issue where the app was taking a long time start up or reactivate, sometimes so long that the system closed the app (I believe because the system thinks it became unresponsive). I narrowed it down to the statement that accessed NetworkInterface.NetworkInterfaceType. I tested and found that executing that single statement could take anywhere from 0.3 seconds to 23 seconds! The same behavior was repeatable on the Samsung Focus and the developer LG Pacific.

I had put the statement in the UI thread because I thought NetworkInterfaceType is a value that would be returned immediately. So the single statement was sometimes hanging up the UI for a very long time. My workaround was to retrieve NetworkInterfaceType in a worker thread and check the value later. 

Below is my test app to measure response time. If you click on the NetworkInterfaceType button, it will display the returned value and how long it took. Here I'm using a worker thread as I do in our product app, but I saw no difference if NetworkInterfaceType is retrieved directly in the click handler.
 
MainPage.xaml
<phone:PhoneApplicationPage  
    x:Class="NetworkStatus.MainPage" 
    xmlns="" 
    xmlns:x="" 
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" 
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" 
    xmlns:d="" 
    xmlns:mc="" 
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768" 
    FontFamily="{StaticResource PhoneFontFamilyNormal}" 
    FontSize="{StaticResource PhoneFontSizeNormal}" 
    Foreground="{StaticResource PhoneForegroundBrush}" 
    SupportedOrientations="Portrait" Orientation="Portrait" 
    shell:SystemTray.IsVisible="True"
 
     
    <Grid x:Name="LayoutRoot" Background="Transparent"
        <Grid.RowDefinitions> 
            <RowDefinition Height="Auto"/> 
            <RowDefinition Height="*"/> 
        Grid.RowDefinitions> 
 
         
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"
            <TextBlock x:Name="ApplicationTitle" Text="NETWORK STATUS" Style="{StaticResource PhoneTextNormalStyle}"/> 
            <TextBlock x:Name="PageTitle" Text="api timing" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 
        StackPanel> 
 
         
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"
            <StackPanel VerticalAlignment="Center"
                <TextBlock x:Name="GetIsNetworkAvailableText" Height="34" HorizontalAlignment="Center" FontSize="24"/> 
                <Button x:Name="GetIsNetworkAvailableButton"  Content="GetIsNetworkAvailable()" Margin="0,0,0,40" Click="GetIsNetworkAvailableButton_Click"/> 
                <TextBlock x:Name="NetworkInterfaceTypeText" Height="34" HorizontalAlignment="Center" FontSize="24"/> 
                <Button x:Name="NetworkInterfaceTypeButton" Content="NetworkInterfaceType" Click="NetworkInterfaceTypeButton_Click"/> 
            StackPanel> 
        Grid> 
    Grid> 
 
phone:PhoneApplicationPage> 


MainPage.xaml.cs
using System; 
using System.Windows; 
using Microsoft.Phone.Controls; 
using System.ComponentModel; 
using Microsoft.Phone.Net.NetworkInformation; 
 
namespace NetworkStatus 
    public partial class MainPage : PhoneApplicationPage 
    { 
        BackgroundWorker networkAvailableWorker; 
        BackgroundWorker interfaceTypeWorker; 
        NetworkInterfaceType netType; 
        bool isNetworkAvailable; 
        TimeSpan typeResponseTime; 
        TimeSpan availableResponseTime; 
 
        // Constructor 
        public MainPage() 
        { 
            InitializeComponent(); 
 
            networkAvailableWorker = new BackgroundWorker(); 
            networkAvailableWorker.DoWork += new DoWorkEventHandler(networkAvailableWorker_DoWork); 
            networkAvailableWorker.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(networkAvailableWorker_RunWorkerCompleted); 
 
            interfaceTypeWorker = new BackgroundWorker(); 
            interfaceTypeWorker.DoWork += new DoWorkEventHandler(interfaceTypeWorker_DoWork); 
            interfaceTypeWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(interfaceTypeWorker_RunWorkerCompleted); 
        } 
 
        private void GetIsNetworkAvailableButton_Click(object sender, RoutedEventArgs e) 
        { 
            GetIsNetworkAvailableText.Text = "waiting..."
            GetIsNetworkAvailableButton.IsEnabled = false
            networkAvailableWorker.RunWorkerAsync(); 
        } 
 
        void networkAvailableWorker_DoWork(object sender, DoWorkEventArgs e) 
        { 
            DateTime beginTime = DateTime.UtcNow; 
            isNetworkAvailable = NetworkInterface.GetIsNetworkAvailable(); 
            availableResponseTime = DateTime.UtcNow - beginTime; 
        } 
 
        void networkAvailableWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
        { 
            GetIsNetworkAvailableText.Text = isNetworkAvailable.ToString() + String.Format(" ({0}s)", availableResponseTime.TotalMilliseconds/1000.0); 
            GetIsNetworkAvailableButton.IsEnabled = true
        } 
 
        private void NetworkInterfaceTypeButton_Click(object sender, RoutedEventArgs e) 
        { 
            NetworkInterfaceTypeText.Text = "waiting..."
            NetworkInterfaceTypeButton.IsEnabled = false
            interfaceTypeWorker.RunWorkerAsync(); 
        } 
 
        void interfaceTypeWorker_DoWork(object sender, DoWorkEventArgs e) 
        { 
            DateTime beginTime = DateTime.UtcNow; 
            netType = NetworkInterface.NetworkInterfaceType; 
            typeResponseTime = DateTime.UtcNow - beginTime; 
        } 
 
        void interfaceTypeWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
        { 
            NetworkInterfaceTypeText.Text = netType.ToString() + String.Format(" ({0}s)", typeResponseTime.TotalMilliseconds/1000.0); 
            NetworkInterfaceTypeButton.IsEnabled = true
        } 
 
    } 

I found that when the phone was connected on WiFi or USB, NetworkInterfaceType would usually return in less than half a second. However on cellular connection there were huge variations. 2-3 seconds was typical while in good cellular coverage. The reponse may drop to half a second after repeating the operation, but may go back up just a few moments later. Under marginal cellular coverage, the time can vary from a couple of seconds up to over 20 seconds (worst I saw was 23 sec).

This suggests that it is performing some kind of ping test and the slow response comes from actual internet delay. However, all I want to know is what type of network the phone is currently using. Isn't that always known by the phone and should give an instantaneous result? Using a worker thread helped, but our UI needs to do different actions depending on WiFi/cellular and it is a burden needing to handle a result that may not return for 20 seconds.
阅读(1140) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~