我之前发过关于我的应用程序跳过框架的帖子,因为我可能没有正在进行后台活动并正确更新用户界面,这里有一个指向问题的链接: Doing background stuff on a different UI
我使用过AsyncTask,Handlers,Timers,Threads ......我仍然得到应用程序正在跳帧的相同错误。
以下是我的完整代码:
public class MainActivity extends Activity {
public static final String DEBUG_TAG = "MainActvity";
public int mInterval = 5000; // 10 seconds by default, can be changed here, it should be aligned
// with how many secs in takes to get latency packets
private NetworkInformation dsNetwork;
private TextView wifiTextView;
private TextView ipTextView;
private TextView macTextView;
private TextView ssidTextView;
private TextView linkSpeedTextView;
private TextView frequencyTextView;
private TextView signalLevelTextView;
private TextView dlBandwidthTextView;
private TextView upBandwidthTextView;
private TextView latencyTextView;
private Handler handler;
//private Runnable runnableCode;
//private Timer timerAsync;
//private TimerTask timerTaskAsync;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wifiTextView = (TextView)findViewById(R.id.wifi_textView);
ipTextView = (TextView)findViewById(R.id.ip_val_textView);
macTextView = (TextView)findViewById(R.id.mac_val_textView);
ssidTextView = (TextView)findViewById(R.id.ssid_val_textView);
linkSpeedTextView = (TextView)findViewById(R.id.linkSpeed_val_textView);
frequencyTextView = (TextView)findViewById(R.id.frequency_val_textView);
signalLevelTextView = (TextView)findViewById(R.id.signalLevel_val_textView);
dlBandwidthTextView = (TextView)findViewById(R.id.dlBandwidth_val_textView);
upBandwidthTextView = (TextView)findViewById(R.id.upBandwidth_val_textView);
latencyTextView = (TextView)findViewById(R.id.latency_val_textView);
handler = new Handler();
startRepeatingTask();
}
Runnable mStatusChecker = new Runnable() {
@Override
public void run() {
updateUI(dsNetwork); //this function can change value of mInterval.
handler.postDelayed(mStatusChecker, mInterval);
}
};
void startRepeatingTask() {
dsNetwork = new NetworkInformation(getApplicationContext());
mStatusChecker.run();
}
void stopRepeatingTask() {
handler.removeCallbacks(mStatusChecker);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private void updateUI(NetworkInformation dsNetwork){
// Handles updating the textviews in the UI
//Log.d(DEBUG_TAG, "updateUI(NetworkInformation)");
if (dsNetwork.isConnected()){
wifiTextView.setText(R.string.wifi_is_on);
wifiTextView.setTextColor(Color.GREEN);
ipTextView.setText(dsNetwork.getIpAddress());
macTextView.setText(dsNetwork.getMacAddress());
ssidTextView.setText(dsNetwork.getSsid());
linkSpeedTextView.setText(String.valueOf(dsNetwork.getLinkSpeed()) + " Mbps");
frequencyTextView.setText(String.valueOf(dsNetwork.getFrequency()) + " MHz");
signalLevelTextView.setText(String.valueOf(dsNetwork.getSignalLevel()) + "%");
dlBandwidthTextView.setText(String.valueOf(dsNetwork.getDlBandwidth()/1000) + " Mbps");
upBandwidthTextView.setText(String.valueOf(dsNetwork.getDlBandwidth()/1000) + " Mbps");
latencyTextView.setText(String.valueOf(dsNetwork.getLatency("10.10.0.62")) + " ms");
}
else {
wifiTextView.setText(R.string.wifi_is_off);
wifiTextView.setTextColor(Color.RED);
ipTextView.setText("N/A");
macTextView.setText("N/A");
ssidTextView.setText("N/A");
linkSpeedTextView.setText("N/A");
frequencyTextView.setText("N/A");
signalLevelTextView.setText("N/A");
dlBandwidthTextView.setText("N/A");
upBandwidthTextView.setText("N/A");
latencyTextView.setText("N/A");
}
}
}
以下是处理获取信息的网络类:
public class NetworkInformation {
public static int SIGNAL_LEVEL_LIMIT = 101;
public Context mContext;
public static String DEBUG_TAG = "NetworkInformation";
private boolean isConnected;
private String networkType; //Wifi, Mobile Data, Ethernet...
private String ssid;
private String ipAddress;
private String macAddress;
private int frequency; // in MHz
private int linkSpeed; // in Mbps
private int signalLevel; // Measured from 1 to SIGNAL_LEVEL_LIMIT
private int dlBandwidth; // downstream bandwidth in Kbps
private int upBandwidth; // upstream bandwidth in Kbps
public boolean isConnected() {
return isConnected;
}
public String getNetworkType() {
return networkType;
}
public String getSsid() {
return ssid;
}
public int getFrequency() {
return frequency;
}
public String getIpAddress() {
return ipAddress;
}
public String getMacAddress() {
return macAddress;
}
public int getLinkSpeed() {
return linkSpeed;
}
public int getSignalLevel() {
return signalLevel;
}
public int getDlBandwidth() {
return dlBandwidth;
}
public int getUpBandwidth() {
return upBandwidth;
}
// Constructor: gets application contex, sets whether or not there is connection, and sets the
// connection-related variables
public NetworkInformation(Context mContext) {
this.mContext = mContext;
setConnectionStatus();
setNetworkType();
if (this.networkType == "None") {
// TODO: handle the case when there's no connection
}
if (this.networkType == "Wifi") {
setWifiInfo();
}
if(this.networkType == "Mobile Data") {
//TODO: setMobileDataInfo()
}
}
/*
Returns the latency to a given server in mili-seconds by issuing a ping command.
system will issue 5 ICMP Echo Request packet each having size of 56 bytes
every second, and returns the avg latency of them.
Returns 0 when there is no connection
*/
public double getLatency(String ipAddress){
String pingCommand = "/system/bin/ping -c 4 " + ipAddress;
String inputLine = "";
double avgRtt = 0;
try {
// execute the command on the environment interface
Process process = Runtime.getRuntime().exec(pingCommand);
// gets the input stream to get the output of the executed command
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
inputLine = bufferedReader.readLine();
while ((inputLine != null)) {
if (inputLine.length() > 0 && inputLine.contains("avg")) { // when we get to the last line of executed ping command
break;
}
inputLine = bufferedReader.readLine();
}
}
catch (IOException e){
Log.v(DEBUG_TAG, "getLatency: EXCEPTION");
e.printStackTrace();
}
// Extracting the average round trip time from the inputLine string
String afterEqual = inputLine.substring(inputLine.indexOf("="), inputLine.length()).trim();
String afterFirstSlash = afterEqual.substring(afterEqual.indexOf('/') + 1, afterEqual.length()).trim();
String strAvgRtt = afterFirstSlash.substring(0, afterFirstSlash.indexOf('/'));
avgRtt = Double.valueOf(strAvgRtt);
return avgRtt;
}
/*
The following are private utility functions
*/
// Checks if the device is connected to the Internet, and sets the class variables
private void setConnectionStatus() {
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
// if there is internet connection, set the variabel
if ((activeNetwork != null) && (activeNetwork.isConnectedOrConnecting()))
this.isConnected = true;
else
this.isConnected = false;
}
// Returns the type of network: Internet, Mobile Data, WiMax...
private void setNetworkType() {
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
String networkType = "None";
switch (activeNetwork.getType()) {
case ConnectivityManager.TYPE_WIFI:
networkType = "Wifi";
break;
case ConnectivityManager.TYPE_MOBILE:
networkType = "Mobile Data";
break;
case ConnectivityManager.TYPE_ETHERNET:
networkType = "Ethernet";
break;
case ConnectivityManager.TYPE_WIMAX:
networkType = "WiMAX";
break;
case ConnectivityManager.TYPE_VPN:
networkType = "VPN";
break;
}
this.networkType = networkType;
}
// Gets the wifi information, and updates the class variables
private void setWifiInfo() {
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
Network[] network = cm.getAllNetworks();
NetworkCapabilities netCapab = cm.getNetworkCapabilities(network[0]);
WifiManager wifiManager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo != null) {
this.ssid = wifiInfo.getSSID();
this.ipAddress = Formatter.formatIpAddress(wifiInfo.getIpAddress());
this.macAddress = wifiInfo.getMacAddress();
this.linkSpeed = wifiInfo.getLinkSpeed();
this.frequency = wifiInfo.getFrequency();
this.dlBandwidth = netCapab.getLinkDownstreamBandwidthKbps();
this.upBandwidth = netCapab.getLinkUpstreamBandwidthKbps();
this.signalLevel = wifiManager.calculateSignalLevel(wifiManager.getConnectionInfo().getRssi(), SIGNAL_LEVEL_LIMIT);
}
}
}
当应用程序首先运行时,它运行正常,但它变得越来越慢,最后在10分钟后崩溃...... 我一直在logcat中得到这个错误,它不断出现: I / Choreographer:跳过183帧!应用程序可能在其主线程上做了太多工作。
哦,我以这种方式做了Handler:Repeat a task with a time delay? 而这样: Update TextView Every Second
但都没有效果。有人救了我...
答案 0 :(得分:1)
方法getLatency(...)
是一个长时间运行的操作(启动外部进程并执行一些I / O)。不应在更新UI的主线程中调用此类内容。编舞者试图保持60fps,因此3秒的被阻止的主线程可能导致180帧丢帧。
启动一些后台任务,获取所需的全部数据,然后在主线程中更新UI。