日期: 2021 年 5 月 12 日

Android 常用的提示框,输入框,弹窗

文章目录

 

  • 环境配置
      • Step 1. Add the JitPack repository to your build file
      • Step 2. Add the dependency
  • 使用方法介绍
          • 1. 选择dialog
          • 2. 确认dialog
          • 3. 可以输入内容的确认框
          • 4.连接dialog
          • 5. 加载dialog
          • 6. 密码输入dialog

环境配置

Step 1. Add the JitPack repository to your build file

Add it in your root build.gradle(Project) at the end of repositories:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

 

Step 2. Add the dependency

Add it in your build.gradle(Module) at the end of dependencies:

dependencies {
   implementation 'com.github.HanHuoBin:BaseDialog:1.2.0'
}

 

使用方法介绍

1. 选择dialog

在这里插入图片描述

ActionSheetDialog dialog = new ActionSheetDialog(this).builder().setTitle("请选择")
        .addSheetItem("相册", null, new ActionSheetDialog.OnSheetItemClickListener() {
            @Override
            public void onClick(int which) {
                showMsg("相册");
            }
        }).addSheetItem("拍照", null, new ActionSheetDialog.OnSheetItemClickListener() {
            @Override
            public void onClick(int which) {
                showMsg("拍照");
            }
        });
dialog.show();

 

2. 确认dialog

在这里插入图片描述

MyAlertDialog myAlertDialog = new MyAlertDialog(this).builder()
        .setTitle("确认吗?")
        .setMsg("删除内容")
        .setPositiveButton("确认", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showMsg("确认");
            }
        }).setNegativeButton("取消", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showMsg("取消");
            }
        });
myAlertDialog.show();

 

在这里插入图片描述

ConfirmDialog confirmDialog = new ConfirmDialog(this);
confirmDialog.setLogoImg(R.mipmap.dialog_notice).setMsg("提示");
confirmDialog.setClickListener(new ConfirmDialog.OnBtnClickListener() {
    @Override
    public void ok() {

    }

    @Override
    public void cancel() {

    }
});
confirmDialog.show();

 

3. 可以输入内容的确认框

在这里插入图片描述

final MyAlertInputDialog myAlertInputDialog = new MyAlertInputDialog(this).builder()
                .setTitle("请输入")
                .setEditText("");
myAlertInputDialog.setPositiveButton("确认", new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        showMsg(myAlertInputDialog.getResult());
        myAlertInputDialog.dismiss();
    }
}).setNegativeButton("取消", new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        showMsg("取消");
        myAlertInputDialog.dismiss();
    }
});
myAlertInputDialog.show();

 

4.连接dialog

在这里插入图片描述

MyImageMsgDialog myImageMsgDialog = new MyImageMsgDialog(this).builder()
        .setImageLogo(getResources().getDrawable(R.mipmap.ic_launcher))
        .setMsg("连接中...");
ImageView logoImg = myImageMsgDialog.getLogoImg();
logoImg.setImageResource(R.drawable.connect_animation);
connectAnimation = (AnimationDrawable) logoImg.getDrawable();
connectAnimation.start();
myImageMsgDialog.show();

 

在这里插入图片描述

ConnectingDialog connectingDialog = new ConnectingDialog(this);
connectingDialog.setMessage("MSG");
connectingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
    @Override
    public void onCancel(DialogInterface dialog) {

    }
});
connectingDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        return false;
    }
});
connectingDialog.show();

 

5. 加载dialog

在这里插入图片描述

LoadingDialog loadingDialog = new LoadingDialog(this);
loadingDialog.setMessage("loading");
loadingDialog.show();

 

6. 密码输入dialog

在这里插入图片描述

final MyPwdInputDialog pwdDialog = new MyPwdInputDialog(this)
        .builder()
        .setTitle("请输入密码");
pwdDialog.setPasswordListener(new MyPwdInputDialog.OnPasswordResultListener() {
    @Override
    public void onPasswordResult(String password) {
        showMsg("您的输入结果:" + password);
        pwdDialog.dismiss();
    }
});
pwdDialog.show();

 

在这里插入图片描述

final MyPayInputDialog myPayInputDialog = new MyPayInputDialog(this).Builder();
myPayInputDialog.setResultListener(new MyPayInputDialog.ResultListener() {
    @Override
    public void onResult(String result) {
        showMsg("您的输入结果:" + result);
        myPayInputDialog.dismiss();
    }
}).setTitle("支付");
myPayInputDialog.show();

 

原文链接:https://www.jianshu.com/p/e3945c7ec38a

Android顶部弹出提示语的三种实现方式

Android顶部弹出提示语的三种实现方式:

WindowManager、PopupWindow、Toast

需求:在主页Activity顶部从上向下滑动出现提示条,且5秒后自动从下向上滑动消失。

自定义布局文件:layout_tips.xml

// layout_tips.xml
<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”120px”
android:paddingStart=”20px”
android:paddingEnd=”20px”
android:gravity=”center”
android:background=”#cc000000″>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_marginTop=”30px”
android:layout_marginBottom=”30px”
android:text=”提示语”
android:textSize=”38px”
android:textColor=”@android:color/white”/>
</LinearLayout>

自定义滑动动画:

<style name=”popwindowAnimStyle” parent=”android:Animation”>
<item name=”android:windowEnterAnimation”>@anim/anim_popup_show</item>
<item name=”android:windowExitAnimation”>@anim/anim_popup_exit</item>
</style>

自定义出现动画:anim_popup_show.xml

<set xmlns:android=”http://schemas.android.com/apk/res/android”>
<translate
android:fromYDelta=”-120%”
android:toYDelta=”0″
android:duration=”400″/>
</set>

自定义消失动画:anim_popup_exit.xml

<set xmlns:android=”http://schemas.android.com/apk/res/android”>
<translate
android:fromYDelta=”0″
android:toYDelta=”-120%”
android:duration=”400″/>
</set>

一、WindowManager实现
优点:可始终显示在当前Activity内所有Fragment、Dialog之上;
缺点:若切换Activity,则被新Activity覆盖。

View contentView = LayoutInflater.from(this).inflate(R.layout.layout_tips, null);
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
if(windowManager != null) {
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | //不拦截页面点击事件
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
layoutParams.format = PixelFormat.TRANSLUCENT;
layoutParams.gravity = Gravity.TOP;
layoutParams.y = (int) getResources().getDimension(R.dimen.y30);
layoutParams.height = (int) getResources().getDimension(R.dimen.y119);
layoutParams.windowAnimations = R.style.popwindowAnimStyle; //自定义动画
windowManager.addView(contentView, layoutParams);

new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if(windowManager != null) {
windowManager.removeViewImmediate(contentView);
windowManager = null;
}
}
}, 3000);
}

二、PopupWindow实现
缺点:会被当前Activity新出现的Fragment、Dialog覆盖。

View contentView = LayoutInflater.from(this).inflate(R.layout.layout_tips, null);
contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
DisplayMetrics dm = getResources().getDisplayMetrics();
PopupWindow popupWindow = new PopupWindow(contentView, dm.widthPixels – contentView.getPaddingStart() * 2,
(int) getResources().getDimension(R.dimen.y120));
popupWindow.setOutsideTouchable(false); //点击外部区域不消失
popupWindow.setTouchable(false);
popupWindow.setBackgroundDrawable(null);
popupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
popupWindow.setAnimationStyle(R.style.popwindowAnimStyle); //自定义动画
popupWindow.showAtLocation(tvShopDeviceName, Gravity.TOP | Gravity.CENTER_HORIZONTAL,
0, (int) getResources().getDimension(R.dimen.y30)); //指定顶部位置

new Handler().postDelayed(new Runnable() {
@Override
public void run() {
popupWindow.dismiss();
}
}, 3000);

三、Toast实现
优点:可始终显示在屏幕*上层,不被新Activity覆盖;
缺点:Android 7.0后无法自定义显示/隐藏动画,默认为渐隐渐现。

View contentView = LayoutInflater.from(this).inflate(R.layout.layout_tips, null);
Toast videoToast = Toast.makeText(this, “”, Toast.LENGTH_LONG);
videoToast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, (int) getResources().getDimension(R.dimen.y30));
videoToast.setView(contentView);
try {
Object mTN = getField(videoToast, “mTN”);
if(mTN != null) {
Object mParams = getField(mTN, “mParams”);
if(mParams instanceof WindowManager.LayoutParams) {
WindowManager.LayoutParams params = (WindowManager.LayoutParams) mParams;
//params.windowAnimations = R.style.popwindowAnimStyle; //自定义动画无效
params.width = dm.widthPixels – contentView.getPaddingStart() * 2;
params.height = (int) getResources().getDimension(R.dimen.y120);
}
}
} catch (Exception e){
e.printStackTrace();
}
videoToast.show();

private Object getField(Object object, String fieldName)
throws NoSuchFieldException, IllegalAccessException{
Field field = object.getClass().getDeclaredField(fieldName);
if(field != null) {
field.setAccessible(true);
return field.get(object);
}
return null;
}

android各种提示Dialog 弹出框

开发过程中 经常需要各种弹出框 用来做提示  或者 展示一些 数据信息。写了一个 DialogUtil , 话不多说 直接上代码 ,希望对大家有帮助。

public static Dialog getProcessDialog(Activity activity, CharSequence message,
boolean dismissTouchOutside, boolean cancelable) {
final LayoutInflater inflater = LayoutInflater.from(activity);
View v = inflater.inflate(R.layout.progress_hud, null);
Dialog dialog = getCustomDialog(activity, v, dismissTouchOutside, cancelable, -1);
if (dismissTouchOutside) {
dialog.setCanceledOnTouchOutside(true);
} else {
dialog.setCanceledOnTouchOutside(false);
}

ImageView spinner = (ImageView) v.findViewById(R.id.spinnerImageView);
((AnimationDrawable) spinner.getBackground()).start();
TextView messageTv = (TextView) v.findViewById(R.id.message);
if (TextUtils.isEmpty(message)) {
messageTv.setVisibility(View.GONE);
} else {
messageTv.setText(message);
messageTv.setVisibility(View.VISIBLE);
}

return dialog;
}

public static Dialog getCustomDialog(final Activity activity, View view, boolean dismissTouchOutside,
boolean cancelable, int theme) {
//Dialog dialog = theme > 0 ? new FullScreenDialogHUD(activity, theme)
// : new Dialog(activity, R.style.Dialog_FullScreen);
Dialog dialog = new Dialog(activity, R.style.Dialog_FullScreen);
dialog.setContentView(view);
dialog.setCancelable(cancelable);
dialog.setCanceledOnTouchOutside(dismissTouchOutside);
if (!cancelable) {
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
dialog.dismiss();
activity.finish();
}
return false;
}
});
}
return dialog;
}

public static Dialog getOneButtonDialog(final Activity activity, String content,
boolean dismissTouchOutside, boolean cancelable,
DialogInterface.OnClickListener confirmOnClickListener) {
Dialog dialog = new AlertDialog.Builder(activity)
.setPositiveButton(R.string.confirm, confirmOnClickListener)
.setCancelable(cancelable)
.setMessage(content)
.create();
dialog.setCanceledOnTouchOutside(dismissTouchOutside);
if (!cancelable) {
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
dialog.dismiss();
activity.finish();
}
return false;
}
});
}
return dialog;
}

public static Dialog getButtonsDialog(Activity activity, int resId,
DialogInterface.OnClickListener confirmOnClickListener) {
return getButtonsDialog(activity, activity.getString(resId), true, true, confirmOnClickListener,
null);
}

public static Dialog getButtonsDialog(Activity activity, String content,
DialogInterface.OnClickListener confirmOnClickListener) {
return getButtonsDialog(activity, content, true, true, confirmOnClickListener, null);
}

public static Dialog getButtonsDialog(Activity activity, String content, boolean dismissTouchOutside,
boolean cancelable, DialogInterface.OnClickListener confirmOnClickListener,
DialogInterface.OnClickListener cancelOnClickListener) {
Dialog dialog = new AlertDialog.Builder(activity)
.setNegativeButton(R.string.cancel, cancelOnClickListener)
.setPositiveButton(R.string.confirm, confirmOnClickListener)
.setCancelable(cancelable)
.setMessage(content)
.create();
dialog.setCanceledOnTouchOutside(dismissTouchOutside);
return dialog;
}

progress_hud.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:orientation=”vertical”
android:gravity=”center_horizontal”
android:background=”@android:color/transparent”>

<ImageView
android:id=”@+id/spinnerImageView”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:background=”@anim/spinner”/>

<TextView
android:id=”@+id/message”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_marginTop=”15dp”
android:textColor=”#FFFFFF”/>

</LinearLayout>

style Dialog_FullScreen
<style name=”Dialog.FullScreen” parent=”Theme.AppCompat.Dialog”>
<item name=”android:windowFrame”>@null</item>
<item name=”android:windowIsFloating”>true</item>
<item name=”android:windowContentOverlay”>@android:color/transparent</item>
<item name=”android:windowAnimationStyle”>@android:style/Animation.Dialog</item>
<item name=”android:windowIsTranslucent”>true</item>
<item name=”android:windowNoTitle”>true</item>
<item name=”android:windowFullscreen”>true</item>
<item name=”android:windowBackground”>@android:color/transparent</item>
<item name=”android:backgroundDimEnabled”>true</item>
</style>

有这些  其他弹出个人信息框 都可以自定义用getCustomDialog这个方法 传 对应的 view 实现。很方便。

希望对大家有帮助。

Android顶部弹出提示的两种实现方式

先给大家上一张效果图:

%title插图%num

越来越多的APP提示越来越花哨,有中间的,有顶部的,有底部的,滑动滑出的,淡入淡出的,今天就先给大家做一个简单的顶部弹出提示效果

其实这是一个很简单的功能,做起来也并不复杂,我们先看使用Toast如何实现

*种:Toast实现

布局文件layout_toast:

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”match_parent”
android:layout_height=”55dp”
android:background=”#ff4959″
android:fitsSystemWindows=”true”
android:orientation=”vertical”>

<LinearLayout
android:id=”@+id/test”
android:layout_width=”match_parent”
android:layout_height=”match_parent”>

<TextView
android:id=”@+id/txtToastMessage”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:gravity=”center”
android:text=”测试测试”
android:textColor=”#ffffff”
android:textSize=”18sp” />
</LinearLayout>

</LinearLayout>
就一个简单的文本嵌套,就不多说了

然后我们再看Java代码实现

if (mToast == null) {
mToast = new Toast(mContext);
}
mToast.setDuration(Toast.LENGTH_SHORT);
mToast.setGravity(Gravity.TOP, 0, 0);
View toastView = LayoutInflater.from(mContext).inflate(R.layout.layout_toast, null);
mToast.setView(toastView);
mToast.show();
运行程序我们发现并没有我们想要的效果,而是在顶部自适应显示

%title插图%num

我们已经setView了但是并没有根据我们的布局显示我们想要的效果,原因是什么呢?通过看源码我们发现Toas并没有设置宽高的方法,而且其宽高是根据内容的大小而自适应的,所以只能自己写了。

既然没有设置宽高的方法, 那我们是否可以通过setView(View)方法动态定义View的宽高来实现呢,想到就要做,于是我这样写

WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
View toastView = LayoutInflater.from(mContext).inflate(R.layout.layout_toast, null);
if (mToast == null) {
mToast = new Toast(mContext);
}
LinearLayout relativeLayout = (LinearLayout) toastView.findViewById(R.id.test);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(wm
.getDefaultDisplay().getWidth(), dip2px(mContext, 60));
relativeLayout.setLayoutParams(layoutParams);
mToast.setDuration(Toast.LENGTH_SHORT);
mToast.setGravity(Gravity.TOP, 0, 0);
mToast.setView(toastView);
mToast.show();
果然动态设置宽高后效果就实现了,但是这样有一个问题需要大家注意下

不能设置布局文件的根节点的宽高度,这一样无效,因此需要设置LinearLayout的宽高度
不能设置布局文件的根节点的宽高度,这一样无效,因此需要设置LinearLayout的宽高度
不能设置布局文件的根节点的宽高度,这一样无效,因此需要设置LinearLayout的宽高度
所以我在Textview上面包了一层

第二种:Popwindow实现

相对于Toast来说Popwindow实现起来就方便多了,我们只要有布局文件,只需要设置一下就可以实现跟上个相同的效果,关键代码如下:

// 把View添加到PopWindow中
this.setContentView(mPopWindow);
//设置SelectPicPopupWindow弹出窗体的宽
this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
//设置SelectPicPopupWindow弹出窗体的高
this.setHeight(dip2px(mContext, 60));
// 设置SelectPicPopupWindow弹出窗体可点击
this.setFocusable(false);
// 设置背景透明
this.setBackgroundDrawable(new ColorDrawable(0x00000000));
点击测试:

popUtil = new PopUtil(MainActivity.this, “我是POP测试”);
new CountDownTimer(2000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
popUtil.showAtLocation(MainActivity.this.findViewById(R.id.pop),
Gravity.TOP, 0, 0);
}

@Override
public void onFinish() {
popUtil.dismiss();
}
}.start();
我这里做了一个两秒的倒计时,两秒后自动取消PopWindow,跟Toast功能相同

结语:

其实延伸开还有很多效果可以实现,例如淡入淡出的动画效果,这就需要大家去开动脑筋去实现了

Demo地址  https://github.com/cuiyongtao/MyToast

Android全局异常捕获并弹窗提示

Android 难免有崩溃的时候,但是崩溃了该如何处理呢?虽然那天有位同仁说 “既然崩溃了,用户体验就差了,心里会想这是毛APP,下次也不想用了” ,所以检查BUG以防崩溃是必须的,但是也需要一个后备方案,崩溃了能友好些,我们也能收集一些崩溃的信息。
说到全局捕获异常的UncaughtExceptionHandler,就不得不说期间遇到的各种坑:
1. 初始化肯定在Application,网上说的Activity启各种不认同。但在Application启就存在不能弹AlertDialog的问题(目前不确定,不知道是自己哪里没处理好还是的确是这个问题,有时间再验证一下)
2. 崩溃不一定是单次,在多层Activity中,崩溃一个顶层的Activity可能导致下层的Activity连续崩溃,所以uncaughtException可能会捕获到多次崩溃信息(具体影响后面会说到)
先来张崩溃后的效果图:
背景是另一个APP,当前的APP已崩溃并弹出该提示

%title插图%num
实现流程:
写个类继承于UncaughtExceptionHandler,实现方法
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处
mDefaultHandler.uncaughtException(thread, ex);
} else {
// 跳转到崩溃提示Activity
Intent intent = new Intent(mContext, CrashDialog.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
System.exit(0);// 关闭已奔溃的app进程
}
}

然后转handleException方法处理异常:
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}

// 收集错误信息
getCrashInfo(ex);

return true;
}

上面的代码很清楚了,如果异常被捕获到并且异常信息不会NULL,处理完则跳转到CrashDialog。为什么跳Activity用Dialog样式,而不直接弹AlertDialog,是因为的确弹不出来。
收集错误信息:
private void getCrashInfo(Throwable ex) {
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
printWriter.close();
String errorMessage = writer.toString();
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String mFilePath = Environment.getExternalStorageDirectory() + “/” + App.ERROR_FILENAME;
FileTxt.WirteTxt(mFilePath, FileTxt.ReadTxt(mFilePath) + ‘\n’ + errorMessage);
} else {
Log.i(App.TAG, “哦豁,说好的SD呢…”);
}
}

是的,我把错误信息写到了存储并在刚才的CrashDialog中读取。为什么不直接传值呢?因为刚说到的坑第2条,多次崩溃的情况下,将导致直接传值只会传*后一次崩溃信息,而*后一次崩溃信息并不是主要引发崩溃的点,收集上来的错误信息可读性不大。那为什么我不写个全局变量来存储呢?因为尝试过,不知道是机型问题(Huawei Mate7 – API 23)还是全部问题,变量压根就不记录数据,*后只有将信息依次写到存储。
主要代码
App.java
package cn.qson.androidcrash;

/**
* @author x024
*/

import android.app.Application;

public class App extends Application {

public final static String TAG = “x024”;
public final static String ERROR_FILENAME = “x024_error.log”;

@Override
public void onCreate() {
super.onCreate();

CrashHanlder.getInstance().init(this);

}
}

CrashHanlder.java
package cn.qson.androidcrash;

/**
* @author x024
*/

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;

import android.content.Context;
import android.content.Intent;
import android.os.Environment;
import android.util.Log;

/**
* 收集错误报告并上传到服务器
*
* @author x024
*
*/
public class CrashHanlder implements UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler mDefaultHandler;
// CrashHandler实例
private static CrashHanlder INSTANCE = new CrashHanlder();
// 程序的Context对象
private Context mContext;

private CrashHanlder() {
}

public static CrashHanlder getInstance() {
return INSTANCE;
}

/**
* 初始化
*
* @param context
*/
public void init(Context context) {
mContext = context;
// 获取系统默认的UncaughtException处理
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 设置该CrashHandler为程序的默认处理
Thread.setDefaultUncaughtExceptionHandler(this);
}

/**
* 异常捕获
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处
mDefaultHandler.uncaughtException(thread, ex);
} else {
// 跳转到崩溃提示Activity
Intent intent = new Intent(mContext, CrashDialog.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
System.exit(0);// 关闭已奔溃的app进程
}
}

/**
* 自定义错误捕获
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}

// 收集错误信息
getCrashInfo(ex);

return true;
}

/**
* 收集错误信息
*
* @param ex
*/
private void getCrashInfo(Throwable ex) {
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
printWriter.close();
String errorMessage = writer.toString();
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String mFilePath = Environment.getExternalStorageDirectory() + “/” + App.ERROR_FILENAME;
FileTxt.WirteTxt(mFilePath, FileTxt.ReadTxt(mFilePath) + ‘\n’ + errorMessage);
} else {
Log.i(App.TAG, “哦豁,说好的SD呢…”);
}

}

}

CrashDialog.java
package cn.qson.androidcrash;

/**
* @author x024
*/

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class CrashDialog extends Activity {

private String mFilePath;
private Button btnExit, btnRestart;
private Boolean StorageState = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crash);
CrashDialog.this.setFinishOnTouchOutside(false);
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
mFilePath = Environment.getExternalStorageDirectory() + “/” + App.ERROR_FILENAME;
StorageState = true;
} else {
Log.i(App.TAG, “哦豁,说好的SD呢…”);
}

new Thread(upLog).start();
initView();
}

private void initView() {
btnExit = (Button) findViewById(R.id.cash_exit);
btnRestart = (Button) findViewById(R.id.cash_restart);

btnExit.setOnClickListener(mOnClick);
btnRestart.setOnClickListener(mOnClick);

}

OnClickListener mOnClick = new OnClickListener() {

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.cash_exit:
exit();
break;
case R.id.cash_restart:
restart();
break;
default:
break;
}
}
};

// 上传错误信息
Runnable upLog = new Runnable() {
@Override
public void run() {
try {

String Mobile = Build.MODEL;
String maxMemory = “” + getmem_TOLAL() / 1024 + “m”;
String nowMemory = “” + getmem_UNUSED(CrashDialog.this) / 1024 + “m”;
String eMessage = “未获取到错误信息”;
if (StorageState) {
eMessage = FileTxt.ReadTxt(mFilePath).replace(“‘”, “”);
}
Log.i(App.TAG, “Mobile:” + Mobile + ” | maxMemory:” + maxMemory + ” |nowMemory:” + nowMemory
+ ” |eMessage:” + eMessage);

/**
* 可以在这调你自己的接口上传信息
*/
} catch (Exception e) {
e.printStackTrace();
}
}
};

private void exit() {
FileTxt.deleteFile(mFilePath);
System.exit(0);
android.os.Process.killProcess(android.os.Process.myPid());
}

private void restart() {
Intent intent = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(getBaseContext().getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
exit();
}

@Override
public void onBackPressed() {
super.onBackPressed();
exit();
}

// 获取可用内存
public static long getmem_UNUSED(Context mContext) {
long MEM_UNUSED;
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
am.getMemoryInfo(mi);

MEM_UNUSED = mi.availMem / 1024;
return MEM_UNUSED;
}

// 获取剩余内存
public static long getmem_TOLAL() {
long mTotal;
String path = “/proc/meminfo”;
String content = null;
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(path), 8);
String line;
if ((line = br.readLine()) != null) {
content = line;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
int begin = content.indexOf(‘:’);
int end = content.indexOf(‘k’);

content = content.substring(begin + 1, end).trim();
mTotal = Integer.parseInt(content);
return mTotal;
}

}

完整代码:http://download.csdn.net/detail/hx7013/9710757

android中常用的弹出提示框

我们在平时做开发的时候,免不了会用到各种各样的对话框,相信有过其他平台开发经验的朋友都会知道,大部分的平台都只提供了几个*简单的实现,如果我们想实现自己特定需求的对话框,大家可能首先会想到,通过继承等方式,重写我们自己的对话框。当然,这也是不失为一个不错的解决方式,但是一般的情况却是这样,我们重写的对话框,也许只在一个特定的地方会用到,为了这一次的使用,而去创建一个新类,往往有点杀鸡用牛刀的感觉,甚至会对我们的程序增加不必要的复杂性,对于这种情形的对话框有没有更优雅的解决方案呢?
幸运的是,android提供了这种问题的解决方案,刚开始接触android的时候,我在做一个自定义对话框的时候,也是通过继承的方式来实现,后来随着对文档了解的深入,发现了android起始已经提供了相应的接口Dialog Builder ,下面我就吧相关的内容在这里分享一下,也能让更多的初学者少走弯路。

首先是一个*简单的应用,就是弹出一个消息框,在android中可以这样实现

view plain copy to clipboard print ?
  1. 1
  2. new  AlertDialog.Builder(self)
  3. 2
  4.                 .setTitle(“标题” )
  5. 3
  6.                 .setMessage(“简单消息框” )
  7. 4
  8.                 .setPositiveButton(“确定” ,  null )
  9. 5
  10.                 .show();
效果如下:

1.png

上面的代码中我们新建了一个AlertDialog,并用Builder方法形成了一个对象链,通过一系列的设置方法,构造出我们需要的对话框,然后调用 show方法显示出来,注意到Builder方法的参数 self,这个其实是Activity对象的引用,根据你所处的上下文来传入相应的引用就可以了。例如在onCreate方法中调用,只需传入this即可。

下面是带确认和取消按钮的对话框

  1. view plain copy to clipboard print ?
    1. new  AlertDialog.Builder(self)
    2. .setTitle(“确认” )
    3. .setMessage(“确定吗?” )
    4. .setPositiveButton(“是” ,  null )
    5. .setNegativeButton(“否” , null)
    6. .show();
    复制代码

2.png

注意到,这里有两个null参数,这里要放的其实是这两个按钮点击的监听程序,由于我们这里不需要监听这些动作,所以传入null值简单忽略掉,但是实际开发的时候一般都是需要传入监听器的,用来响应用户的操作。

下面是一个可以输入文本的对话框

  1. view plain copy to clipboard print ?
    1. new  AlertDialog.Builder(self)
    2. .setTitle(“请输入” )
    3. .setIcon(android.R.drawable.ic_dialog_info)
    4. .setView(new  EditText(self))
    5. .setPositiveButton(“确定” , null)
    6. .setNegativeButton(“取消” ,  null )
    7. .show();

    3.png

    如上代码,我们用setView方法,为我们的对话框传入了一个文本编辑框,当然,你可以传入任何的视图对象,比如图片框,WebView等。。尽情发挥你的想象力吧~:lol

    下面是单选框与多选框,也是非常有用的两种对话框

  1. view plain copy to clipboard print ?
    1. new  AlertDialog.Builder(self)
    2. .setTitle(“请选择” )
    3. .setIcon(android.R.drawable.ic_dialog_info)
    4. .setSingleChoiceItems(new  String[] {“选项1”“选项2”“选项3” , “选项4” },  0 ,
    5.   new  DialogInterface.OnClickListener() {
    6.      public   void  onClick(DialogInterface dialog,  int  which) {
    7.         dialog.dismiss();
    8.      }
    9.   }
    10. )
    11. .setNegativeButton(“取消” ,  null )
    12. .show();


4.png

  1. view plain copy to clipboard print ?
    1. new  AlertDialog.Builder(self)
    2. .setTitle(“多选框” )
    3. .setMultiChoiceItems(new  String[] {“选项1”“选项2”“选项3” , “选项4” },  null ,  null )
    4. .setPositiveButton(“确定” , null)
    5. .setNegativeButton(“取消” ,  null )
    6. .show();

    多选对话框

    单选和多选对话框应该是我们平时用的非常多的,代码应该很好理解,下面再*后介绍两个、

    列表对话框

  1. view plain copy to clipboard print ?
    1. new  AlertDialog.Builder(self)
    2. .setTitle(“列表框” )
    3. .setItems(new  String[] {“列表项1”“列表项2”“列表项3” },  null )
    4. .setNegativeButton(“确定” ,  null )
    5. .show();

    6.png

    *后,在对话框中显示图片

  1. view plain copy to clipboard print ?
    1. ImageView img =  new ImageView(self);
    2. img.setImageResource(R.drawable.icon);
    3. new  AlertDialog.Builder(self)
    4. .setTitle(“图片框” )
    5. .setView(img)
    6. .setPositiveButton(“确定” ,  null )
    7. .show();
    7.png

    我们传入了一个ImageView来显示图片,这里显示了一个经典的android小绿人图标~ ~,当然这里还可以放上网络图片,具体的实现方法就不介绍了,留给大家来练习吧~:lol

    *后总结一下,android平台为我们开发提供了*大的便利,DialogBuilder能做的不止这些,这里给大家展示的只是冰山一角,我们可以尽情的发挥想象,创造我们自己的对话框。

Linux中高效编写Bash脚本的9个小技巧

Shell 脚本编程 是你在 Linux 下学习或练习编程的*简单的方式。尤其对 系统管理员要处理着自动化任务,且要开发新的简单的实用程序或工具等(这里只是仅举几例)更是必备技能。本文中,我们将分享 9个写出高效可靠的 bash 脚本的实用技巧。

 

1脚本中多写注释

这是不仅可应用于 shell 脚本程序中,也可用在其他所有类型的编程中的一种推荐做法。在脚本中作注释能帮你或别人翻阅你的脚本时了解脚本的不同部分所做的工作。

对于刚入门的人来说,注释用 # 号来定义。

 # TecMint 是浏览各类 Linux 文章的*佳站点

2当运行失败时使脚本退出

有时即使某些命令运行失败,bash 可能继续去执行脚本,这样就影响到脚本的其余部分(会*终导致逻辑错误)。用下面的行的方式在遇到命令失败时来退出脚本执行:

 # 如果命令运行失败让脚本退出执行 set -o errexit
   # 或 set -e

3当 Bash 用未声明变量时使脚本退出

Bash 也可能会使用能导致起逻辑错误的未声明的变量。因此用下面行的方式去通知 bash 当它尝试去用一个未声明变量时就退出脚本执行:

# 若有用未设置的变量即让脚本退出执行
 set -o nounset # 或 set -u

4 使用双引号来引用变量

当引用时(使用一个变量的值)用双引号有助于防止由于空格导致单词分割开和由于识别和扩展了通配符而导致的不必要匹配。

看看下面的例子:

        #!/bin/bash     
    # 若命令失败让脚本退出 
    set -o errexit  
    # 若未设置的变量被使用让脚本退出 
    set -o nounset 
    echo "Names without double quotes"  
    echo names="Tecmint FOSSMint Linusay" 
    for name in $names; 
    do   
        echo "$name" 
    done 
    
    echo echo "Names with double quotes"  
    echo 
    for name in "$names"; 
    do   
        echo "$name" 
    done exit 0

保存文件并退出,接着如下运行一下:

 $ ./names.sh

640?wx_fmt=png

在脚本中用双引号

5 在脚本中使用函数

除了非常小的脚本(只有几行代码),总是记得用函数来使代码模块化且使得脚本更可读和可重用。

写函数的语法如下所示:

  function check_root(){   
      command1;    
      command2; 
   } 
   # 或 
   check_root(){   
       command1;    
       command2; 
   }

写成单行代码时,每个命令后要用终止符号:

check_root(){ command1; command2; }

6 字符串比较时用 = 而不是 ==

注意 == 是 = 的同义词,因此仅用个单 = 来做字符串比较,例如:

1请输入标题value1=”tecmint.com”     
value2=”fossmint.com” 
if [ "$value1" = "$value2" ]

7 用 $(command)  来做代换

命令代换 是用这个命令的输出结果取代命令本身。用 $(command) 而不是引号 `command` 来做命令代换。

这种做法也是 shellcheck tool (可针对 shell 脚本显示警告和建议)所建议的。例如:

 user=`echo “$UID”` 
 user=$(echo “$UID”)

8用 readonly 来声明静态变量

静态变量不会改变;它的值一旦在脚本中定义后不能被修改:

 readonly passwd_file=”/etc/passwd” 
 readonly group_file=”/etc/group”

 

9环境变量用大写字母命名,而自定义变量用小写

所有的 bash 环境变量用大写字母去命名,因此用小写字母来命名你的自定义变量以避免变量名冲突:

  1. # 定义自定义变量用小写,而环境变量用大写
  2. nikto_file=”$HOME/Downloads/nikto-master/program/nikto.pl”
  3. perl “$nikto_file” -h “$1”

怎么深入学云计算Linux 编写bash脚本有哪些技巧

怎么深入学云计算Linux?编写bash脚本有哪些技巧?很多同学反映,常常被Linux中的shell脚本困扰,各种不同的脚本编程让人无从下手。其实只要你找对方法,掌握shell脚本还是很轻松的。一般情况下,我们都是使用bash(bourne again shell)进行shell编程,因为bash是免费的并且很容易使用。接下来就给大家分享bash脚本编写技巧。

%title插图%num

 

1、当运行失败时使脚本退出

有时即使某些命令运行失败,bash也会继续去执行脚本,这样就影响到脚本的其余部分,*终导致逻辑错误。这时我们就要退出脚本执行:

# 如果命令运行失败让脚本退出执行

set -o errexit

# 或

set -e

2、脚本中多写注释

这不仅可应用于shell脚本程序中,也可用在其他所有类型的编程中。在脚本中作注释能帮你或别人翻阅你的脚本时了解脚本的不同部分所做的工作。对于刚入门的人来说,注释用#号来定义。

3、字符串比较时用 = 而不是 ==

注意 == 是 = 的同义词,因此仅用个单 = 来做字符串比较,例如:

value1=”tecmint.com”

value2=”fossmint.com”

if [ “$value1” = “$value2” ]

4、当bash用未声明变量时使脚本退出

bash可能会使用能导致起逻辑错误的未声明的变量,你可以用下面行的方式去通知bash当它尝试去用一个未声明变量时就退出脚本执行:

# 若有用未设置的变量即让脚本退出执行

set -o nounset

# 或

set -u

5、用readonly来声明静态变量

静态变量不会改变,它的值一旦在脚本中定义后不能被修改:

readonly passwd_file=”/etc/passwd”

readonly group_file=”/etc/group”

6、环境变量用大写字母命名,而自定义变量用小写

所有的bash环境变量用大写字母去命名,因此用小写字母来命名你的自定义变量以避免变量名冲突:

# 定义自定义变量用小写,而环境变量用大写

nikto_file=”$HOME/Downloads/nikto-master/program/nikto.pl”

perl “$nikto_file” -h “$1”

7、使用双引号来引用变量

当引用时(使用一个变量的值)用双引号有助于防止由于空格导致单词分割开和由于识别和扩展了通配符而导致的不必要匹配。

8、启用shell脚本调试模式的方法

-v(verbose 的简称),告诉shell读取脚本时显示所有行,激活详细模式。

-n (noexec 或 no ecxecution 简称),指示shell读取所有命令然而不执行它们,这个选项激活语法检查模式。

-x (xtrace 或 execution trace 简称),告诉shell在终端显示所有执行的命令和它们的参数,这个选项是启用shell跟踪模式。

调用shell调试选项:$ shell 选项 参数1 … 参数N

启用调试模式:$ set -选项

禁用调试模式:$ set +选项

随着开源软件的流行以及互联网的高速发展,Linux得到了企业的广泛重视,HR在招聘云计算人才时也会考核其对Linux的掌握程度。如果你想更深入的学习Linux、快速掌握高薪云计算人才所需的技能,可以选择专业的学习。

每个运维人员应该知道的 10 个 Linux 命令!

Linux是一个用户必须理解和维护的系统,所以日常体验就像向水坑加水滴一样。时间一长,水坑就会成为湖泊,甚至是海洋。所以我们必须杜微慎防。

在这篇内容中,将分享一些不太受欢迎但非常有用的Linux命令,个人*力推荐。如果你是在Macbook上工作,那也没关系,因为提到的大部分命令也存在于OSX系统中。

640?wx_fmt=jpeg

10file

返回给定文件的信息。例如,你可以输出图像的尺寸信息:

file logo.png

返回:

> PNG image data, 16 x 16, 8-bit/color RGBA, non-interlaced

9iotop,powertop,nethogs

你怎么监控Linux系统中正在发生的情况?这三个命令是你的救星:

  • iotop:通过磁盘写入对进程进行排序,并显示程序写入磁盘的次数和频率。
  • powertop:通过能量消耗列出流程。当你在外面,在某个地方你不能为笔记本电脑充电的地方时,这是一个至关重要的命令。
  • nethogs:通过网络流量列出进程。

8tee

它会分割程序的输出,从而可以打印和保存。例如,添加一个新的条目到hosts文件;

echo “127.0.0.1 foobar” | sudo tee -a /etc/hosts

7pidof,kill和pkill

这三个重要的命令可以帮助你控制系统中的运行程序。

pidof打印出正在运行的程序的进程ID。例如,以下命令将输出nginx的进程ID:

pidof nginx

你可以通过kill命令杀死nginx:

kill -USR2 $(pidof nginx)’

pkill是一个快捷命令,可以杀死进程匹配模式:

pkill -f nginx

6tmux

如果还没有安装tmux的话,那么你必须安装。Tmux是终端的优秀窗口和会话管理器。

5tree

以树状格式列出目录的内容。它有整洁的选项,如只显示目录;

tree -d

4find

当我们正在数十个文件中寻找特定文件时,这个命令就是救星。我将在这里介绍几个简单的用例。

示例1:列出所有CSS文件(包括子目录):

find . -type f -name “*.css”

示例2:列出所有CSS或HTML文件:

find . -type f name.cssorname.html−name”∗.css”−or−name”∗.html”

3htop

有名的过程监控。它有一个漂亮又多彩的命令行界面。一些有用的键绑定:

  • \过滤器
  • /搜索
  • ,选择排序条件
  • k发送杀死信号
  • u用户过滤结果
  • t打开/关闭树模式
  • -和+ 折叠 / 展开选定的流程树
  • H关闭显示线程

2chroot

很多人喜欢这个命令,是因为它在给定的目录中打开了一个新的TTY。这意味着,你可以创建一个文件夹,在其中设置一个新的Linux系统,并随时切换到该“子系统”。

是不是很强大?

1dialog

在命令行上与用户交互的一种非常简单又良好的方式。例如,下面的命令展示了一个不错的输入框:

dialog –title “Oh hey” –inputbox “Howdy?” 8 55

它既存在于Linux,也存在于OSX系统上,并支持许多其他类型的对话框;消息框,菜单,确认,进度条…我为Happy Hacking Linux编写的安装向导就是用这个令人惊叹的命令制作的!

怎么学Linux匿名管道

云计算人才要会哪些技能?怎么学Linux匿名管道?云计算产业的迅猛发展催生了大量的人才需求,为了能够快速的入行,很多人选择专业学习。接下来小编就给大家分享云计算入门学习中有关Linux匿名管道的知识点。

%title插图%num

 

什么是管道呢?

管道实际上就是内核中的一块缓冲区,通过进程从管道中放数据,取数据来完成进程中数据资源的传输。管道的特点是:单向通信,也就是说传输数据的一方,就只能传输数据,接收数据就只能接收数据。

匿名管道,就是没有名字的管道,没有名字两个不相干的进程是无法传输数据的。所以匿名管道的适用范围就是父子进程等有亲缘关系的进程间通信。

匿名管道特点

1)管道是半双工单向通信(即数据只能在一个方向上流动),具有固定的读端和写端。需要双方通信时,需要建立两个管道;

2)只能用于具有亲缘关系的进程之间的通信(父子进程或者兄弟进程之间);通常,一个管道由一个进程创建,然后该进程调用fork,此后父子进程之间就可应用该管道;

3)生命周期随进程,进程退出,管道释放;

4)面向字节流;

5)可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。

如何创建和使用匿名管道?

创建管道

函数原型:

BOOLWINAPICreatePipe(

PHANDLEhReadPipe,

PHANDLEhWritePipe,

LPSECURITY_ATTRIBUTESlpPipeAttributes,

DWORDnSize

);

函数说明:

*个参数返回新创建的管道的读取端句柄;

第二个参数返回新创建的管道的写入端句柄。注意不能在管道的读取端写入数据也不能在写入端读取数据;

第三个参数表示管道的安全属性,通常可以作如下设置:

SECURITY_ATTRIBUTES sa;

sa.nLength

= sizeof(SECURITY_ATTRIBUTES);

sa.lpSecurityDescriptor

= NULL;

sa.bInheritHandle

= TRUE;

第四个参数表示管道的缓冲区容量,为0表示使用默认大小。函数执行成功返回TRUE,否则返回FALSE。

从管道中读取数据

函数原型:

BOOLReadFile(

HANDLEhFile,

LPVOIDlpBuffer,

DWORDnNumberOfBytesToRead,

LPDWORDlpNumberOfBytesRead,

LPOVERLAPPEDlpOverlapped

);

函数说明:

*个参数为句柄,可以是创建文件函数CreateFile()的返回值也可以是管道;

第二个参数是一个指向缓冲区的指针,函数将读取的数据写入该缓冲区;

第三个参数的表达非常好,光从名字上就可以知道这是用来指定读取的字节数;

第四个参数将返回实际读取到的字节数;

第五个参数是用于异步操作方面,一般传入NULL即可。

向管道写入数据

函数原型:

BOOLWriteFile(

HANDLEhFile,

LPCVOIDlpBuffer,

DWORDnNumberOfBytesToWrite,

LPDWORDlpNumberOfBytesWritten,

LPOVERLAPPEDlpOverlapped

);

函数说明:

*个参数为句柄,可以是创建文件函数CreateFile()的返回值也可以是管道。

第二个参数是一个指针,该指针指向待写入管道的数据。

第三个参数表示要写入的字节数。

第四个参数将返回实际写入管道的字节数。

第五个参数是用于异步操作方面,一般传入NULL即可。

关闭管道的一端

函数原型:BOOLCloseHandle(HANDLEhObject);

函数说明:当读取和写入端都关闭后,系统会关闭管道并回收资源。

一个合格的云计算人才需要掌握很多技能,比如Linux、网络工程师、Python运维、云计算、OpenStack、Doctor容器技术等。如果你想快速掌握这些技能,可以选择专业的学习。

 

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速