Windows Phone应用消耗过多电池。使用HttpClient

时间:2014-05-25 00:12:14

标签: c# windows-phone-8

我正在编写一个允许用户控制媒体经典播放器(MPC)播放的应用,例如暂停/播放,音量调高/降低,同步字幕等.MPC有一个可以激活的Web界面互动更容易。但有时当我运行和使用该应用程序时,我的电池耗尽比平常更快。

我非常确定导致电池消耗过多的关键特性是定时器。代码低于此描述,但为了简化,几秒钟后,它会重复{We​​b站点的HttpClient请求以接收正确的播放器当前时间。

我的问题是:我是否认为即使应用程序不再运行,HttpClient行为可能会产生过多请求并进行堆叠?而且,如果HttpClient不是使用和与Web服务器交互的正确或更好的对象,它会是什么?欢迎提供有关C#中请求的建议(方法,对象,关于这些对象的书籍等)

该应用程序在名为 MainPage.cs 的文件中运行。它使用名为 Player.cs 的类的方法。

MainPage.cs

namespace homecinemarc
{
    public partial class MainPage : PhoneApplicationPage
    {
        public IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
        // Timer to check movie status is defined here
        public DispatcherTimer timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(.3) };
        public HttpClient client = new HttpClient();
        private Player player;
        private string filename;

        // Constructor
        public MainPage()
        {
            // Default initialization
            InitializeComponent();

            if (settings.Contains("ip") && settings.Contains("port"))
            {
                player = new Player(settings["ip"] as string, settings["port"] as string);
            }

            if (!DeviceNetworkInformation.IsWiFiEnabled)
            {
                MessageBox.Show("Your phone's wifi is off. To run this app correctly, you must turn it on. You will be redirected to you Windows Phone connectivity settings.");
                ConnectionSettingsTask connectionSettingsTask = new ConnectionSettingsTask();
                connectionSettingsTask.ConnectionSettingsType = ConnectionSettingsType.WiFi;
                connectionSettingsTask.Show();
            }


            // Default Messaging
            connectedMessage.Text = "Connecting to homecinema";
            progressBar.Visibility = Visibility.Visible;           
        }

        /// <summary>
        /// Core code
        /// </summary>
        private async void MainProgram()
        {
            if (await player.checkConnection())
            {

                connectedMessage.Text = "Connected to " + player.ip + ":" + player.port;
                PlayButton.IsEnabled = true;
                PauseButton.IsEnabled = true;

                // Verificar posição do player
                await player.checkStatus();

                // Update with player status;
                barPosition.Maximum = player.totalTime.Ticks;
                barPosition.Value = player.currentTime.Ticks;

                txtCurrentTime.Text = player.currentTime.ToString();
                txtTotalTime.Text = player.totalTime.ToString();

                if (player.status == "Playing")
                {
                    PauseButton.Visibility = Visibility.Visible;
                    PlayButton.Visibility = Visibility.Collapsed;
                }
                else
                {
                    PauseButton.Visibility = Visibility.Collapsed;
                    PlayButton.Visibility = Visibility.Visible;
                }

                timer.Tick += updateTimers;
                timer.Start();
            }
            else
            {
                player.showError(Error.FailedToConnect);
                connectedMessage.Text = "Connection Failed to " + player.ip + ":" + player.port;
            }
            progressBar.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// Checks if it's the first run of the app.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            // First run, runs a basic configuration.
            if (!settings.Contains("firstRun"))
            {
                try
                {
                    MessageBox.Show("This is your first run! Let me show how to setup Homecinema correctly. You must tap on Settings by the end of the instructions, set an IP and save it to use this app correctly :)");
                    NavigationService.Navigate(new Uri("/HelpPage.xaml", UriKind.Relative));
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                MainProgram();
            }
        }

        /// <summary>
        /// Update timer values
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void updateTimers(object sender, EventArgs e)
        {
            await player.checkStatus();

            string currentFilename = player.filename;

            // Checks if there is a change of file and reset 
            // subtitle delay value if there is.
            if (filename != currentFilename)
                player.subtitleDelay = 0;

            barPosition.Value = player.currentTime.Ticks;
            txtCurrentTime.Text = player.currentTime.ToString();
            txtStatus.Text = player.status;
            txtVolume.Text = player.volumeValue + "%";
            txtVolume.Foreground = new SolidColorBrush(Colors.White);
            txtFilename.Text = player.filename;
            txtSubtitleValue.Text = player.subtitleDelay + "ms";
            filename = player.filename;

            if (player.volumeMute == 1)
            {
                txtVolume.Text = "Mute";
                txtVolume.Foreground = new SolidColorBrush(Colors.Red);
            }

            if (player.status == "Playing")
            {
                PlayButton.Visibility = Visibility.Collapsed;
                PauseButton.Visibility = Visibility.Visible;
            }
            else
            {
                PauseButton.Visibility = Visibility.Collapsed;
                PlayButton.Visibility = Visibility.Visible;
            }

        }

        /********************************
         * Events 
         ********************************/

        private void Refresh_Click(object sender, EventArgs e)
        {
            connectedMessage.Text = "Connecting to homecinema";
            progressBar.Visibility = Visibility.Visible;

            MainProgram();
        }

        private void Play_Click(object sender, RoutedEventArgs e)
        {
            player.makeRequest("887");
            txtStatus.Text = "Playing";
            timer.Start();
            PlayButton.Visibility = Visibility.Collapsed;
            PauseButton.Visibility = Visibility.Visible;
        }

        private void Pause_Click(object sender, RoutedEventArgs e)
        {
            player.makeRequest("888");
            txtStatus.Text = "Paused";
            PauseButton.Visibility = Visibility.Collapsed;
            PlayButton.Visibility = Visibility.Visible;
        }

        private void btn_volumeMute_Click(object sender, RoutedEventArgs e)
        {
            player.makeRequest("909");
        }

        private void btnVolumeUp_Click(object sender, RoutedEventArgs e)
        {
            player.makeRequest("907");
        }

        // There are some other events but all with the same structure as
        // above.

    }
}

Player.cs

namespace homecinemarc
{
    class Player
    {
        public Connection conn;
        public string ip { get; set; }
        public string port { get; set; }
        public string filename { get; private set; }
        public string status { get; private set; }
        public int volumeValue { get; private set; }
        public int volumeMute { get; private set; }
        public bool isConnected { get; private set; }
        public TimeSpan currentTime;
        public TimeSpan totalTime;
        public int subtitleDelay { get; set; }
        private HttpClient client = new HttpClient();

        // Constructor
        public Player(string ip, string port)
        {
            conn = new Connection(ip, port);
            this.ip = ip;
            this.port = port;
            this.subtitleDelay = 0;
        }

        /// <summary>
        /// Check if there is a connection to defined IP and Port to allow the app to run
        /// </summary>
        public async Task<bool> checkConnection()
        {
            try
            {
                HttpResponseMessage aResponse = await client.GetAsync(new Uri("http://" + ip + ":" + port + "/command.html"));
                isConnected = aResponse.StatusCode.Equals(HttpStatusCode.OK);
                return isConnected;

            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// Update variables of timers 
        /// </summary>
        /// <returns></returns>
        public async Task checkStatus()
        {
            HttpResponseMessage aResponse = await client.GetAsync(new Uri("http://" + this.ip + ":" + this.port + "/status.html"));
            string[] match = Regex.Split(aResponse.Content.ReadAsStringAsync().Result, @",");

            if (match.Length > 0){
                TimeSpan.TryParse(match[3].Substring(2, match[3].Length - 3), out currentTime);
                TimeSpan.TryParse(match[5].Substring(2, match[5].Length - 3), out totalTime);
                status = match[1].Substring(2, match[1].Length - 3);
                volumeMute = int.Parse(match[6]);
                volumeValue = int.Parse(match[7]);

                // These next steps try to remove Rippers, file formarts, etc
                // to show a short yet useful name. That's because MPC don't
                // return the media title (like, IDv3 tag), just filename.
                match[0] = HttpUtility.UrlEncode(match[0]);
                match[0] = Regex.Replace(match[0].Substring(12, match[0].Length - 15), "[\\.]|[\\+]", " ");
                match[0] = Regex.Replace(match[0], "Xvid|Ac3|www|org|avi|mp4|mkv|wmv|HDTV|X264|DIMENSION|\\-|\\((\\d+)\\)|%5(d|b)|Dual Audio|BRRip|x264|AC3|1080p|Lektor i Napisy PL|mvgroup|NF|DD5|WEBRip|NTb|\\-", "");

                filename = match[0];
                Debug.WriteLine(filename);
            }
        }

        /// <summary>
        /// Core method that sends POST request to IP and PORT defined
        /// </summary>
        /// <param name="wmcommand">Code defined by MCP controls.html code</param>
        public async void makeRequest(String wmcommand)
        {
            try
            {
                HttpClient client = new HttpClient();
                var body = String.Format("wm_command={0}", wmcommand);

                StringContent theContent = new StringContent(body, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded");
                HttpResponseMessage aResponse = await client.PostAsync(new Uri("http://" + this.ip + ":" + this.port + "/command.html"), theContent);
            }
            catch (Exception e)
            {
                showError(Error.FailedRequest);
            }
        }

        /// <summary>
        /// Shoes a messagebox with error description
        /// </summary>
        /// <param name="error">Error type of sealed values. Seek to Error class to find which is appropriate</param>
        public void showError(Error error)
        {
            MessageBox.Show(error.ToString());
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我正在开发另一个项目,该项目包含一个运行后台的计时器。令我惊讶的是,我了解了一个应用程序,当suspended时,即当锁定屏幕关闭或其他应用程序开始运行时,所有连接,网络请求或计时器都会停止,直到用户返回应用程序为止,如果没有编码,它将不会自动重试连接和请求。

如果我设置PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;会覆盖用户的设置并阻止锁定屏幕,那么这可能是一个问题,然后我必须手动处理所有计时器和请求被暂停 - (Source )。

最后,这个应用程序不是问题,HttpClient对象也不是。