提交 bac6c4c6 编写于 作者: 猴子请来的救兵_'s avatar 猴子请来的救兵_

模拟弱网的功能

上级 14724c76
......@@ -28,6 +28,6 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.squareup.okhttp3:okhttp:3.6.0'
implementation 'com.squareup.okio:okio:1.11.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
implementation 'com.squareup.okio:okio:1.15.0'
}
package com.didichuxing.doraemondemo;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.text.format.Formatter;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
......@@ -15,28 +19,36 @@ import com.didichuxing.doraemonkit.kit.network.common.NetworkPrinterHelper;
import com.didichuxing.doraemonkit.kit.timecounter.TimeCounterManager;
import com.didichuxing.doraemonkit.ui.realtime.RealTimeChartPage;
import com.didichuxing.doraemonkit.ui.realtime.datasource.DataSourceFactory;
import com.didichuxing.doraemonkit.util.threadpool.ThreadPoolProxy;
import com.didichuxing.doraemonkit.util.threadpool.ThreadPoolProxyFactory;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private OkHttpClient okHttpClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......@@ -48,6 +60,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
findViewById(R.id.btn_show_hide_icon).setOnClickListener(this);
findViewById(R.id.btn_time_count).setOnClickListener(this);
findViewById(R.id.btn_create_database).setOnClickListener(this);
findViewById(R.id.btn_upload_test).setOnClickListener(this);
findViewById(R.id.btn_download_test).setOnClickListener(this);
okHttpClient = new OkHttpClient().newBuilder().build();
}
......@@ -111,6 +125,12 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
dbHelper.getWritableDatabase();
dbHelper.close();
break;
case R.id.btn_upload_test:
requestByFile(true);
break;
case R.id.btn_download_test:
requestByFile(false);
break;
default:
break;
}
......@@ -193,6 +213,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
onHttpFailure(e);
}
@Override
......@@ -248,6 +269,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
onHttpFailure(e);
}
@Override
......@@ -258,4 +280,111 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
}
});
}
/**
* 模拟上传或下载文件
*
* @param upload true上传 false下载
*/
private void requestByFile(final boolean upload) {
final ProgressDialog dialog = ProgressDialog.show(this, null, null);
dialog.setCancelable(true);
Request request = null;
if (upload) {
try {
//模拟一个1M的文件用来上传
final long length = 1L * 1024 * 1024;
final File temp = new File(getFilesDir(), "test.tmp");
if (!temp.exists() || temp.length() != length) {
final RandomAccessFile accessFile = new RandomAccessFile(temp, "rwd");
accessFile.setLength(length);
temp.createNewFile();
}
request = new Request.Builder()
.post(RequestBody.create(MediaType.parse(temp.getName()), temp))
.url("http://wallpaper.apc.360.cn/index.php?c=WallPaper&a=getAppsByOrder&order=create_time&start=0&count=1&from=360chrome")
.build();
} catch (IOException e) {
e.printStackTrace();
}
} else {
//下载一个2M的文件
request = new Request.Builder()
.get()
.url("http://cdn1.lbesec.com/products/history/20131220/privacyspace_rel_2.2.1617.apk")
.build();
}
Call call = okHttpClient.newCall(request);
final long startTime = SystemClock.uptimeMillis();
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
dialog.cancel();
onHttpFailure(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
onFailure(call, new IOException(response.message()));
return;
}
final ResponseBody body = response.body();
if (!upload) {
inputStream2File(body.byteStream(), new File(getFilesDir(), "test.apk"));
}
dialog.cancel();
final long requestLength = upload ? call.request().body().contentLength() : 0;
final long responseLength = body.contentLength() < 0 ? 0 : body.contentLength();
final long endTime = SystemClock.uptimeMillis() - startTime;
final long speed = (upload ? requestLength : responseLength) / endTime * 1000;
final String message = String.format("请求大小:%s,响应大小:%s,耗时:%dms,均速:%s/s", Formatter.formatFileSize(getApplicationContext(), requestLength), Formatter.formatFileSize(getApplicationContext(), responseLength), endTime, Formatter.formatFileSize(getApplicationContext(), speed));
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.d("onResponse", message);
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
}
});
}
});
}
private void onHttpFailure(final IOException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (e instanceof UnknownHostException) {
Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();
} else if (e instanceof SocketTimeoutException) {
Toast.makeText(MainActivity.this, "请求超时", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
private void inputStream2File(InputStream is, File saveFile) {
try {
int len;
byte[] buf = new byte[2048];
FileOutputStream fos = new FileOutputStream(saveFile);
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.flush();
fos.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
okHttpClient.dispatcher().cancelAll();
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.didichuxing.doraemondemo.MainActivity">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.didichuxing.doraemondemo.MainActivity">
<Button
android:id="@+id/btn_test_urlconnection"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="HttpUrlConnection Test"/>
android:text="HttpUrlConnection Test" />
<Button
android:id="@+id/btn_test_okhttp"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="OkHttp Test"/>
android:text="OkHttp Test" />
<Button
android:id="@+id/btn_test_custom"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="其他网络库 Test"/>
android:text="其他网络库 Test" />
<Button
android:id="@+id/btn_show_hide_icon"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="显示/隐藏入口"/>
android:text="显示/隐藏入口" />
<Button
android:id="@+id/btn_time_count"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="页面跳转耗时"/>
android:text="页面跳转耗时" />
<Button
android:id="@+id/btn_test_crash"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="模拟 Crash"/>
android:text="模拟 Crash" />
<Button
android:id="@+id/btn_create_database"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="创建数据库"/>
android:text="创建数据库" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_upload_test"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="50dp"
android:text="上传测试" />
<Button
android:layout_weight="1"
android:id="@+id/btn_download_test"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="下载测试" />
</LinearLayout>
</LinearLayout>
......@@ -25,6 +25,6 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
compileOnly 'com.squareup.okio:okio:1.11.0'
compileOnly 'com.squareup.okhttp3:okhttp:3.6.0'
compileOnly 'com.squareup.okio:okio:1.15.0'
compileOnly 'com.squareup.okhttp3:okhttp:3.12.1'
}
\ No newline at end of file
package com.didichuxing.doraemonkit.kit.network.okhttp;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* @author denghaha
* created 2019-05-10 11:56
*/
public class DoraemonWeakNetworkInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
return chain.proceed(request);
}
}
\ No newline at end of file
......@@ -36,11 +36,11 @@ dependencies {
transitive=true
exclude group: 'com.android.support'
}
implementation 'com.squareup.okhttp3:okhttp:3.6.0'
compileOnly 'com.squareup.okio:okio:1.11.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
compileOnly 'com.squareup.okio:okio:1.15.0'
compileOnly 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
testImplementation 'junit:junit:4.12'
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.google.zxing:core:3.3.0'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
......
......@@ -29,8 +29,8 @@ import com.didichuxing.doraemonkit.kit.parameter.ram.Ram;
import com.didichuxing.doraemonkit.kit.sysinfo.SysInfo;
import com.didichuxing.doraemonkit.kit.temporaryclose.TemporaryClose;
import com.didichuxing.doraemonkit.kit.timecounter.TimeCounterKit;
import com.didichuxing.doraemonkit.kit.topactivity.TopActivity;
import com.didichuxing.doraemonkit.kit.viewcheck.ViewChecker;
import com.didichuxing.doraemonkit.kit.weaknetwork.WeakNetwork;
import com.didichuxing.doraemonkit.kit.webdoor.WebDoor;
import com.didichuxing.doraemonkit.kit.webdoor.WebDoorManager;
import com.didichuxing.doraemonkit.ui.FloatIconPage;
......@@ -163,6 +163,7 @@ public class DoraemonKit {
tool.add(new Crash());
tool.add(new LogInfo());
tool.add(new DataClean());
tool.add(new WeakNetwork());
performance.add(new FrameInfo());
performance.add(new Cpu());
......
......@@ -24,4 +24,5 @@ public interface FragmentIndex {
int FRAGMENT_WEB_DOOR_DEFAULT = 18;
int FRAGMENT_CUSTOM = 19;
int FRAGMENT_TOP_ACTIVITY = 20;
int FRAGMENT_WEAK_NETWORK = 21;
}
......@@ -4,6 +4,7 @@ import com.didichuxing.doraemonkit.kit.network.NetworkManager;
import com.didichuxing.doraemonkit.kit.network.httpurlconnection.HttpUrlConnectionProxy;
import com.didichuxing.doraemonkit.kit.network.httpurlconnection.HttpsUrlConnectionProxy;
import com.didichuxing.doraemonkit.kit.network.okhttp.DoraemonInterceptor;
import com.didichuxing.doraemonkit.kit.network.okhttp.DoraemonWeakNetworkInterceptor;
import java.net.HttpURLConnection;
import java.net.URLConnection;
......@@ -30,6 +31,7 @@ public class AopUtils {
}
public static void addInterceptor(OkHttpClient.Builder builder) {
builder.addInterceptor(new DoraemonInterceptor());
builder.addNetworkInterceptor(new DoraemonWeakNetworkInterceptor())
.addInterceptor(new DoraemonInterceptor());
}
}
package com.didichuxing.doraemonkit.kit.network.okhttp;
import com.didichuxing.doraemonkit.kit.weaknetwork.WeakNetworkManager;
import java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* 用于模拟弱网的拦截器
*
* @author denghaha
* created 2019-05-09 16:29
*/
public class DoraemonWeakNetworkInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
if (!WeakNetworkManager.get().isActive()) {
Request request = chain.request();
return chain.proceed(request);
}
final int type = WeakNetworkManager.get().getType();
switch (type) {
case WeakNetworkManager.TYPE_TIMEOUT:
//超时
final HttpUrl url = chain.request().url();
throw WeakNetworkManager.get().simulateTimeOut(url.host(), url.port());
case WeakNetworkManager.TYPE_SPEED_LIMIT:
//限速
return WeakNetworkManager.get().simulateSpeedLimit(chain);
default:
//断网
throw WeakNetworkManager.get().simulateOffNetwork(chain.request().url().host());
}
}
}
package com.didichuxing.doraemonkit.kit.weaknetwork;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import okio.Buffer;
import okio.BufferedSink;
import okio.ByteString;
import okio.Okio;
import okio.Sink;
import okio.Source;
import okio.Timeout;
/**
* 可以设置每次写入大小的BufferedSink
*
* @author denghaha
* created 2019-05-10 16:07
*/
public class ByteCountBufferedSink implements BufferedSink {
private final long mByteCount;
private final Sink mOriginalSink;
private final BufferedSink mDelegate;
public ByteCountBufferedSink(Sink sink, long byteCount) {
this.mOriginalSink = sink;
this.mDelegate = Okio.buffer(mOriginalSink);
this.mByteCount = byteCount;
}
@Override
public long writeAll(Source source) throws IOException {
if (source == null) throw new IllegalArgumentException("source == null");
long totalBytesRead = 0;
for (long readCount; (readCount = source.read(buffer(), mByteCount)) != -1; ) {
totalBytesRead += readCount;
emitCompleteSegments();
}
return totalBytesRead;
}
@Override
public BufferedSink emitCompleteSegments() throws IOException {
mOriginalSink.write(buffer(), mByteCount);
return this;
}
@Override
public Buffer buffer() {
return mDelegate.buffer();
}
@Override
public BufferedSink write(ByteString byteString) throws IOException {
return mDelegate.write(byteString);
}
@Override
public BufferedSink write(byte[] source) throws IOException {
return mDelegate.write(source);
}
@Override
public BufferedSink write(byte[] source, int offset, int byteCount) throws IOException {
return mDelegate.write(source, offset, byteCount);
}
@Override
public BufferedSink write(Source source, long byteCount) throws IOException {
return mDelegate.write(source, byteCount);
}
@Override
public BufferedSink writeUtf8(String string) throws IOException {
return mDelegate.writeUtf8(string);
}
@Override
public BufferedSink writeUtf8(String string, int beginIndex, int endIndex) throws IOException {
return mDelegate.writeUtf8(string, beginIndex, endIndex);
}
@Override
public BufferedSink writeUtf8CodePoint(int codePoint) throws IOException {
return mDelegate.writeUtf8CodePoint(codePoint);
}
@Override
public BufferedSink writeString(String string, Charset charset) throws IOException {
return mDelegate.writeString(string, charset);
}
@Override
public BufferedSink writeString(String string, int beginIndex, int endIndex, Charset charset) throws IOException {
return mDelegate.writeString(string, beginIndex, endIndex, charset);
}
@Override
public BufferedSink writeByte(int b) throws IOException {
return mDelegate.writeByte(b);
}
@Override
public BufferedSink writeShort(int s) throws IOException {
return mDelegate.writeShort(s);
}
@Override
public BufferedSink writeShortLe(int s) throws IOException {
return mDelegate.writeShortLe(s);
}
@Override
public BufferedSink writeInt(int i) throws IOException {
return mDelegate.writeInt(i);
}
@Override
public BufferedSink writeIntLe(int i) throws IOException {
return mDelegate.writeIntLe(i);
}
@Override
public BufferedSink writeLong(long v) throws IOException {
return mDelegate.writeLong(v);
}
@Override
public BufferedSink writeLongLe(long v) throws IOException {
return mDelegate.writeLongLe(v);
}
@Override
public BufferedSink writeDecimalLong(long v) throws IOException {
return mDelegate.writeDecimalLong(v);
}
@Override
public BufferedSink writeHexadecimalUnsignedLong(long v) throws IOException {
return mDelegate.writeHexadecimalUnsignedLong(v);
}
@Override
public void flush() throws IOException {
mDelegate.flush();
}
@Override
public BufferedSink emit() throws IOException {
return mDelegate.emit();
}
@Override
public OutputStream outputStream() {
return mDelegate.outputStream();
}
@Override
public int write(ByteBuffer src) throws IOException {
return mDelegate.write(src);
}
@Override
public boolean isOpen() {
return mDelegate.isOpen();
}
@Override
public void write(Buffer source, long byteCount) throws IOException {
mDelegate.write(source, byteCount);
}
@Override
public Timeout timeout() {
return mDelegate.timeout();
}
@Override
public void close() throws IOException {
mDelegate.close();
}
}
package com.didichuxing.doraemonkit.kit.weaknetwork;
import android.os.SystemClock;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Sink;
/**
* @author denghaha
* created 2019-05-09 18:35
*/
public class SpeedLimitRequestBody extends RequestBody {
private long mSpeedByte;//b/s
private RequestBody mRequestBody;
private BufferedSink mBufferedSink;
public SpeedLimitRequestBody(long speed, RequestBody source) {
this.mRequestBody = source;
this.mSpeedByte = speed * 1024;//转成字节
}
@Override
public MediaType contentType() {
return mRequestBody.contentType();
}
@Override
public long contentLength() throws IOException {
return mRequestBody.contentLength();
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
if (mBufferedSink == null) {
//mBufferedSink = Okio.buffer(sink(sink));
//默认8K 精确到1K
mBufferedSink = new ByteCountBufferedSink(sink(sink), 1024L);
}
mRequestBody.writeTo(mBufferedSink);
mBufferedSink.close();
}
private Sink sink(final BufferedSink sink) {
return new ForwardingSink(sink) {
private long cacheTotalBytesWritten;
private long cacheStartTime;
@Override
public void write(Buffer source, long byteCount) throws IOException {
if (cacheStartTime == 0) {
cacheStartTime = SystemClock.uptimeMillis();
}
super.write(source, byteCount);
cacheTotalBytesWritten += byteCount;
long endTime = SystemClock.uptimeMillis() - cacheStartTime;
//如果在一秒内
if (endTime <= 1000L) {
//大小就超出了限制
if (cacheTotalBytesWritten >= mSpeedByte) {
long sleep = 1000L - endTime;
SystemClock.sleep(sleep);
//重置计算
cacheStartTime = 0L;
cacheTotalBytesWritten = 0L;
}
}
}
};
}
}
package com.didichuxing.doraemonkit.kit.weaknetwork;
import android.os.SystemClock;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
/**
* @author denghaha
* created 2019-05-09 18:35
*/
public class SpeedLimitResponseBody extends ResponseBody {
private long mSpeedByte;//b/s
private ResponseBody mResponseBody;
private BufferedSource mBufferedSource;
public SpeedLimitResponseBody(long speed, ResponseBody source) {
this.mResponseBody = source;
this.mSpeedByte = speed * 1024L;//转成字节
}
@Override
public MediaType contentType() {
return mResponseBody.contentType();
}
@Override
public long contentLength() {
return mResponseBody.contentLength();
}
@Override
public BufferedSource source() {
if (mBufferedSource == null) {
mBufferedSource = Okio.buffer(source(mResponseBody.source()));
}
return mBufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
private long cacheTotalBytesRead;
private long cacheStartTime;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
if (cacheStartTime == 0) {
cacheStartTime = SystemClock.uptimeMillis();
}
//默认8K 精确到1K
long bytesRead = super.read(sink.buffer(), 1024L);
cacheTotalBytesRead += bytesRead == -1 ? 0 : bytesRead;
long endTime = SystemClock.uptimeMillis() - cacheStartTime;
//如果在一秒内
if (endTime <= 1000L) {
//大小就超出了限制
if (cacheTotalBytesRead >= mSpeedByte) {
long sleep = 1000L - endTime;
SystemClock.sleep(sleep);
//重置计算
cacheStartTime = 0L;
cacheTotalBytesRead = 0L;
}
}
return bytesRead;
}
};
}
}
package com.didichuxing.doraemonkit.kit.weaknetwork;
import android.content.Context;
import android.content.Intent;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.constant.BundleKey;
import com.didichuxing.doraemonkit.constant.FragmentIndex;
import com.didichuxing.doraemonkit.kit.Category;
import com.didichuxing.doraemonkit.kit.IKit;
import com.didichuxing.doraemonkit.ui.UniversalActivity;
/**
* 模拟弱网
*
* @author denghaha
* created 2019/5/7 19:05
*/
public class WeakNetwork implements IKit {
@Override
public int getCategory() {
return Category.TOOLS;
}
@Override
public int getName() {
return R.string.dk_kit_weak_network;
}
@Override
public int getIcon() {
return R.drawable.dk_weak_network;
}
@Override
public void onClick(Context context) {
Intent intent = new Intent(context, UniversalActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(BundleKey.FRAGMENT_INDEX, FragmentIndex.FRAGMENT_WEAK_NETWORK);
context.startActivity(intent);
}
@Override
public void onAppInit(Context context) {
}
}
\ No newline at end of file
package com.didichuxing.doraemonkit.kit.weaknetwork;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import com.didichuxing.doraemonkit.R;
import com.didichuxing.doraemonkit.ui.base.BaseFragment;
import com.didichuxing.doraemonkit.ui.setting.SettingItem;
import com.didichuxing.doraemonkit.ui.setting.SettingItemAdapter;
import com.didichuxing.doraemonkit.ui.widget.titlebar.HomeTitleBar;
/**
* 模拟弱网
*
* @author denghaha
* created 2019/5/7 19:10
*/
public class WeakNetworkFragment extends BaseFragment implements TextWatcher {
private SettingItemAdapter mSettingItemAdapter;
private RecyclerView mSettingList;
private View mWeakNetworkOptionView;
private View mTimeoutOptionView;
private View mSpeedLimitView;
private EditText mTimeoutValueView, mRequestSpeedView, mResponseSpeedView;
@Override
protected int onRequestLayout() {
return R.layout.dk_fragment_weak_network;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initView();
}
private void initView() {
HomeTitleBar homeTitleBar = findViewById(R.id.title_bar);
homeTitleBar.setListener(new HomeTitleBar.OnTitleBarClickListener() {
@Override
public void onRightClick() {
getActivity().finish();
}
});
mWeakNetworkOptionView = findViewById(R.id.weak_network_layout);
mSettingList = findViewById(R.id.setting_list);
mSettingList.setLayoutManager(new LinearLayoutManager(getContext()));
mSettingItemAdapter = new SettingItemAdapter(getContext());
mSettingList.setAdapter(mSettingItemAdapter);
mSettingItemAdapter.append(new SettingItem(R.string.dk_weak_network_switch, WeakNetworkManager.get().isActive()));
mSettingItemAdapter.setOnSettingItemSwitchListener(new SettingItemAdapter.OnSettingItemSwitchListener() {
@Override
public void onSettingItemSwitch(View view, SettingItem data, boolean on) {
if (data.desc == R.string.dk_weak_network_switch) {
setWeakNetworkEnabled(data.isChecked);
}
}
});
RadioGroup optionGroup = findViewById(R.id.weak_network_option);
optionGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (R.id.timeout == checkedId) {
//超时
showTimeoutOptionView();
} else if (R.id.speed_limit == checkedId) {
//限速
showSpeedLimitOptionView();
} else {
//断网
showOffNetworkOptionView();
}
}
});
mTimeoutOptionView = findViewById(R.id.layout_timeout_option);
mSpeedLimitView = findViewById(R.id.layout_speed_limit);
mTimeoutValueView = findViewById(R.id.value_timeout);
mTimeoutValueView.addTextChangedListener(this);
mRequestSpeedView = findViewById(R.id.request_speed);
mRequestSpeedView.addTextChangedListener(this);
mResponseSpeedView = findViewById(R.id.response_speed);
mResponseSpeedView.addTextChangedListener(this);
updateUIState();
}
private void updateUIState() {
final boolean active = WeakNetworkManager.get().isActive();
mWeakNetworkOptionView.setVisibility(active ? View.VISIBLE : View.GONE);
if (active) {
int checkButtonId;
final int type = WeakNetworkManager.get().getType();
switch (type) {
case WeakNetworkManager.TYPE_TIMEOUT:
checkButtonId = R.id.timeout;
break;
case WeakNetworkManager.TYPE_SPEED_LIMIT:
checkButtonId = R.id.speed_limit;
break;
default:
checkButtonId = R.id.off_network;
break;
}
RadioButton defaultOptionView = findViewById(checkButtonId);
defaultOptionView.setChecked(true);
mTimeoutValueView.setHint(String.valueOf(WeakNetworkManager.get().getTimeOutMillis()));
mRequestSpeedView.setHint(String.valueOf(WeakNetworkManager.get().getRequestSpeed()));
mResponseSpeedView.setHint(String.valueOf(WeakNetworkManager.get().getResponseSpeed()));
}
}
private void setWeakNetworkEnabled(boolean enabled) {
WeakNetworkManager.get().setActive(enabled);
updateUIState();
}
private void showTimeoutOptionView() {
mTimeoutOptionView.setVisibility(View.VISIBLE);
mSpeedLimitView.setVisibility(View.GONE);
WeakNetworkManager.get().setType(WeakNetworkManager.TYPE_TIMEOUT);
}
private void showSpeedLimitOptionView() {
mSpeedLimitView.setVisibility(View.VISIBLE);
mTimeoutOptionView.setVisibility(View.GONE);
WeakNetworkManager.get().setType(WeakNetworkManager.TYPE_SPEED_LIMIT);
}
private void showOffNetworkOptionView() {
mSpeedLimitView.setVisibility(View.GONE);
mTimeoutOptionView.setVisibility(View.GONE);
WeakNetworkManager.get().setType(WeakNetworkManager.TYPE_OFF_NETWORK);
}
private long getLongValue(EditText editText) {
CharSequence text = editText.getText();
if (TextUtils.isEmpty(text)) {
return 0L;
}
return Long.parseLong(text.toString());
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
long timeOutMillis = getLongValue(mTimeoutValueView);
long requestSpeed = getLongValue(mRequestSpeedView);
long responseSpeed = getLongValue(mResponseSpeedView);
WeakNetworkManager.get().setParameter(timeOutMillis, requestSpeed, responseSpeed);
}
@Override
public void afterTextChanged(Editable s) {
}
static class SimpleTextWatcher implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
}
}
}
package com.didichuxing.doraemonkit.kit.weaknetwork;
import android.os.SystemClock;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.concurrent.atomic.AtomicBoolean;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* @author denghaha
* created 2019-05-09 16:30
*/
public class WeakNetworkManager {
public static final int TYPE_OFF_NETWORK = 0;
public static final int TYPE_TIMEOUT = 1;
public static final int TYPE_SPEED_LIMIT = 2;
public static final int DEFAULT_TIMEOUT_MILLIS = 2000;
public static final int DEFAULT_REQUEST_SPEED = 1;
public static final int DEFAULT_RESPONSE_SPEED = 1;
private int mType = TYPE_OFF_NETWORK;
private long mTimeOutMillis = DEFAULT_TIMEOUT_MILLIS;
private long mRequestSpeed = DEFAULT_REQUEST_SPEED;
private long mResponseSpeed = DEFAULT_RESPONSE_SPEED;
private AtomicBoolean mIsActive = new AtomicBoolean(false);
private static class Holder {
private static WeakNetworkManager INSTANCE = new WeakNetworkManager();
}
public static WeakNetworkManager get() {
return WeakNetworkManager.Holder.INSTANCE;
}
public boolean isActive() {
return mIsActive.get();
}
public void setActive(boolean isActive) {
mIsActive.set(isActive);
}
public void setParameter(long timeOutMillis, long requestSpeed, long responseSpeed) {
if (timeOutMillis > 0) {
mTimeOutMillis = timeOutMillis;
}
if (requestSpeed > 0) {
mRequestSpeed = requestSpeed;
}
if (responseSpeed > 0) {
mResponseSpeed = responseSpeed;
}
}
public void setType(int type) {
mType = type;
}
public int getType() {
return mType;
}
public long getTimeOutMillis() {
return mTimeOutMillis;
}
public long getRequestSpeed() {
return mRequestSpeed;
}
public long getResponseSpeed() {
return mResponseSpeed;
}
/**
* 模拟断网
*/
public UnknownHostException simulateOffNetwork(String host) {
return new UnknownHostException(String.format("Unable to resolve host \"%s\": No address associated with hostname", host));
}
/**
* 模拟超时
*
* @param host
* @param port
*/
public SocketTimeoutException simulateTimeOut(String host, int port) {
SystemClock.sleep(mTimeOutMillis);
return new SocketTimeoutException(String.format("failed to connect to %s (port %d) after %dms", host, port, mTimeOutMillis));
}
/**
* 限速
*/
public Response simulateSpeedLimit(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
final RequestBody body = request.body();
if (body != null) {
request = request.newBuilder().method(request.method(), new SpeedLimitRequestBody(mRequestSpeed, body)).build();
}
final Response response = chain.proceed(request);
return response.newBuilder().body(new SpeedLimitResponseBody(mResponseSpeed, response.body())).build();
}
}
......@@ -23,6 +23,7 @@ import com.didichuxing.doraemonkit.kit.sysinfo.SysInfoFragment;
import com.didichuxing.doraemonkit.kit.timecounter.TimeCounterFragment;
import com.didichuxing.doraemonkit.kit.topactivity.TopActivityFragment;
import com.didichuxing.doraemonkit.kit.viewcheck.ViewCheckFragment;
import com.didichuxing.doraemonkit.kit.weaknetwork.WeakNetworkFragment;
import com.didichuxing.doraemonkit.kit.webdoor.WebDoorDefaultFragment;
import com.didichuxing.doraemonkit.kit.webdoor.WebDoorFragment;
import com.didichuxing.doraemonkit.ui.base.BaseActivity;
......@@ -76,6 +77,9 @@ public class UniversalActivity extends BaseActivity {
case FragmentIndex.FRAGMENT_DATA_CLEAN:
fragmentClass = DataCleanFragment.class;
break;
case FragmentIndex.FRAGMENT_WEAK_NETWORK:
fragmentClass = WeakNetworkFragment.class;
break;
case FragmentIndex.FRAGMENT_BLOCK_MONITOR:
fragmentClass = BlockMonitorFragment.class;
break;
......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/dk_color_FFFFFF"
android:orientation="vertical"
android:paddingLeft="@dimen/dk_dp_15"
android:paddingRight="@dimen/dk_dp_15">
<com.didichuxing.doraemonkit.ui.widget.titlebar.HomeTitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="89dp"
app:dkIcon="@drawable/dk_close_icon_big"
app:dkTitle="@string/dk_kit_weak_network" />
<android.support.v7.widget.RecyclerView
android:id="@+id/setting_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title_bar" />
<RelativeLayout
android:id="@+id/weak_network_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/setting_list"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dk_dp_15"
android:paddingLeft="@dimen/dk_dp_15"
android:paddingRight="@dimen/dk_dp_15"
android:visibility="gone"
tools:visibility="visible">
<RadioGroup
android:id="@+id/weak_network_option"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dk_dp_15"
android:orientation="horizontal">
<RadioButton
android:id="@+id/off_network"
style="@style/DK.RadioButton.Left"
android:layout_weight="1"
android:text="@string/dk_weak_network_off" />
<RadioButton
android:id="@+id/timeout"
style="@style/DK.RadioButton"
android:layout_weight="1"
android:text="@string/dk_weak_network_timeout" />
<RadioButton
android:id="@+id/speed_limit"
style="@style/DK.RadioButton.Right"
android:layout_weight="1"
android:text="@string/dk_weak_network_speed_limit" />
</RadioGroup>
<RelativeLayout
android:id="@+id/layout_timeout_option"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/weak_network_option"
android:visibility="gone">
<TextView
android:id="@+id/label_timeout"
style="@style/DK.TextBig.Darker"
android:layout_centerVertical="true"
android:text="超时时间:" />
<EditText
android:id="@+id/value_timeout"
style="@style/DK.Input"
android:layout_width="80dp"
android:layout_toRightOf="@id/label_timeout"
android:gravity="center"
android:hint="2000"
android:inputType="number"
android:paddingLeft="@dimen/dk_dp_5"
android:paddingRight="@dimen/dk_dp_5"
android:singleLine="true" />
<TextView
style="@style/DK.TextBig.Darker"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/value_timeout"
android:text="ms" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/layout_speed_limit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/weak_network_option"
android:visibility="gone"
tools:visibility="visible">
<RelativeLayout
android:id="@+id/layout_limit_request"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/label_request_speed"
style="@style/DK.TextBig.Darker"
android:layout_centerVertical="true"
android:text="@string/dk_weak_network_request_limit" />
<EditText
android:id="@+id/request_speed"
style="@style/DK.Input"
android:layout_width="80dp"
android:layout_toRightOf="@id/label_request_speed"
android:gravity="center"
android:hint="1"
android:inputType="number"
android:paddingLeft="@dimen/dk_dp_5"
android:paddingRight="@dimen/dk_dp_5"
android:singleLine="true" />
<TextView
style="@style/DK.TextBig.Darker"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/request_speed"
android:text="@string/dk_weak_network_speed_unit" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/layout_limit_response"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/layout_limit_request">
<TextView
android:id="@+id/label_response_speed"
style="@style/DK.TextBig.Darker"
android:layout_centerVertical="true"
android:text="@string/dk_weak_network_response_limit" />
<EditText
android:id="@+id/response_speed"
style="@style/DK.Input"
android:layout_width="80dp"
android:layout_toRightOf="@id/label_response_speed"
android:gravity="center"
android:hint="1"
android:inputType="number"
android:paddingLeft="@dimen/dk_dp_5"
android:paddingRight="@dimen/dk_dp_5"
android:singleLine="true" />
<TextView
style="@style/DK.TextBig.Darker"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/response_speed"
android:text="@string/dk_weak_network_speed_unit" />
</RelativeLayout>
<TextView
style="@style/DK.TextSmall"
android:layout_below="@id/layout_limit_response"
android:layout_marginTop="@dimen/dk_dp_15"
android:gravity="left"
android:text="@string/dk_weak_network_limit_message" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
\ No newline at end of file
......@@ -17,6 +17,7 @@
<string name="dk_kit_temporary_close">Hide Doraemon</string>
<string name="dk_kit_crash">Crash Viewer</string>
<string name="dk_kit_data_clean">Cache Cleanup</string>
<string name="dk_kit_weak_network">Simulated Weak Network</string>
<string name="dk_kit_view_check">View Ciewer</string>
<string name="dk_kit_net_monitor">Traffic Monitor</string>
<string name="dk_kit_time_counter">Time Counter</string>
......@@ -85,6 +86,15 @@
<string name="dk_crash_capture_look">View Crash Log</string>
<string name="dk_crash_capture_clean_data">Clean Crash Cache</string>
<string name="dk_crash_capture_summary_title">Crash Log List</string>
<string name="dk_weak_network_switch">Simulate Weak Network Switch</string>
<string name="dk_weak_network_off">Off Network</string>
<string name="dk_weak_network_timeout">Time Out</string>
<string name="dk_weak_network_speed_limit">Speed Limit</string>
<string name="dk_weak_network_request_limit">Request Speed Limit:</string>
<string name="dk_weak_network_response_limit">Response Speed Limit:</string>
<string name="dk_weak_network_limit_message">request speed limit will limit speed when uploading, response speed limit will limit speed when downloading, 0 does not limit speed</string>
<string name="dk_back">Back</string>
<string name="dk_frameinfo_ram">RAM</string>
<string name="dk_kit_network_monitor">Network Monitor</string>
......@@ -143,8 +153,8 @@
<string name="dk_item_time_counter_switch">Activity Time Counter</string>
<string name="dk_item_time_goto_list">View History</string>
<string name="dk_kit_block_time_counter_list">Time Counter History</string>
<string name="dk_submit" >submit</string>
<string name="dk_cancel" >cancel</string>
<string name="dk_submit">submit</string>
<string name="dk_cancel">cancel</string>
<string name="dk_delete">delete</string>
<string name="dk_db_tips_insert">insert</string>
......
......@@ -18,6 +18,7 @@
<string name="dk_kit_temporary_close">隐藏</string>
<string name="dk_kit_crash">Crash查看</string>
<string name="dk_kit_data_clean">缓存清理</string>
<string name="dk_kit_weak_network">模拟弱网</string>
<string name="dk_kit_view_check">控件检查</string>
<string name="dk_kit_net_monitor">流量监控</string>
<string name="dk_kit_time_counter">耗时</string>
......@@ -86,6 +87,15 @@
<string name="dk_crash_capture_look">查看Crash日志</string>
<string name="dk_crash_capture_switch">Crash日志收集开关</string>
<string name="dk_crash_capture_summary_title">Crash日志列表</string>
<string name="dk_weak_network_switch">模拟弱网开关</string>
<string name="dk_weak_network_off">断网</string>
<string name="dk_weak_network_timeout">超时</string>
<string name="dk_weak_network_speed_limit">限速</string>
<string name="dk_weak_network_request_limit">请求限速:</string>
<string name="dk_weak_network_response_limit">响应限速:</string>
<string name="dk_weak_network_limit_message">请求限速会在上传时限速,响应限速会在下载时限速,0则不限速</string>
<string name="dk_back">返回</string>
<string name="dk_frameinfo_ram">RAM</string>
<string name="dk_kit_network_monitor">流量监控</string>
......
......@@ -18,6 +18,7 @@
<string name="dk_kit_temporary_close">隱藏</string>
<string name="dk_kit_crash">Crash 查看</string>
<string name="dk_kit_data_clean">清除 Cache</string>
<string name="dk_kit_weak_network">模擬弱網</string>
<string name="dk_kit_view_check">View 元件檢查</string>
<string name="dk_kit_net_monitor">流量監控</string>
<string name="dk_kit_time_counter">耗時</string>
......@@ -85,6 +86,15 @@
<string name="dk_crash_capture_look">查看 Crash Log</string>
<string name="dk_crash_capture_switch">Crash Log 收集開關</string>
<string name="dk_crash_capture_summary_title">Crash Log 列表</string>
<string name="dk_weak_network_switch">模擬弱網開關</string>
<string name="dk_weak_network_off">斷網</string>
<string name="dk_weak_network_timeout">超時</string>
<string name="dk_weak_network_speed_limit">限速</string>
<string name="dk_weak_network_request_limit">請求限速:</string>
<string name="dk_weak_network_response_limit">響應限速:</string>
<string name="dk_weak_network_limit_message">請求限速會在上傳時限速,響應限速會在下載時限速,0則不限速</string>
<string name="dk_back">返回</string>
<string name="dk_frameinfo_ram">RAM</string>
<string name="dk_kit_network_monitor">流量監控</string>
......
......@@ -18,6 +18,7 @@
<string name="dk_kit_temporary_close">隐藏</string>
<string name="dk_kit_crash">Crash查看</string>
<string name="dk_kit_data_clean">缓存清理</string>
<string name="dk_kit_weak_network">模拟弱网</string>
<string name="dk_kit_view_check">控件检查</string>
<string name="dk_kit_net_monitor">流量监控</string>
<string name="dk_kit_time_counter">耗时</string>
......@@ -89,6 +90,15 @@
<string name="dk_crash_capture_clean_data">一键清理Crash日志</string>
<string name="dk_crash_capture_summary_title">Crash日志列表</string>
<string name="dk_weak_network_switch">模拟弱网开关</string>
<string name="dk_weak_network_off">断网</string>
<string name="dk_weak_network_timeout">超时</string>
<string name="dk_weak_network_speed_limit">限速</string>
<string name="dk_weak_network_request_limit">请求限速:</string>
<string name="dk_weak_network_response_limit">响应限速:</string>
<string name="dk_weak_network_limit_message">请求限速会在上传时限速,响应限速会在下载时限速,0则不限速</string>
<string name="dk_weak_network_speed_unit" translatable="false">K/s</string>
//流量监控
<string name="dk_kit_network_monitor">流量监控</string>
<string name="dk_kit_network_monitor_detail">流量监测详情</string>
......
......@@ -63,11 +63,14 @@ apply plugin: 'android-aspectjx'
```
注:
使用插件有两个目的:1是实现网络请求的自动监控,不需要手动写其他代码。2是可以实现三方jar包内的请求的hook。
使用插件有两个目的:1是实现网络请求的自动监控和模拟弱网功能,不需要手动写其他代码。2是可以实现三方jar包内的请求的hook。
但使用插件会稍微影响到编译速度。如果不需要这个功能,可以通过手动添加DoraemonInterceptor的方式进行OkHttp的监控,如下:
```
OkHttpClient client = new OkHttpClient().newBuilder()
//用于模拟弱网的拦截器
.addNetworkInterceptor(new DoraemonWeakNetworkInterceptor())
//网络请求监控的拦截器
.addInterceptor(new DoraemonInterceptor()).build();
```
#### 4. 自定义功能组件(可选)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册