网速 ping"/>
网络监测 断网 网速 ping
监测网络的Activity
public class NetActivity extends Activity {private static final String URL_DOWNLOAD = ".tencent.wework.apk";public static final int MESSAGE_WHAT_REFUSH_CURRENT_SPEED = 1;//刷新当前网速public static final int MESSAGE_WHAT_REFUSH_AVE_SPEED = 2;//刷新平均网速public static final int MESSAGE_WHAT_REFUSH_RESET = 3;//重置private static final int DURATION_REFUSH_CURRENT_SPEED = 150;//过多久时间后刷新一次实时网速private static final int DURATION_REFUSH_AVE_SPEED = 300;//过多久时间后刷新一次平均网速private static final int DURATION_MAXCHECK = 5 * 1000;//整个测速过程允许的最大时间private TextView tv_type, tv_now_speed, tv_ave_speed;private DashboardView mDashboardView;private Button btn;private boolean flag = false;private Handler handler = new StaticUiHandler(this);private Disposable pingDisposable;private long lastTotalRxBytes = 0;private long lastTimeStamp = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_net);tv_type = findViewById(R.id.connection_type);tv_now_speed = findViewById(R.id.now_speed);tv_ave_speed = findViewById(R.id.ave_speed);btn = findViewById(R.id.start_btn);mDashboardView = findViewById(R.id.dashboard_view);btn.setOnClickListener(arg0 -> checkNetSpeed());checkNetSpeed();}@Overrideprotected void onDestroy() {super.onDestroy();flag = false;handler.removeCallbacksAndMessages(null);if (pingDisposable != null) {pingDisposable.dispose();}}/*** 监测网速*/private void checkNetSpeed() {flag = true;handler.postDelayed(this::reset, DURATION_MAXCHECK);checkNetType();btn.setText("正在ping百度ip...");btn.setEnabled(false);}/*** 监测网络类型*/private void checkNetType() {//先ping一下百度看能不能通pingDisposable = Observable.create((ObservableOnSubscribe<Boolean>) emitter -> {boolean isSuccess = PingUtils.pingIpAddress(PingUtils.BAIDU_IP, 2);emitter.onNext(isSuccess);}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(aBoolean -> {//通的话再检查是什么网,或者网络不可用btn.setText("正在检查网络...");if (aBoolean) {ConnectivityManager manager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);if (manager != null) {NetworkInfo networkInfo = manager.getActiveNetworkInfo();if (networkInfo != null) {tv_type.setText(networkInfo.getTypeName());//网络类型btn.postDelayed(() -> btn.setText("正在测试网速..."), 500);new DownloadThread().start();} else {tv_type.setText("网络不可用");Toast.makeText(NetActivity.this, "网络不可用", Toast.LENGTH_SHORT).show();reset();}} else {tv_type.setText("网络不可用");Toast.makeText(NetActivity.this, "网络不可用", Toast.LENGTH_SHORT).show();reset();}//不同的话说明没网} else {tv_type.setText("无网络");Toast.makeText(NetActivity.this, "无网络", Toast.LENGTH_SHORT).show();reset();}});}/*** 复原到初始状态*/private void reset() {if (flag) {flag = false;btn.setText("重新测试");btn.setEnabled(true);handler.removeCallbacksAndMessages(null);}}private void showCurrentNetSpeed() {long nowTimeStamp = System.currentTimeMillis();long totalRxBytes = TrafficStats.getTotalRxBytes();if (TrafficStats.getUidRxBytes(getApplicationInfo().uid) != TrafficStats.UNSUPPORTED&& totalRxBytes > lastTotalRxBytes && nowTimeStamp - lastTimeStamp > 0) {int speed = (int) ((totalRxBytes - lastTotalRxBytes) * 1000 / (nowTimeStamp - lastTimeStamp));//毫秒转换成秒lastTimeStamp = nowTimeStamp;lastTotalRxBytes = TrafficStats.getTotalRxBytes();tv_now_speed.setText(PingUtils.formatData(speed) + "/S");Log.i("bqt", "当前网速:" + PingUtils.formatData(speed) + "/S");mDashboardView.setRealTimeValue(speed * 1.0f / 1024 / 1024);}}//region Handlerstatic class StaticUiHandler extends Handler {private SoftReference<NetActivity> mSoftReference;StaticUiHandler(NetActivity activity) {mSoftReference = new SoftReference<>(activity);}@SuppressLint("SetTextI18n")@Overridepublic void handleMessage(Message msg) {NetActivity activity = mSoftReference.get();if (activity != null && msg != null) {switch (msg.what) {case MESSAGE_WHAT_REFUSH_CURRENT_SPEED:activity.showCurrentNetSpeed();break;case MESSAGE_WHAT_REFUSH_AVE_SPEED:activity.tv_ave_speed.setText(PingUtils.formatData((int) msg.obj) + "/S");break;case MESSAGE_WHAT_REFUSH_RESET:activity.reset();break;}}}}//endregion//region 子线程/*** 下载资源,下载过程中,根据已下载长度、总长度、时间计算实时网速*/class DownloadThread extends Thread {@Overridepublic void run() {try {URLConnection connection = new URL(URL_DOWNLOAD).openConnection();InputStream inputStream = connection.getInputStream();Log.i("bqt", "总长度:" + PingUtils.formatData(connection.getContentLength()));long startTime = System.currentTimeMillis();//开始时间long usedTime;//已经使用的时长long tempTime1 = 0, tempTime2 = 0;int aveSpeed;//当前网速和平均网速int temLen, downloadLen = 0;//已下载的长度byte[] buf = new byte[1024];while ((temLen = inputStream.read(buf)) != -1 && flag) {usedTime = System.currentTimeMillis() - startTime;//毫秒downloadLen += temLen;//刷新当前网速if (System.currentTimeMillis() - tempTime1 > DURATION_REFUSH_CURRENT_SPEED) {tempTime1 = System.currentTimeMillis();handler.sendMessage(Message.obtain(handler, MESSAGE_WHAT_REFUSH_CURRENT_SPEED, 0));}//刷新平均网速if (System.currentTimeMillis() - tempTime2 > DURATION_REFUSH_AVE_SPEED) {if (usedTime > 0) {//防止分母为零时报ArithmeticExceptiontempTime2 = System.currentTimeMillis();aveSpeed = (int) (downloadLen / usedTime) * 1000;//平均网速,单位秒handler.sendMessage(Message.obtain(handler, MESSAGE_WHAT_REFUSH_AVE_SPEED, aveSpeed));Log.i("bqt", "平均网速:" + PingUtils.formatData(aveSpeed) + "/S 已下载长度:" + PingUtils.formatData(downloadLen));}}}//重置handler.sendMessage(Message.obtain(handler, MESSAGE_WHAT_REFUSH_RESET));inputStream.close();} catch (Exception e) {e.printStackTrace();}}}//endregion
}
x1 209 1
public class NetActivity extends Activity {2
3
private static final String URL_DOWNLOAD = ".tencent.wework.apk";4
5
public static final int MESSAGE_WHAT_REFUSH_CURRENT_SPEED = 1;//刷新当前网速6
public static final int MESSAGE_WHAT_REFUSH_AVE_SPEED = 2;//刷新平均网速7
public static final int MESSAGE_WHAT_REFUSH_RESET = 3;//重置8
9
private static final int DURATION_REFUSH_CURRENT_SPEED = 150;//过多久时间后刷新一次实时网速10
private static final int DURATION_REFUSH_AVE_SPEED = 300;//过多久时间后刷新一次平均网速11
private static final int DURATION_MAXCHECK = 5 * 1000;//整个测速过程允许的最大时间12
13
private TextView tv_type, tv_now_speed, tv_ave_speed;14
private DashboardView mDashboardView;15
private Button btn;16
private boolean flag = false;17
private Handler handler = new StaticUiHandler(this);18
private Disposable pingDisposable;19
20
private long lastTotalRxBytes = 0;21
private long lastTimeStamp = 0;22
23
@Override24
protected void onCreate(Bundle savedInstanceState) {25
super.onCreate(savedInstanceState);26
setContentView(R.layout.activity_net);27
28
tv_type = findViewById(R.id.connection_type);29
tv_now_speed = findViewById(R.id.now_speed);30
tv_ave_speed = findViewById(R.id.ave_speed);31
btn = findViewById(R.id.start_btn);32
mDashboardView = findViewById(R.id.dashboard_view);33
34
btn.setOnClickListener(arg0 -> checkNetSpeed());35
checkNetSpeed();36
}37
38
@Override39
protected void onDestroy() {40
super.onDestroy();41
flag = false;42
handler.removeCallbacksAndMessages(null);43
if (pingDisposable != null) {44
pingDisposable.dispose();45
}46
}47
48
/**49
* 监测网速50
*/51
private void checkNetSpeed() {52
flag = true;53
handler.postDelayed(this::reset, DURATION_MAXCHECK);54
checkNetType();55
56
btn.setText("正在ping百度ip...");57
btn.setEnabled(false);58
}59
60
/**61
* 监测网络类型62
*/63
private void checkNetType() {64
//先ping一下百度看能不能通65
pingDisposable = Observable.create((ObservableOnSubscribe<Boolean>) emitter -> {66
boolean isSuccess = PingUtils.pingIpAddress(PingUtils.BAIDU_IP, 2);67
emitter.onNext(isSuccess);68
})69
.subscribeOn(Schedulers.io())70
.observeOn(AndroidSchedulers.mainThread())71
.subscribe(aBoolean -> {72
//通的话再检查是什么网,或者网络不可用73
btn.setText("正在检查网络...");74
if (aBoolean) {75
ConnectivityManager manager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);76
if (manager != null) {77
NetworkInfo networkInfo = manager.getActiveNetworkInfo();78
if (networkInfo != null) {79
tv_type.setText(networkInfo.getTypeName());//网络类型80
btn.postDelayed(() -> btn.setText("正在测试网速..."), 500);81
new DownloadThread().start();82
} else {83
tv_type.setText("网络不可用");84
Toast.makeText(NetActivity.this, "网络不可用", Toast.LENGTH_SHORT).show();85
reset();86
}87
} else {88
tv_type.setText("网络不可用");89
Toast.makeText(NetActivity.this, "网络不可用", Toast.LENGTH_SHORT).show();90
reset();91
}92
//不同的话说明没网93
} else {94
tv_type.setText("无网络");95
Toast.makeText(NetActivity.this, "无网络", Toast.LENGTH_SHORT).show();96
reset();97
}98
});99
}100
101
/**102
* 复原到初始状态103
*/104
private void reset() {105
if (flag) {106
flag = false;107
btn.setText("重新测试");108
btn.setEnabled(true);109
handler.removeCallbacksAndMessages(null);110
}111
}112
113
private void showCurrentNetSpeed() {114
long nowTimeStamp = System.currentTimeMillis();115
long totalRxBytes = TrafficStats.getTotalRxBytes();116
if (TrafficStats.getUidRxBytes(getApplicationInfo().uid) != TrafficStats.UNSUPPORTED117
&& totalRxBytes > lastTotalRxBytes && nowTimeStamp - lastTimeStamp > 0) {118
int speed = (int) ((totalRxBytes - lastTotalRxBytes) * 1000 / (nowTimeStamp - lastTimeStamp));//毫秒转换成秒119
lastTimeStamp = nowTimeStamp;120
lastTotalRxBytes = TrafficStats.getTotalRxBytes();121
122
tv_now_speed.setText(PingUtils.formatData(speed) + "/S");123
Log.i("bqt", "当前网速:" + PingUtils.formatData(speed) + "/S");124
125
mDashboardView.setRealTimeValue(speed * 1.0f / 1024 / 1024);126
}127
}128
129
//region Handler130
131
static class StaticUiHandler extends Handler {132
private SoftReference<NetActivity> mSoftReference;133
134
StaticUiHandler(NetActivity activity) {135
mSoftReference = new SoftReference<>(activity);136
}137
138
@SuppressLint("SetTextI18n")139
@Override140
public void handleMessage(Message msg) {141
NetActivity activity = mSoftReference.get();142
if (activity != null && msg != null) {143
switch (msg.what) {144
case MESSAGE_WHAT_REFUSH_CURRENT_SPEED:145
activity.showCurrentNetSpeed();146
break;147
case MESSAGE_WHAT_REFUSH_AVE_SPEED:148
activity.tv_ave_speed.setText(PingUtils.formatData((int) msg.obj) + "/S");149
break;150
case MESSAGE_WHAT_REFUSH_RESET:151
activity.reset();152
break;153
}154
}155
}156
}157
//endregion158
159
//region 子线程160
161
/**162
* 下载资源,下载过程中,根据已下载长度、总长度、时间计算实时网速163
*/164
class DownloadThread extends Thread {165
@Override166
public void run() {167
try {168
URLConnection connection = new URL(URL_DOWNLOAD).openConnection();169
InputStream inputStream = connection.getInputStream();170
Log.i("bqt", "总长度:" + PingUtils.formatData(connection.getContentLength()));171
172
long startTime = System.currentTimeMillis();//开始时间173
long usedTime;//已经使用的时长174
long tempTime1 = 0, tempTime2 = 0;175
176
int aveSpeed;//当前网速和平均网速177
int temLen, downloadLen = 0;//已下载的长度178
byte[] buf = new byte[1024];179
while ((temLen = inputStream.read(buf)) != -1 && flag) {180
usedTime = System.currentTimeMillis() - startTime;//毫秒181
downloadLen += temLen;182
183
//刷新当前网速184
if (System.currentTimeMillis() - tempTime1 > DURATION_REFUSH_CURRENT_SPEED) {185
tempTime1 = System.currentTimeMillis();186
handler.sendMessage(Message.obtain(handler, MESSAGE_WHAT_REFUSH_CURRENT_SPEED, 0));187
}188
189
//刷新平均网速190
if (System.currentTimeMillis() - tempTime2 > DURATION_REFUSH_AVE_SPEED) {191
if (usedTime > 0) {//防止分母为零时报ArithmeticException192
tempTime2 = System.currentTimeMillis();193
aveSpeed = (int) (downloadLen / usedTime) * 1000;//平均网速,单位秒194
handler.sendMessage(Message.obtain(handler, MESSAGE_WHAT_REFUSH_AVE_SPEED, aveSpeed));195
Log.i("bqt", "平均网速:" + PingUtils.formatData(aveSpeed) + "/S 已下载长度:" + PingUtils.formatData(downloadLen));196
}197
}198
}199
200
//重置201
handler.sendMessage(Message.obtain(handler, MESSAGE_WHAT_REFUSH_RESET));202
inputStream.close();203
} catch (Exception e) {204
e.printStackTrace();205
}206
}207
}208
//endregion209
}
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"android:background="#800F"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="#000"android:orientation="horizontal"android:paddingBottom="10dp"android:paddingTop="10dp"><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:singleLine="true"android:text="连接方式"android:textColor="#ffffff"/><TextViewandroid:id="@+id/connection_type"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:singleLine="true"android:textColor="#fff"tools:text="2M/S"/></LinearLayout><Viewandroid:layout_width="1dp"android:layout_height="match_parent"android:background="#dbdbdb"/><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="当前速度"android:textColor="#ffffff"/><TextViewandroid:id="@+id/now_speed"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:textColor="#fff"tools:text="2M/S"/></LinearLayout><Viewandroid:layout_width="1dp"android:layout_height="match_parent"android:background="#dbdbdb"/><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="平均速度"android:textColor="#ffffff"/><TextViewandroid:id="@+id/ave_speed"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:textColor="#fff"tools:text="2M/S"/></LinearLayout></LinearLayout><rx.test.bqt.rxjavademo.DashboardViewandroid:id="@+id/dashboard_view"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_marginTop="20dp"/><Buttonandroid:id="@+id/start_btn"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="开始测试"/>
</LinearLayout>
112 1 <?xml version="1.0" encoding="utf-8"?>2
<LinearLayout xmlns:android=""3
xmlns:tools=""4
android:layout_width="match_parent"5
android:layout_height="match_parent"6
android:background="#800F"7
android:orientation="vertical">8 9
<LinearLayout10
android:layout_width="match_parent"11
android:layout_height="wrap_content"12
android:background="#000"13
android:orientation="horizontal"14
android:paddingBottom="10dp"15
android:paddingTop="10dp">16 17
<LinearLayout18
android:layout_width="0dp"19
android:layout_height="wrap_content"20
android:layout_weight="1"21
android:gravity="center"22
android:orientation="vertical">23 24
<TextView25
android:layout_width="wrap_content"26
android:layout_height="wrap_content"27
android:singleLine="true"28
android:text="连接方式"29
android:textColor="#ffffff"/>30 31
<TextView32
android:id="@+id/connection_type"33
android:layout_width="wrap_content"34
android:layout_height="wrap_content"35
android:layout_marginTop="5dp"36
android:singleLine="true"37
android:textColor="#fff"38
tools:text="2M/S"/>39
</LinearLayout>40 41
<View42
android:layout_width="1dp"43
android:layout_height="match_parent"44
android:background="#dbdbdb"/>45 46 47
<LinearLayout48
android:layout_width="0dp"49
android:layout_height="wrap_content"50
android:layout_weight="1"51
android:gravity="center"52
android:orientation="vertical">53 54
<TextView55
android:layout_width="wrap_content"56
android:layout_height="wrap_content"57
android:text="当前速度"58
android:textColor="#ffffff"/>59 60
<TextView61
android:id="@+id/now_speed"62
android:layout_width="wrap_content"63
android:layout_height="wrap_content"64
android:layout_marginTop="5dp"65
android:textColor="#fff"66
tools:text="2M/S"/>67
</LinearLayout>68 69
<View70
android:layout_width="1dp"71
android:layout_height="match_parent"72
android:background="#dbdbdb"/>73 74
<LinearLayout75
android:layout_width="0dp"76
android:layout_height="wrap_content"77
android:layout_weight="1"78
android:gravity="center"79
android:orientation="vertical">80 81
<TextView82
android:layout_width="wrap_content"83
android:layout_height="wrap_content"84
android:text="平均速度"85
android:textColor="#ffffff"/>86 87
<TextView88
android:id="@+id/ave_speed"89
android:layout_width="wrap_content"90
android:layout_height="wrap_content"91
android:layout_marginTop="5dp"92
android:textColor="#fff"93
tools:text="2M/S"/>94
</LinearLayout>95
</LinearLayout>96 97 98
<rx.test.bqt.rxjavademo.DashboardView99
android:id="@+id/dashboard_view"100
android:layout_width="match_parent"101
android:layout_height="wrap_content"102
android:layout_gravity="center_horizontal"103
android:layout_marginTop="20dp"/>104 105
<Button106
android:id="@+id/start_btn"107
android:layout_width="match_parent"108
android:layout_height="wrap_content"109
android:layout_gravity="center_horizontal"110
android:text="开始测试"/>111
</LinearLayout>
一些工具方法
public class PingUtils {public static final String BAIDU_IP = "119.75.217.109";public static final String APPLE_IP = "";/*** 格式化文件大小** @param size 文件大小*/public static String formatData(long size) {DecimalFormat formater = new DecimalFormat("####.00");if (size < 1024) return size + "B";else if (size < Math.pow(1024, 2)) return formater.format(size * Math.pow(1024, -1)) + "KB";else if (size < Math.pow(1024, 3)) return formater.format(size * Math.pow(1024, -2)) + "MB";else if (size < Math.pow(1024, 4)) return formater.format(size * Math.pow(1024, -3)) + "GB";else return "";}/*** ping返回true表示ping通,false表示没有ping通* 所谓没有ping通是指数据包没有返回,也就是客户端没有及时收到ping的返回包因此返回false* 但是要是网络不可用则ping的时候也会返回true,因为ping指定有成功结束,只是ping的返回包是失败的数据包而不是成功的数据包* 所以准确的说返回true表示ping指定返回完成,false表示没收到ping的返回数据* 以上方法是阻塞的,android系统默认等待ping的超时是10s,可以自定义超时时间* 也不用担心方法一直被阻塞,如果ping超时就会自动返回,不必担心方法被阻塞导致无法运行下面的代码* 网上的一些ping的实现说方法会被一直阻塞,实际上是他们ping的命令没写好,以及使用io被阻塞了*/public static boolean ping(String host, int pingCount) {Process process = null;BufferedReader successReader = null;//String command = "/system/bin/ping -c " + pingCount + " -w 5 " + host;//-c 是指ping的次数,-w是指超时时间,单位为s。String command = "ping -c " + pingCount + " " + host;boolean isSuccess = false;try {Log.i("bqt", "【start ping,command:" + command + "】");process = Runtime.getRuntime().exec(command);if (process == null) {Log.i("bqt", "【ping fail:process is null.】");return false;}successReader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = successReader.readLine()) != null) {Log.i("bqt", line);}int status = process.waitFor();if (status == 0) {Log.i("bqt", "【exec cmd success】");isSuccess = true;} else {Log.i("bqt", "【exec cmd fail】");isSuccess = false;}Log.i("bqt", "【exec finished】");} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();} finally {Log.i("bqt", "【ping exit】");if (process != null) {process.destroy();}if (successReader != null) {try {successReader.close();} catch (IOException e) {e.printStackTrace();}}}return isSuccess;}/*** 简易版*/public static boolean pingIpAddress(String host, int pingCount) {try {String command = "ping -c " + pingCount + " -w 5 " + host;//-c 是指ping的次数,-w是指超时时间,单位为s。Log.i("bqt", "【start ping,command:" + command + "】");Process process = Runtime.getRuntime().exec(command);//其中参数-c 1是指ping的次数为1次,-w是指超时时间单位为s。boolean isSuccess = process != null && process.waitFor() == 0;//status 等于0的时候表示网络可用,status等于2时表示当前网络不可用Log.i("bqt", "【end ping,isSuccess:" + isSuccess + "】");return isSuccess;} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}return false;}
}
94 1 public class PingUtils {2
public static final String BAIDU_IP = "119.75.217.109";3
public static final String APPLE_IP = "";4
5
/**6
* 格式化文件大小7
*8
* @param size 文件大小9
*/10
public static String formatData(long size) {11
DecimalFormat formater = new DecimalFormat("####.00");12
if (size < 1024) return size + "B";13
else if (size < Math.pow(1024, 2)) return formater.format(size * Math.pow(1024, -1)) + "KB";14
else if (size < Math.pow(1024, 3)) return formater.format(size * Math.pow(1024, -2)) + "MB";15
else if (size < Math.pow(1024, 4)) return formater.format(size * Math.pow(1024, -3)) + "GB";16
else return "";17
}18
19
/**20
* ping返回true表示ping通,false表示没有ping通21
* 所谓没有ping通是指数据包没有返回,也就是客户端没有及时收到ping的返回包因此返回false22
* 但是要是网络不可用则ping的时候也会返回true,因为ping指定有成功结束,只是ping的返回包是失败的数据包而不是成功的数据包23
* 所以准确的说返回true表示ping指定返回完成,false表示没收到ping的返回数据24
* 以上方法是阻塞的,android系统默认等待ping的超时是10s,可以自定义超时时间25
* 也不用担心方法一直被阻塞,如果ping超时就会自动返回,不必担心方法被阻塞导致无法运行下面的代码26
* 网上的一些ping的实现说方法会被一直阻塞,实际上是他们ping的命令没写好,以及使用io被阻塞了27
*/28
public static boolean ping(String host, int pingCount) {29
Process process = null;30
BufferedReader successReader = null;31
//String command = "/system/bin/ping -c " + pingCount + " -w 5 " + host;//-c 是指ping的次数,-w是指超时时间,单位为s。32
String command = "ping -c " + pingCount + " " + host;33
boolean isSuccess = false;34
try {35
Log.i("bqt", "【start ping,command:" + command + "】");36
process = Runtime.getRuntime().exec(command);37
if (process == null) {38
Log.i("bqt", "【ping fail:process is null.】");39
return false;40
}41
successReader = new BufferedReader(new InputStreamReader(process.getInputStream()));42
String line;43
while ((line = successReader.readLine()) != null) {44
Log.i("bqt", line);45
}46
int status = process.waitFor();47
if (status == 0) {48
Log.i("bqt", "【exec cmd success】");49
isSuccess = true;50
} else {51
Log.i("bqt", "【exec cmd fail】");52
isSuccess = false;53
}54
Log.i("bqt", "【exec finished】");55
} catch (IOException e) {56
e.printStackTrace();57
} catch (InterruptedException e) {58
e.printStackTrace();59
} finally {60
Log.i("bqt", "【ping exit】");61
if (process != null) {62
process.destroy();63
}64
if (successReader != null) {65
try {66
successReader.close();67
} catch (IOException e) {68
e.printStackTrace();69
}70
}71
}72
return isSuccess;73
}74
75
/**76
* 简易版77
*/78
public static boolean pingIpAddress(String host, int pingCount) {79
try {80
String command = "ping -c " + pingCount + " -w 5 " + host;//-c 是指ping的次数,-w是指超时时间,单位为s。81
Log.i("bqt", "【start ping,command:" + command + "】");82
Process process = Runtime.getRuntime().exec(command);83
//其中参数-c 1是指ping的次数为1次,-w是指超时时间单位为s。84
boolean isSuccess = process != null && process.waitFor() == 0;//status 等于0的时候表示网络可用,status等于2时表示当前网络不可用85
Log.i("bqt", "【end ping,isSuccess:" + isSuccess + "】");86
return isSuccess;87
} catch (IOException e) {88
e.printStackTrace();89
} catch (InterruptedException e) {90
e.printStackTrace();91
}92
return false;93
}94
}
一个自定义View
//
public class DashboardView extends View {private static final long ANIMATION_DURATION = 130; //动画时长,注意最好不要在一个动画周期内设置多个动画private static final int M_START_ANGLE = 135; // 起始角度private static final int M_SWEEP_ANGLE = 270; // 绘制角度private static final float mMin = 0; // 最小值private static final float mMax = 5; // 最大值,对应5MB/Sprivate static final int M_SECTION = 10; // 值域(mMax-mMin)等分份数private static final int M_PORTION = 10; // 一个mSection等分份数private static final String M_HEADER_TEXT = "MB/S"; // 表头private static final int SWEEP_ANGLE_COLOR = 0x880000ff;//圆弧颜色private static final int REAL_TIME_VALUE_COLOR = 0xffff0000;//实时读数的颜色private static final boolean IS_SHOW_VALUE = true; // 是否显示实时读数private int mRadius; // 扇形半径private float realTimeValue = mMin; // 实时读数private int mStrokeWidth; // 画笔宽度private int mLength1; // 长刻度的相对圆弧的长度private int mLength2; // 刻度读数顶部的相对圆弧的长度private int mPLRadius; // 指针长半径private int mPSRadius; // 指针短半径private int mPadding;private float mCenterX, mCenterY; // 圆心坐标private Paint mPaint;private RectF mRectFArc;private Path mPath;private RectF mRectFInnerArc;private Rect mRectText;private String[] mTexts;public DashboardView(Context context) {this(context, null);}public DashboardView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DashboardView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mStrokeWidth = dp2px(1);mLength1 = dp2px(8) + mStrokeWidth;mLength2 = mLength1 + dp2px(2);mPSRadius = dp2px(10);mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setStrokeCap(Paint.Cap.ROUND);mRectFArc = new RectF();mPath = new Path();mRectFInnerArc = new RectF();mRectText = new Rect();mTexts = new String[M_SECTION + 1]; // 需要显示mSection + 1个刻度读数for (int i = 0; i < mTexts.length; i++) {float n = (mMax - mMin) / M_SECTION;mTexts[i] = String.valueOf(mMin + i * n);}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mPadding = Math.max(Math.max(getPaddingLeft(), getPaddingTop()),Math.max(getPaddingRight(), getPaddingBottom()));setPadding(mPadding, mPadding, mPadding, mPadding);int width = resolveSize(dp2px(200), widthMeasureSpec);mRadius = (width - mPadding * 2 - mStrokeWidth * 2) / 2;mPaint.setTextSize(sp2px(16));if (IS_SHOW_VALUE) { // 显示实时读数,View高度增加字体高度3倍mPaint.getTextBounds("0", 0, "0".length(), mRectText);} else {mPaint.getTextBounds("0", 0, 0, mRectText);}// 由半径+指针短半径+实时读数文字高度确定的高度int height1 = mRadius + mStrokeWidth * 2 + mPSRadius + mRectText.height() * 3;// 由起始角度确定的高度float[] point1 = getCoordinatePoint(mRadius, M_START_ANGLE);// 由结束角度确定的高度float[] point2 = getCoordinatePoint(mRadius, M_START_ANGLE + M_SWEEP_ANGLE);// 取最大值int max = (int) Math.max(height1, Math.max(point1[1] + mRadius + mStrokeWidth * 2, point2[1] + mRadius + mStrokeWidth * 2));setMeasuredDimension(width, max + getPaddingTop() + getPaddingBottom());mCenterX = mCenterY = getMeasuredWidth() / 2f;mRectFArc.set(getPaddingLeft() + mStrokeWidth,getPaddingTop() + mStrokeWidth,getMeasuredWidth() - getPaddingRight() - mStrokeWidth,getMeasuredWidth() - getPaddingBottom() - mStrokeWidth);mPaint.setTextSize(sp2px(10));mPaint.getTextBounds("0", 0, "0".length(), mRectText);mRectFInnerArc.set(getPaddingLeft() + mLength2 + mRectText.height(),getPaddingTop() + mLength2 + mRectText.height(),getMeasuredWidth() - getPaddingRight() - mLength2 - mRectText.height(),getMeasuredWidth() - getPaddingBottom() - mLength2 - mRectText.height());mPLRadius = mRadius - (mLength2 + mRectText.height() + dp2px(5));}private float tempRealTimeValue;private int dp2px(int dp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,Resources.getSystem().getDisplayMetrics());}private int sp2px(int sp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,Resources.getSystem().getDisplayMetrics());}public float[] getCoordinatePoint(int radius, float angle) {float[] point = new float[2];double arcAngle = Math.toRadians(angle); //将角度转换为弧度if (angle < 90) {point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius);point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius);} else if (angle == 90) {point[0] = mCenterX;point[1] = mCenterY + radius;} else if (angle > 90 && angle < 180) {arcAngle = Math.PI * (180 - angle) / 180.0;point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius);point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius);} else if (angle == 180) {point[0] = mCenterX - radius;point[1] = mCenterY;} else if (angle > 180 && angle < 270) {arcAngle = Math.PI * (angle - 180) / 180.0;point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius);point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius);} else if (angle == 270) {point[0] = mCenterX;point[1] = mCenterY - radius;} else {arcAngle = Math.PI * (360 - angle) / 180.0;point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius);point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius);}return point;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//画圆弧mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(mStrokeWidth);mPaint.setColor(SWEEP_ANGLE_COLOR);canvas.drawArc(mRectFArc, M_START_ANGLE, M_SWEEP_ANGLE, false, mPaint);//画长刻度。画好起始角度的一条刻度后通过canvas绕着原点旋转来画剩下的长刻度double cos = Math.cos(Math.toRadians(M_START_ANGLE - 180));double sin = Math.sin(Math.toRadians(M_START_ANGLE - 180));float x0 = (float) (mPadding + mStrokeWidth + mRadius * (1 - cos));float y0 = (float) (mPadding + mStrokeWidth + mRadius * (1 - sin));float x1 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1) * cos);float y1 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1) * sin);canvas.save();canvas.drawLine(x0, y0, x1, y1, mPaint);float angle = M_SWEEP_ANGLE * 1f / M_SECTION;for (int i = 0; i < M_SECTION; i++) {canvas.rotate(angle, mCenterX, mCenterY);canvas.drawLine(x0, y0, x1, y1, mPaint);}canvas.restore();//画短刻度。同样采用canvas的旋转原理canvas.save();mPaint.setStrokeWidth(1);float x2 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1 / 2f) * cos);float y2 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1 / 2f) * sin);canvas.drawLine(x0, y0, x2, y2, mPaint);angle = M_SWEEP_ANGLE * 1f / (M_SECTION * M_PORTION);for (int i = 1; i < M_SECTION * M_PORTION; i++) {canvas.rotate(angle, mCenterX, mCenterY);if (i % M_PORTION == 0) { // 避免与长刻度画重合continue;}canvas.drawLine(x0, y0, x2, y2, mPaint);}canvas.restore();//画长刻度读数。添加一个圆弧path,文字沿着path绘制mPaint.setTextSize(sp2px(10));mPaint.setTextAlign(Paint.Align.LEFT);mPaint.setStyle(Paint.Style.FILL);for (int i = 0; i < mTexts.length; i++) {mPaint.getTextBounds(mTexts[i], 0, mTexts[i].length(), mRectText);// 粗略把文字的宽度视为圆心角2*θ对应的弧长,利用弧长公式得到θ,下面用于修正角度float degree = (float) (180 * mRectText.width() / 2 /(Math.PI * (mRadius - mLength2 - mRectText.height())));mPath.reset();mPath.addArc(mRectFInnerArc,M_START_ANGLE + i * (M_SWEEP_ANGLE / M_SECTION) - degree, // 正起始角度减去θ使文字居中对准长刻度M_SWEEP_ANGLE);canvas.drawTextOnPath(mTexts[i], mPath, 0, 0, mPaint);}//画表头。没有表头就不画if (!TextUtils.isEmpty(M_HEADER_TEXT)) {mPaint.setTextSize(sp2px(14));mPaint.setTextAlign(Paint.Align.CENTER);mPaint.getTextBounds(M_HEADER_TEXT, 0, M_HEADER_TEXT.length(), mRectText);canvas.drawText(M_HEADER_TEXT, mCenterX, mCenterY / 2f + mRectText.height(), mPaint);}//画指针float degree = M_START_ANGLE + M_SWEEP_ANGLE * (realTimeValue - mMin) / (mMax - mMin); // 指针与水平线夹角int d = dp2px(5); // 指针由两个等腰三角形构成,d为共底边长的一半mPath.reset();float[] p1 = getCoordinatePoint(d, degree - 90);mPath.moveTo(p1[0], p1[1]);float[] p2 = getCoordinatePoint(mPLRadius, degree);mPath.lineTo(p2[0], p2[1]);float[] p3 = getCoordinatePoint(d, degree + 90);mPath.lineTo(p3[0], p3[1]);float[] p4 = getCoordinatePoint(mPSRadius, degree - 180);mPath.lineTo(p4[0], p4[1]);mPath.close();canvas.drawPath(mPath, mPaint);//画指针围绕的镂空圆心mPaint.setColor(Color.WHITE);canvas.drawCircle(mCenterX, mCenterY, dp2px(2), mPaint);//画实时度数值if (IS_SHOW_VALUE) {mPaint.setTextSize(sp2px(18));mPaint.setTextAlign(Paint.Align.CENTER);mPaint.setColor(REAL_TIME_VALUE_COLOR);String value = String.format(Locale.getDefault(), "%.2f", realTimeValue) /*+ " MB/S"*/;mPaint.getTextBounds(value, 0, value.length(), mRectText);canvas.drawText(value, mCenterX, mCenterY + mPSRadius + mRectText.height() * 2, mPaint);}}public float getRealTimeValue() {return realTimeValue;}public void setRealTimeValue(final float value) {if (this.realTimeValue == value || value < mMin || value > mMax) {return;}this.tempRealTimeValue = this.realTimeValue;Animation anim = new Animation() {@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {//开始动画以后applyTransformation函数会自动调用,这里的interpolatedTime是 0-1 区间的变量,反映动画的进度super.applyTransformation(interpolatedTime, t);realTimeValue = tempRealTimeValue + interpolatedTime * (value - tempRealTimeValue);Log.i("bqt", "interpolatedTime=" + interpolatedTime + " realTimeValue=" + realTimeValue);postInvalidate();}};anim.setDuration(ANIMATION_DURATION);this.startAnimation(anim);//不知为什么不能用下面这种动画,感觉应该也是可以的/*ObjectAnimator anim = ObjectAnimator.ofFloat(this, "realTimeValue", value).setDuration(ANIMATION_DURATION);anim.addUpdateListener(animation -> {realTimeValue = (Float) animation.getAnimatedValue();Log.i("bqt", "realTimeValue=" + realTimeValue);postInvalidate();});anim.start();*/}
}
289 1 //2
public class DashboardView extends View {3
4
private static final long ANIMATION_DURATION = 130; //动画时长,注意最好不要在一个动画周期内设置多个动画5
private static final int M_START_ANGLE = 135; // 起始角度6
private static final int M_SWEEP_ANGLE = 270; // 绘制角度7
private static final float mMin = 0; // 最小值8
private static final float mMax = 5; // 最大值,对应5MB/S9
private static final int M_SECTION = 10; // 值域(mMax-mMin)等分份数10
private static final int M_PORTION = 10; // 一个mSection等分份数11
private static final String M_HEADER_TEXT = "MB/S"; // 表头12
private static final int SWEEP_ANGLE_COLOR = 0x880000ff;//圆弧颜色13
private static final int REAL_TIME_VALUE_COLOR = 0xffff0000;//实时读数的颜色14
private static final boolean IS_SHOW_VALUE = true; // 是否显示实时读数15
private int mRadius; // 扇形半径16
private float realTimeValue = mMin; // 实时读数17
private int mStrokeWidth; // 画笔宽度18
private int mLength1; // 长刻度的相对圆弧的长度19
private int mLength2; // 刻度读数顶部的相对圆弧的长度20
private int mPLRadius; // 指针长半径21
private int mPSRadius; // 指针短半径22
23
private int mPadding;24
private float mCenterX, mCenterY; // 圆心坐标25
private Paint mPaint;26
private RectF mRectFArc;27
private Path mPath;28
private RectF mRectFInnerArc;29
private Rect mRectText;30
private String[] mTexts;31
32
public DashboardView(Context context) {33
this(context, null);34
}35
36
public DashboardView(Context context, AttributeSet attrs) {37
this(context, attrs, 0);38
}39
40
public DashboardView(Context context, AttributeSet attrs, int defStyleAttr) {41
super(context, attrs, defStyleAttr);42
43
init();44
}45
46
private void init() {47
mStrokeWidth = dp2px(1);48
mLength1 = dp2px(8) + mStrokeWidth;49
mLength2 = mLength1 + dp2px(2);50
mPSRadius = dp2px(10);51
52
mPaint = new Paint();53
mPaint.setAntiAlias(true);54
mPaint.setStrokeCap(Paint.Cap.ROUND);55
56
mRectFArc = new RectF();57
mPath = new Path();58
mRectFInnerArc = new RectF();59
mRectText = new Rect();60
61
mTexts = new String[M_SECTION + 1]; // 需要显示mSection + 1个刻度读数62
for (int i = 0; i < mTexts.length; i++) {63
float n = (mMax - mMin) / M_SECTION;64
mTexts[i] = String.valueOf(mMin + i * n);65
}66
}67
68
@Override69
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {70
super.onMeasure(widthMeasureSpec, heightMeasureSpec);71
72
mPadding = Math.max(73
Math.max(getPaddingLeft(), getPaddingTop()),74
Math.max(getPaddingRight(), getPaddingBottom())75
);76
setPadding(mPadding, mPadding, mPadding, mPadding);77
78
int width = resolveSize(dp2px(200), widthMeasureSpec);79
mRadius = (width - mPadding * 2 - mStrokeWidth * 2) / 2;80
81
mPaint.setTextSize(sp2px(16));82
if (IS_SHOW_VALUE) { // 显示实时读数,View高度增加字体高度3倍83
mPaint.getTextBounds("0", 0, "0".length(), mRectText);84
} else {85
mPaint.getTextBounds("0", 0, 0, mRectText);86
}87
// 由半径+指针短半径+实时读数文字高度确定的高度88
int height1 = mRadius + mStrokeWidth * 2 + mPSRadius + mRectText.height() * 3;89
// 由起始角度确定的高度90
float[] point1 = getCoordinatePoint(mRadius, M_START_ANGLE);91
// 由结束角度确定的高度92
float[] point2 = getCoordinatePoint(mRadius, M_START_ANGLE + M_SWEEP_ANGLE);93
// 取最大值94
int max = (int) Math.max(height1, Math.max(point1[1] + mRadius + mStrokeWidth * 2, point2[1] + mRadius + mStrokeWidth * 2));95
setMeasuredDimension(width, max + getPaddingTop() + getPaddingBottom());96
97
mCenterX = mCenterY = getMeasuredWidth() / 2f;98
mRectFArc.set(getPaddingLeft() + mStrokeWidth,99
getPaddingTop() + mStrokeWidth,100
getMeasuredWidth() - getPaddingRight() - mStrokeWidth,101
getMeasuredWidth() - getPaddingBottom() - mStrokeWidth);102
103
mPaint.setTextSize(sp2px(10));104
mPaint.getTextBounds("0", 0, "0".length(), mRectText);105
mRectFInnerArc.set(getPaddingLeft() + mLength2 + mRectText.height(),106
getPaddingTop() + mLength2 + mRectText.height(),107
getMeasuredWidth() - getPaddingRight() - mLength2 - mRectText.height(),108
getMeasuredWidth() - getPaddingBottom() - mLength2 - mRectText.height());109
110
mPLRadius = mRadius - (mLength2 + mRectText.height() + dp2px(5));111
}112
113
private float tempRealTimeValue;114
115
private int dp2px(int dp) {116
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,117
Resources.getSystem().getDisplayMetrics());118
}119
120
private int sp2px(int sp) {121
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,122
Resources.getSystem().getDisplayMetrics());123
}124
125
public float[] getCoordinatePoint(int radius, float angle) {126
float[] point = new float[2];127
128
double arcAngle = Math.toRadians(angle); //将角度转换为弧度129
if (angle < 90) {130
point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius);131
point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius);132
} else if (angle == 90) {133
point[0] = mCenterX;134
point[1] = mCenterY + radius;135
} else if (angle > 90 && angle < 180) {136
arcAngle = Math.PI * (180 - angle) / 180.0;137
point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius);138
point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius);139
} else if (angle == 180) {140
point[0] = mCenterX - radius;141
point[1] = mCenterY;142
} else if (angle > 180 && angle < 270) {143
arcAngle = Math.PI * (angle - 180) / 180.0;144
point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius);145
point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius);146
} else if (angle == 270) {147
point[0] = mCenterX;148
point[1] = mCenterY - radius;149
} else {150
arcAngle = Math.PI * (360 - angle) / 180.0;151
point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius);152
point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius);153
}154
155
return point;156
}157
158
@Override159
protected void onDraw(Canvas canvas) {160
super.onDraw(canvas);161
162
//画圆弧163
mPaint.setStyle(Paint.Style.STROKE);164
mPaint.setStrokeWidth(mStrokeWidth);165
mPaint.setColor(SWEEP_ANGLE_COLOR);166
canvas.drawArc(mRectFArc, M_START_ANGLE, M_SWEEP_ANGLE, false, mPaint);167
168
//画长刻度。画好起始角度的一条刻度后通过canvas绕着原点旋转来画剩下的长刻度169
double cos = Math.cos(Math.toRadians(M_START_ANGLE - 180));170
double sin = Math.sin(Math.toRadians(M_START_ANGLE - 180));171
float x0 = (float) (mPadding + mStrokeWidth + mRadius * (1 - cos));172
float y0 = (float) (mPadding + mStrokeWidth + mRadius * (1 - sin));173
float x1 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1) * cos);174
float y1 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1) * sin);175
176
canvas.save();177
canvas.drawLine(x0, y0, x1, y1, mPaint);178
float angle = M_SWEEP_ANGLE * 1f / M_SECTION;179
for (int i = 0; i < M_SECTION; i++) {180
canvas.rotate(angle, mCenterX, mCenterY);181
canvas.drawLine(x0, y0, x1, y1, mPaint);182
}183
canvas.restore();184
185
//画短刻度。同样采用canvas的旋转原理186
canvas.save();187
mPaint.setStrokeWidth(1);188
float x2 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1 / 2f) * cos);189
float y2 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1 / 2f) * sin);190
canvas.drawLine(x0, y0, x2, y2, mPaint);191
angle = M_SWEEP_ANGLE * 1f / (M_SECTION * M_PORTION);192
for (int i = 1; i < M_SECTION * M_PORTION; i++) {193
canvas.rotate(angle, mCenterX, mCenterY);194
if (i % M_PORTION == 0) { // 避免与长刻度画重合195
continue;196
}197
canvas.drawLine(x0, y0, x2, y2, mPaint);198
}199
canvas.restore();200
201
//画长刻度读数。添加一个圆弧path,文字沿着path绘制202
mPaint.setTextSize(sp2px(10));203
mPaint.setTextAlign(Paint.Align.LEFT);204
mPaint.setStyle(Paint.Style.FILL);205
for (int i = 0; i < mTexts.length; i++) {206
mPaint.getTextBounds(mTexts[i], 0, mTexts[i].length(), mRectText);207
// 粗略把文字的宽度视为圆心角2*θ对应的弧长,利用弧长公式得到θ,下面用于修正角度208
float degree = (float) (180 * mRectText.width() / 2 /209
(Math.PI * (mRadius - mLength2 - mRectText.height())));210
211
mPath.reset();212
mPath.addArc(mRectFInnerArc,213
M_START_ANGLE + i * (M_SWEEP_ANGLE / M_SECTION) - degree, // 正起始角度减去θ使文字居中对准长刻度214
M_SWEEP_ANGLE);215
canvas.drawTextOnPath(mTexts[i], mPath, 0, 0, mPaint);216
}217
218
//画表头。没有表头就不画219
if (!TextUtils.isEmpty(M_HEADER_TEXT)) {220
mPaint.setTextSize(sp2px(14));221
mPaint.setTextAlign(Paint.Align.CENTER);222
mPaint.getTextBounds(M_HEADER_TEXT, 0, M_HEADER_TEXT.length(), mRectText);223
canvas.drawText(M_HEADER_TEXT, mCenterX, mCenterY / 2f + mRectText.height(), mPaint);224
}225
226
//画指针227
float degree = M_START_ANGLE + M_SWEEP_ANGLE * (realTimeValue - mMin) / (mMax - mMin); // 指针与水平线夹角228
int d = dp2px(5); // 指针由两个等腰三角形构成,d为共底边长的一半229
mPath.reset();230
float[] p1 = getCoordinatePoint(d, degree - 90);231
mPath.moveTo(p1[0], p1[1]);232
float[] p2 = getCoordinatePoint(mPLRadius, degree);233
mPath.lineTo(p2[0], p2[1]);234
float[] p3 = getCoordinatePoint(d, degree + 90);235
mPath.lineTo(p3[0], p3[1]);236
float[] p4 = getCoordinatePoint(mPSRadius, degree - 180);237
mPath.lineTo(p4[0], p4[1]);238
mPath.close();239
canvas.drawPath(mPath, mPaint);240
241
//画指针围绕的镂空圆心242
mPaint.setColor(Color.WHITE);243
canvas.drawCircle(mCenterX, mCenterY, dp2px(2), mPaint);244
245
//画实时度数值246
if (IS_SHOW_VALUE) {247
mPaint.setTextSize(sp2px(18));248
mPaint.setTextAlign(Paint.Align.CENTER);249
mPaint.setColor(REAL_TIME_VALUE_COLOR);250
String value = String.format(Locale.getDefault(), "%.2f", realTimeValue) /*+ " MB/S"*/;251
mPaint.getTextBounds(value, 0, value.length(), mRectText);252
canvas.drawText(value, mCenterX, mCenterY + mPSRadius + mRectText.height() * 2, mPaint);253
}254
}255
256
public float getRealTimeValue() {257
return realTimeValue;258
}259
260
public void setRealTimeValue(final float value) {261
if (this.realTimeValue == value || value < mMin || value > mMax) {262
return;263
}264
this.tempRealTimeValue = this.realTimeValue;265
266
Animation anim = new Animation() {267
@Override268
protected void applyTransformation(float interpolatedTime, Transformation t) {269
//开始动画以后applyTransformation函数会自动调用,这里的interpolatedTime是 0-1 区间的变量,反映动画的进度270
super.applyTransformation(interpolatedTime, t);271
realTimeValue = tempRealTimeValue + interpolatedTime * (value - tempRealTimeValue);272
Log.i("bqt", "interpolatedTime=" + interpolatedTime + " realTimeValue=" + realTimeValue);273
postInvalidate();274
}275
};276
anim.setDuration(ANIMATION_DURATION);277
this.startAnimation(anim);278
279
//不知为什么不能用下面这种动画,感觉应该也是可以的280
/*ObjectAnimator anim = ObjectAnimator.ofFloat(this, "realTimeValue", value)281
.setDuration(ANIMATION_DURATION);282
anim.addUpdateListener(animation -> {283
realTimeValue = (Float) animation.getAnimatedValue();284
Log.i("bqt", "realTimeValue=" + realTimeValue);285
postInvalidate();286
});287
anim.start();*/288
}289
}2018-4-8
来自为知笔记(Wiz)
更多推荐
网络监测 断网 网速 ping
发布评论