Windows Phone应用程序消耗过多电池.使用HttpClient
本文关键字:使用 HttpClient Phone 应用程序 Windows | 更新日期: 2023-09-27 18:05:14
我正在编写一个应用程序,允许用户控制媒体经典播放器(MPC)播放,如暂停/播放,音量上升/下降,同步字幕等。MPC有一个可以激活的Web界面,使这种交互更容易。但有时当我运行和使用应用程序时,我的电池耗尽的速度比平时快。
我很确定导致电池过度消耗的一个关键功能是定时器。代码在此描述下面,但为了简短起见,几秒钟后,它会向Web界面重复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());
}
}
}
我正在做另一个项目,它包含一个运行后台的计时器。令我惊讶的是,我了解到一个应用程序,当suspended
,也就是说,当锁屏下降或其他应用程序开始运行时,所有的连接,网络中断或计时器停止,直到用户回到应用程序,它不会自动重试连接和请求,如果没有编码这样做。
这可能是一个问题,如果我设置了PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
,这将覆盖用户的设置和防止锁屏,然后我将不得不手动处理所有定时器和请求保持-(来源)。
最后,这个应用程序不是问题,HttpClient
对象也不是。