├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── compiler.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── _config.yml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ ├── 1.3.apk │ ├── app-release.jobf │ ├── output.json │ └── 多线程下载设计.JPG ├── res │ └── fonts │ │ ├── 全新硬笔行书简.ttf │ │ └── 方正硬笔行书简体.ttf └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ └── song │ │ └── HttpDownload │ │ ├── Constants.java │ │ ├── Download.java │ │ ├── FontDownload.java │ │ ├── MainActivity.java │ │ ├── Net │ │ ├── NetSpeed.java │ │ └── NetSpeedTimer.java │ │ ├── Switch.java │ │ ├── ThreadNum.java │ │ └── Util │ │ └── HttpUtil.java │ └── res │ ├── drawable │ ├── ic_launcher_foreground.xml │ └── textview_border.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values │ ├── colors.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── network_security_config.xml ├── bubbleseekbar ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── xw │ │ └── repo │ │ ├── BubbleSeekBar.java │ │ └── BubbleUtils.java │ └── res │ └── values │ ├── attr.xml │ └── colors.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── index.md └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HttpDownload 2 | 测网速 3 | ====== 4 | 一个刷流量,测网速小工具 5 | ----------------------- 6 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.2" 6 | 7 | defaultConfig { 8 | applicationId "song.HttpDownload" 9 | minSdkVersion 21 10 | targetSdkVersion 29 11 | versionCode 5 12 | versionName "1.3" 13 | 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled true 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: 'libs', include: ['*.jar']) 28 | 29 | implementation 'androidx.appcompat:appcompat:1.1.0' 30 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 31 | testImplementation 'junit:junit:4.12' 32 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 33 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 34 | 35 | //导入seekbar 包 36 | implementation 'com.xw.repo:bubbleseekbar:3.20-lite' 37 | //fastJson 38 | implementation('com.alibaba:fastjson:1.2.71') 39 | //SwipeDelMenuLayout(侧滑菜单) 40 | implementation 'com.github.mcxtzhang:SwipeDelMenuLayout:V1.3.0' 41 | //OKHttp 42 | implementation 'com.squareup.okhttp3:okhttp:3.4.1' 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/release/1.3.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyqs/HttpDownload/90cc032ceae47288129bfde0694d6141144bbe70/app/release/1.3.apk -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "outputType": { 4 | "type": "APK" 5 | }, 6 | "apkData": { 7 | "type": "MAIN", 8 | "splits": [], 9 | "versionCode": 5, 10 | "versionName": "1.3", 11 | "enabled": true, 12 | "outputFile": "app-release.apk", 13 | "fullName": "release", 14 | "baseName": "release", 15 | "dirName": "" 16 | }, 17 | "path": "app-release.apk", 18 | "properties": {} 19 | } 20 | ] -------------------------------------------------------------------------------- /app/release/多线程下载设计.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyqs/HttpDownload/90cc032ceae47288129bfde0694d6141144bbe70/app/release/多线程下载设计.JPG -------------------------------------------------------------------------------- /app/res/fonts/全新硬笔行书简.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyqs/HttpDownload/90cc032ceae47288129bfde0694d6141144bbe70/app/res/fonts/全新硬笔行书简.ttf -------------------------------------------------------------------------------- /app/res/fonts/方正硬笔行书简体.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyqs/HttpDownload/90cc032ceae47288129bfde0694d6141144bbe70/app/res/fonts/方正硬笔行书简体.ttf -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyqs/HttpDownload/90cc032ceae47288129bfde0694d6141144bbe70/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/song/HttpDownload/Constants.java: -------------------------------------------------------------------------------- 1 | package song.HttpDownload; 2 | 3 | public class Constants { 4 | public static String font_00 = "全新硬笔行书简.ttf"; 5 | public static String font_00_url = "http://js.xiazaicc.com/down3/qxybxsj_downcc.com.zip"; 6 | public static String font_01 = "方正硬笔行书简体.ttf"; 7 | public static String font_01_url = "http://b.xiazaicc.com/down3/fzybxsj_downcc.com.zip"; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/song/HttpDownload/Download.java: -------------------------------------------------------------------------------- 1 | package song.HttpDownload; 2 | import android.os.Message; 3 | import android.util.Log; 4 | import java.io.InputStream; 5 | import java.net.HttpURLConnection; 6 | import java.net.URL; 7 | import static song.HttpDownload.MainActivity.mHandler; 8 | import static song.HttpDownload.MainActivity.mUrl; 9 | 10 | //工具类,单例模式-恶汉式 11 | public class Download implements Runnable{ 12 | 13 | private static final Download INSTANCE = new Download(); 14 | @Override 15 | public void run() { 16 | try 17 | { 18 | Log.d("线程"+Thread.currentThread().getName(),"开始!"); 19 | URL url = new URL(mUrl); 20 | //打开链接 21 | HttpURLConnection coon = (HttpURLConnection) url.openConnection(); 22 | //设置超时:2s 23 | coon.setConnectTimeout(2000); 24 | //获取输入流 25 | InputStream in = coon.getInputStream(); 26 | //获得长度 27 | Log.d("长度", String.valueOf(coon.getContentLength())); 28 | //创建字节流 29 | byte[] bs = new byte[1024]; 30 | //遍历数据 31 | while ((in.read(bs)) != -1){ 32 | //一旦Switch对象为false,终止线程 33 | if(!Switch.getInstance().getStatu()){ 34 | //当关闭按钮时,中断当前线程。 35 | in.close();//释放服务器资源 36 | Thread.currentThread().interrupt(); 37 | } 38 | } 39 | in.close(); 40 | } catch (Exception e) { 41 | //设置开关状态 42 | Switch.getInstance().setStatu(false); 43 | Message msg = new Message(); 44 | msg.what=100; 45 | if(e instanceof java.net.UnknownHostException){ 46 | msg.obj = "未知主机异常:java.net.UnknownHostException"; 47 | }else if(e instanceof java.net.ConnectException){ 48 | msg.obj = "网络连接异常:java.net.ConnectException"; 49 | }else if(e instanceof java.net.SocketTimeoutException){ 50 | msg.obj = "网络连接超时(2s):java.net.SocketTimeoutException"; 51 | }else if(e instanceof java.io.IOException){ 52 | msg.obj = "已停止测试!"; 53 | }else{ 54 | msg.obj = e.toString(); 55 | } 56 | // e.printStackTrace(); 57 | mHandler.sendMessage(msg); 58 | }finally { 59 | //正常/异常都要执行的代码 60 | //线程结束,num-- 61 | MainActivity.mNetSpeedTimer.stopSpeedTimer();//关闭网速 62 | ThreadNum.getInstance().numLess(); 63 | Log.d("线程"+Thread.currentThread().getName(),"结束!"); 64 | } 65 | } 66 | //私有化构造器 67 | private Download(){}; 68 | //暴露获取对象的方法 69 | public static Download getInstance(){ 70 | return INSTANCE; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/song/HttpDownload/FontDownload.java: -------------------------------------------------------------------------------- 1 | package song.HttpDownload; 2 | 3 | import android.os.Build; 4 | import android.os.Message; 5 | import android.util.Log; 6 | 7 | import androidx.annotation.RequiresApi; 8 | 9 | import java.io.File; 10 | import java.io.FileOutputStream; 11 | import java.io.OutputStream; 12 | import java.net.URL; 13 | import java.net.URLConnection; 14 | import java.nio.charset.Charset; 15 | import java.text.DecimalFormat; 16 | import java.util.zip.ZipEntry; 17 | import java.util.zip.ZipInputStream; 18 | 19 | public class FontDownload { 20 | 21 | //@RequiresApi(api = Build.VERSION_CODES.N) :只有达到指定api级别,该方法才会被执行 22 | @RequiresApi(api = Build.VERSION_CODES.N) 23 | public static void download(int i){ 24 | String str = ""; 25 | String text = ""; 26 | switch (i){ 27 | case 0: str = Constants.font_00_url; 28 | text = Constants.font_00; 29 | break; 30 | case 1: str = Constants.font_01_url; 31 | text = Constants.font_01; 32 | break; 33 | default: 34 | Log.d("FontDownload", "选项越界!");break; 35 | } 36 | 37 | try { 38 | URL url = new URL(str);// url 39 | URLConnection coon = url.openConnection(); 40 | 41 | Log.d("FontDownload","文件MIME类型:"+coon.getContentType()); 42 | Log.d("FontDownload","文件长度:"+coon.getContentLength()); 43 | 44 | // Zip流,注意解码 45 | ZipInputStream zip = new ZipInputStream(url.openStream(),Charset.forName("GBK")); 46 | ZipEntry zipEntry = null;//键值对 47 | //迭代zip中的条目 48 | while ((zipEntry = zip.getNextEntry()) != null) { 49 | //如果当前文件是AndroidManifest.xml,打印出来 50 | if (text.equals(zipEntry.getName())) { 51 | Log.d("FontDownload","进入if,写出文件..."); 52 | //文件输出流 53 | File dir = new File(MainActivity.mFiles,"fonts"); 54 | if (!dir.exists()) { 55 | dir.mkdir(); 56 | } 57 | File file = new File(dir,zipEntry.getName()); 58 | if (!file.exists()){ 59 | file.createNewFile(); 60 | } 61 | OutputStream out = new FileOutputStream(file); 62 | 63 | //读取内容 64 | byte[] buffer = new byte[(int)zipEntry.getSize()]; 65 | int len = 0; 66 | 67 | /** zipInputStream中的read()方法说明: 68 | * 参数1:缓冲流 69 | * 参数2:开始读取目标阵列时的偏移值 70 | * 参数3:读取的最大字节数 即:缓冲流大小 71 | * */ 72 | //解码正常,编码错误 73 | while((len = zip.read(buffer,0,buffer.length)) != -1) { 74 | out.write(buffer,0,len); 75 | } 76 | out.close(); 77 | } 78 | Log.d("FontDownload",zipEntry.getName()); 79 | double d = (double)0; 80 | DecimalFormat df = new DecimalFormat("0.00"); //控制小数显示位数 81 | String unit = ""; 82 | if(zipEntry.getSize() != -1 && zipEntry.getSize()>1024) { 83 | d = (double)zipEntry.getSize()/1024; 84 | unit = "KB"; 85 | if(d>1024) { 86 | d = (double)d/1024; 87 | unit = "MB"; 88 | } 89 | } 90 | Log.d("FontDownload","文件大小:"+df.format(d)+unit); 91 | Log.d("FontDownload","-----------------------"); 92 | //关闭当前zipEntry 93 | zip.closeEntry(); 94 | } 95 | //关闭此输入流并释放与流相关联的任何系统资源 96 | zip.close(); 97 | //告诉主线程字体下载完成 98 | Message msg = new Message(); 99 | msg.what = 200; 100 | MainActivity.mHandler.sendMessage(msg); 101 | } catch (Exception e) { 102 | e.printStackTrace(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/song/HttpDownload/MainActivity.java: -------------------------------------------------------------------------------- 1 | package song.HttpDownload; 2 | 3 | import androidx.annotation.RequiresApi; 4 | import androidx.appcompat.app.AlertDialog; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | 7 | import android.content.DialogInterface; 8 | import android.content.Intent; 9 | import android.content.SharedPreferences; 10 | import android.content.pm.PackageInfo; 11 | import android.content.pm.PackageManager; 12 | import android.graphics.Color; 13 | import android.graphics.Typeface; 14 | import android.net.Uri; 15 | import android.os.Build; 16 | import android.os.Bundle; 17 | import android.os.Handler; 18 | import android.os.Message; 19 | import android.util.Log; 20 | import android.view.KeyEvent; 21 | import android.view.View; 22 | import android.widget.Button; 23 | import android.widget.TextView; 24 | import android.widget.Toast; 25 | 26 | import com.xw.repo.BubbleSeekBar; 27 | 28 | import org.json.JSONArray; 29 | import org.json.JSONException; 30 | import org.json.JSONObject; 31 | 32 | import java.io.File; 33 | import java.io.IOException; 34 | 35 | import okhttp3.Call; 36 | import okhttp3.Callback; 37 | import okhttp3.Response; 38 | import song.HttpDownload.Net.NetSpeed; 39 | import song.HttpDownload.Net.NetSpeedTimer; 40 | import song.HttpDownload.Util.HttpUtil; 41 | 42 | //写得一手烂代码 43 | public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 44 | 45 | private TextView mUrl_ET;//输入框 46 | public static Button mAction;//开关 47 | public static String mUrl;//URI 48 | public static SharedPreferences sp; 49 | private SharedPreferences.Editor mEdit; 50 | public static Handler mHandler; 51 | private TextView mLog;//Log 52 | private com.xw.repo.BubbleSeekBar mSeekBar;//seekbar 53 | private TextView mThreadNum;//线程数 54 | private TextView mInternet;//网络 55 | private TextView mNetSpeed;//网速 56 | public static File mFiles;//私有目录 57 | public static NetSpeedTimer mNetSpeedTimer;// 58 | private String responseData; 59 | private String versionName; 60 | 61 | @RequiresApi(api = Build.VERSION_CODES.N) 62 | @Override 63 | protected void onCreate(Bundle savedInstanceState) { 64 | super.onCreate(savedInstanceState); 65 | setContentView(R.layout.activity_main); 66 | initId();//初始化 67 | //回显 68 | mUrl_ET.setText(sp.getString("url","")); 69 | 70 | //用于监听消息 71 | mHandler = new Handler(){ 72 | @RequiresApi(api = Build.VERSION_CODES.N) 73 | @Override 74 | public void handleMessage(Message msg) { 75 | if(msg.what == 200){ 76 | applyTypeface(); 77 | }else if (msg.what == NetSpeedTimer.NET_SPEED_TIMER_DEFAULT){ 78 | String speed = (String) msg.obj; 79 | mNetSpeed.setText("网速: "+speed); 80 | } 81 | 82 | switch (msg.what){ 83 | //100:异常信息 84 | case 100: 85 | mAction_status(Switch.getInstance().getStatu()); 86 | String str = (String) msg.obj; 87 | mLog.setText(str); 88 | break; 89 | //应用字体 90 | case 200: 91 | applyTypeface(); 92 | break; 93 | case NetSpeedTimer.NET_SPEED_TIMER_DEFAULT: 94 | String speed = (String) msg.obj; 95 | mNetSpeed.setText("网速: "+speed); 96 | break; 97 | //检测更新 98 | case 300: 99 | AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); 100 | dialog.setTitle("有新版本咯!\uD83D\uDE43"); 101 | dialog.setMessage("最新版:"+versionName); 102 | dialog.setCancelable(true); 103 | dialog.setPositiveButton("下载新版本!", new DialogInterface.OnClickListener() { 104 | @Override 105 | public void onClick(DialogInterface dialog, int which) { 106 | Switch.getInstance().setStatu(false); 107 | if(mNetSpeedTimer!=null){ //有可能打开app后,不刷流量 108 | mNetSpeedTimer.stopSpeedTimer(); 109 | } 110 | Uri uri = Uri.parse("https://gitee.com/qrxt/HttpDownload/blob/master/app/release"); 111 | Intent intent = new Intent(); 112 | intent.setAction("android.intent.action.VIEW"); 113 | intent.setData(uri); 114 | startActivity(intent); 115 | finish(); 116 | } 117 | }); 118 | dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() { 119 | @Override 120 | public void onClick(DialogInterface dialog, int which) { 121 | 122 | } 123 | }); 124 | dialog.show(); 125 | break; 126 | } 127 | 128 | } 129 | }; 130 | applyTypeface(); //应用字体 131 | CheckUpdate(); //检测更新 132 | } 133 | //网速 134 | private void initNewWork() { 135 | //创建NetSpeedTimer实例 136 | mNetSpeedTimer = new NetSpeedTimer(this, new NetSpeed(), mHandler).setDelayTime(10).setPeriodTime(1000); 137 | //在想要开始执行的地方调用该段代码 138 | mNetSpeedTimer.startSpeedTimer(); 139 | } 140 | 141 | //使用Typeface 142 | @RequiresApi(api = Build.VERSION_CODES.N) 143 | private void applyTypeface(){ 144 | //自定义一个字体样式 145 | File f0 = new File(mFiles.toString()+"/fonts/"+Constants.font_00); 146 | File f1 = new File(mFiles.toString()+"/fonts/"+Constants.font_01); 147 | //如果ttf文件不存在,就下载 148 | if (!f0.exists()){ 149 | new Thread(new Runnable() { 150 | @Override 151 | public void run() { 152 | FontDownload.download(0); 153 | } 154 | }).start(); 155 | return; 156 | }else if (!f1.exists()){ 157 | new Thread(new Runnable() { 158 | @Override 159 | public void run() { 160 | FontDownload.download(1); 161 | } 162 | }).start(); 163 | return; 164 | } 165 | Typeface ttf_00 = Typeface.createFromFile(f0); 166 | Typeface ttf_01 = Typeface.createFromFile(f1); 167 | mUrl_ET.setTypeface(ttf_00); 168 | mThreadNum.setTypeface(ttf_00); 169 | mAction.setTypeface(ttf_00); 170 | mInternet.setTypeface(ttf_00); 171 | mNetSpeed.setTypeface(ttf_01); 172 | } 173 | //复写返回键 174 | @Override 175 | public boolean onKeyDown(int keyCode, KeyEvent event){ 176 | 177 | AlertDialog.Builder dialog = new AlertDialog.Builder(this); 178 | dialog.setTitle("确定\"完全退出\"吗?"); 179 | dialog.setMessage("完全退出 将停止运行本应用程序!"); 180 | dialog.setCancelable(true); 181 | dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() { 182 | @Override 183 | public void onClick(DialogInterface dialog, int which) { 184 | Switch.getInstance().setStatu(false); 185 | if(mNetSpeedTimer!=null){ //有可能打开app后,不刷流量 186 | mNetSpeedTimer.stopSpeedTimer(); 187 | } 188 | finish(); 189 | } 190 | }); 191 | dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() { 192 | @Override 193 | public void onClick(DialogInterface dialog, int which) { 194 | 195 | } 196 | }); 197 | dialog.show(); 198 | 199 | return true; 200 | } 201 | //初始化控件 202 | private void initId() { 203 | sp = this.getSharedPreferences("config", MODE_PRIVATE); 204 | mFiles = this.getFilesDir(); 205 | //uri输入框 206 | mUrl_ET = findViewById(R.id.inputUrl_ET); 207 | mUrl_ET.setOnClickListener(this); 208 | //网络/网速 209 | mInternet = findViewById(R.id.internet_TV); 210 | mNetSpeed = findViewById(R.id.netSpeed_TV); 211 | //TextView:线程数 212 | mThreadNum = findViewById(R.id.ThreadNum_TV); 213 | //seekbar 不能放在onClick()方法中,因为 mSeekBar 是自定义类型 214 | mSeekBar = findViewById(R.id.seek_bar_ThreadNum); 215 | mSeekBar.setOnProgressChangedListener(new BubbleSeekBar.OnProgressChangedListener() { 216 | //参数发生改变 217 | @Override 218 | public void onProgressChanged(BubbleSeekBar bubbleSeekBar, int progress, float progressFloat, boolean fromUser) { 219 | mThreadNum.setText("线程数:"+((Integer)mSeekBar.getProgress()).toString()); 220 | } 221 | //处于滑动状态 222 | @Override 223 | public void getProgressOnActionUp(BubbleSeekBar bubbleSeekBar, int progress, float progressFloat) { 224 | 225 | } 226 | //停止滑动后 227 | @Override 228 | public void getProgressOnFinally(BubbleSeekBar bubbleSeekBar, int progress, float progressFloat, boolean fromUser) { 229 | 230 | } 231 | }); 232 | //开关 233 | mAction = findViewById(R.id.action_Btn); 234 | mAction.setOnClickListener(this); 235 | 236 | //log 237 | mLog = findViewById(R.id.log); 238 | 239 | // 240 | 241 | } 242 | //按钮点击事件 243 | @Override 244 | public void onClick(View v) { 245 | switch (v.getId()){ 246 | case R.id.action_Btn : 247 | action(); 248 | break; 249 | default: break; 250 | } 251 | } 252 | //点击开始按钮 253 | private void action() { 254 | //检测并保存 255 | if (saveUrl()) return; 256 | //取反,用于开关操作 257 | Switch.getInstance().setStatu(!Switch.getInstance().getStatu()); 258 | //按钮更改(文本/背景) 259 | mAction_status(Switch.getInstance().getStatu()); 260 | //如果是要启动 261 | if(Switch.getInstance().getStatu()){ 262 | //启动 263 | Thread_manager(); 264 | } 265 | } 266 | //方法:设置按钮显示状态 267 | private void mAction_status(boolean b) { 268 | if (b) { 269 | //开刷 270 | initNewWork();//启动网速 271 | mAction.setText("暂停"); 272 | mAction.setBackgroundColor(Color.parseColor("#5BEA62")); 273 | }else { 274 | //暂停 275 | mNetSpeedTimer.stopSpeedTimer();//关闭网速 276 | mAction.setText("继续测试~"); 277 | mAction.setBackgroundColor(Color.parseColor("#FF8080")); 278 | } 279 | } 280 | 281 | //线程管理器 282 | private void Thread_manager() { 283 | new Thread(){ 284 | @Override 285 | public void run() { 286 | super.run(); 287 | Download d = Download.getInstance(); 288 | //for循环用于一直监听按钮状态 289 | for(;Switch.getInstance().getStatu();){ 290 | //如果当前线程数小于8,就创建线程 291 | if(ThreadNum.getInstance().getNum() NetSpeedTimer 11 | * */ 12 | public class NetSpeed { 13 | private static final String TAG = NetSpeed.class.getSimpleName(); 14 | private long lastTotalRxBytes = 0; 15 | private long lastTimeStamp = 0; 16 | DecimalFormat df = new DecimalFormat("0.00");//小数格式,保留两位 17 | 18 | public String getNetSpeed(int uid) { 19 | long nowTotalRxBytes = getTotalRxBytes(uid);//总接收字节 20 | long nowTimeStamp = System.currentTimeMillis();//当前时间 21 | //(当前接收字节数-上次接收字节数)/(当前时间-上次时间 ms)*1000 单位:KB/s 22 | long speed = ((nowTotalRxBytes - lastTotalRxBytes) * 1000 / (nowTimeStamp - lastTimeStamp));//毫秒转换 23 | lastTimeStamp = nowTimeStamp; 24 | lastTotalRxBytes = nowTotalRxBytes; 25 | if(speed>1024){ 26 | return df.format(speed / 1024.00) + " MB/s"; 27 | } 28 | return speed + " KB/s"; 29 | } 30 | 31 | 32 | //getApplicationInfo().uid 33 | public long getTotalRxBytes(int uid) { 34 | //TrafficStats 判断是否支持流量统计api, 不支持:0 支持:返回总接收字节,单位KB 35 | 36 | return TrafficStats.getUidRxBytes(uid) == TrafficStats.UNSUPPORTED ? 0 : (TrafficStats.getTotalRxBytes() / 1024);//转为KB 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/song/HttpDownload/Net/NetSpeedTimer.java: -------------------------------------------------------------------------------- 1 | package song.HttpDownload.Net; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Message; 6 | 7 | import java.util.Timer; 8 | import java.util.TimerTask; 9 | 10 | public class NetSpeedTimer { 11 | private long defaultDelay = 1000; 12 | private long defaultPeriod = 1000; 13 | private static final int ERROR_CODE = -101011010; 14 | private int mMsgWhat = ERROR_CODE; 15 | private NetSpeed mNetSpeed; 16 | private Handler mHandler; 17 | private Context mContext; 18 | private SpeedTimerTask mSpeedTimerTask; 19 | 20 | public static final int NET_SPEED_TIMER_DEFAULT = 101010; 21 | //网速计时器(构造器) 22 | public NetSpeedTimer(Context context, NetSpeed netSpeed, Handler handler) { 23 | this.mContext = context; 24 | this.mNetSpeed = netSpeed; 25 | this.mHandler = handler; 26 | } 27 | //设置延迟时间 28 | public NetSpeedTimer setDelayTime(long delay) { 29 | this.defaultDelay = delay; 30 | return this; 31 | } 32 | //设置周期时间 33 | public NetSpeedTimer setPeriodTime(long period) { 34 | this.defaultPeriod = period; 35 | return this; 36 | } 37 | //信息发送 38 | public NetSpeedTimer setHanderWhat(int what) { 39 | this.mMsgWhat = what; 40 | return this; 41 | } 42 | 43 | /* 44 | * 开启获取网速定时器 45 | */ 46 | public void startSpeedTimer() { 47 | Timer timer = new Timer(); 48 | mSpeedTimerTask = new SpeedTimerTask(mContext, mNetSpeed, mHandler, 49 | mMsgWhat); 50 | timer.schedule(mSpeedTimerTask, defaultDelay, defaultPeriod); 51 | } 52 | 53 | /* 54 | * 关闭定时器 55 | */ 56 | public void stopSpeedTimer() { 57 | if (null != mSpeedTimerTask) { 58 | mSpeedTimerTask.cancel(); 59 | } 60 | } 61 | 62 | /* 63 | * @author 64 | * 静态内部类 65 | */ 66 | private static class SpeedTimerTask extends TimerTask { 67 | private int mMsgWhat; 68 | private NetSpeed mNetSpeed; 69 | private Handler mHandler; 70 | private Context mContext; 71 | 72 | public SpeedTimerTask(Context context, NetSpeed netSpeed, 73 | Handler handler, int what) { 74 | this.mContext = context; 75 | this.mHandler = handler; 76 | this.mNetSpeed = netSpeed; 77 | this.mMsgWhat = what; 78 | } 79 | //定时创建线程发送 80 | @Override 81 | public void run() { 82 | if (null != mNetSpeed && null != mHandler) { 83 | Message obtainMessage = mHandler.obtainMessage(); 84 | if (mMsgWhat != ERROR_CODE) { 85 | obtainMessage.what = mMsgWhat; 86 | } else { 87 | obtainMessage.what = NET_SPEED_TIMER_DEFAULT; 88 | } 89 | obtainMessage.obj = mNetSpeed.getNetSpeed(mContext 90 | .getApplicationInfo().uid); 91 | mHandler.sendMessage(obtainMessage); 92 | } 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /app/src/main/java/song/HttpDownload/Switch.java: -------------------------------------------------------------------------------- 1 | package song.HttpDownload; 2 | 3 | /** 4 | * 开关状态: 5 | * */ 6 | class Switch { 7 | //开关状态 8 | private static boolean statu = false; 9 | //获取状态 10 | static boolean getStatu() { 11 | return statu; 12 | } 13 | //设置状态 14 | static void setStatu(boolean statu) { 15 | INSTANCE.statu = statu; 16 | } 17 | 18 | //单例设计模式 19 | private static Switch INSTANCE = new Switch(); 20 | private Switch(){}; 21 | static Switch getInstance(){ 22 | return INSTANCE; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/song/HttpDownload/ThreadNum.java: -------------------------------------------------------------------------------- 1 | package song.HttpDownload; 2 | /** 用于描述: 3 | * 线程对象,及其方法 4 | * synchronized修饰方法:同一时刻只能有一个线程在方法中,保证线程安全 5 | * 6 | * */ 7 | public class ThreadNum { 8 | //当前线程数 9 | private static int num = 0; 10 | //直接初始化对象 11 | private static ThreadNum INSTANCE = new ThreadNum(); 12 | //加 13 | synchronized static void numAdd(){ 14 | num++; 15 | } 16 | //减 17 | synchronized static void numLess(){ 18 | num--; 19 | } 20 | //获取线程数 21 | static int getNum(){ 22 | return num; 23 | } 24 | //私有化构造器 25 | private ThreadNum(){} 26 | //暴露对象 27 | public static ThreadNum getInstance(){ 28 | return INSTANCE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/song/HttpDownload/Util/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package song.HttpDownload.Util; 2 | 3 | import okhttp3.OkHttpClient; 4 | import okhttp3.Request; 5 | 6 | public class HttpUtil { 7 | 8 | public static void sendRequestWithOkhttp(String address,okhttp3.Callback callback) 9 | { 10 | OkHttpClient client=new OkHttpClient(); 11 | Request request=new Request.Builder().url(address).build(); 12 | client.newCall(request).enqueue(callback); 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 13 | 15 | 17 | 19 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/textview_border.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 21 | 28 | 29 | 33 | 39 | 45 | 46 | 47 | 48 | 52 | 53 | 60 | 68 | 69 | 70 |