Android--qq是怎么做到程序出qt 异常捕获 防止崩溃崩溃了界面都不会挂的

Android 如何收集已发布程序的崩溃信息
字体:[ ] 类型:转载 时间:
下面我就说说如何收集程序运行过程的异常信息。需要的朋友可以过来参考下
我们写程序的时候都希望能写出一个没有任何Bug的程序,期望在任何情况下都不会发生程序崩溃。不过理想是丰满的,现实是骨感的。没有一个程序员能保证自己写的程序绝对不会出现异常崩溃。特别是针对用户数达到几十万几百万的程序,当你用户数达到一定数量级后,就算你的程序出现个别异常崩溃情况也不用惊讶。既然我们写的程序都有可能发生异常崩溃,如果是还没发布的程序,我们可以通过测试抓取Log来分析。不过针对已经发布的程序,我们没法重现现象,所以让用户反馈程序异常信息就很重要。下面我们说说如何收集程序运行过程的异常信息。
1、Android异常捕获接口 代码如下://当线程因未捕获的异常而突然终止时,调用处理程序的接口static interface UncaughtExceptionHandler2、设置线程捕获异常从上面的接口我们可以看到,这个接口是针对线程来说,也就是说我们如果需要监控某个线程运行情况,只要把这个接口实现了,然后把监控方法设置到具体的线程里面即可。一般来说,我们最需要监控的就是我们的UI线程也就是主线程。 代码如下://设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) 3、UncaughtExceptionHandler 实例 代码如下:class MythouCrashHandler implements UncaughtExceptionHandler {&&& private static final String TAG = "MythouCrashHandler----&";&&& private UncaughtExceptionHandler defaultUEH;  //构造函数,获取默认的处理方法&&& public MythouCrashHandler() &&& {&&&&&&& this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();&&& }  //这个接口必须重写,用来处理我们的异常信息&&& @Override&&& public void uncaughtException(Thread thread, Throwable ex) &&& {&&&&&&& final Writer result = new StringWriter();&&&&&&& final PrintWriter printWriter = new PrintWriter(result);     //获取跟踪的栈信息,除了系统栈信息,还把手机型号、系统版本、编译版本的唯一标示&&&&&&& StackTraceElement[] trace = ex.getStackTrace();&&&&&&& StackTraceElement[] trace2 = new StackTraceElement[trace.length+3];&&&&&&& System.arraycopy(trace, 0, trace2, 0, trace.length);&&&&&&& trace2[trace.length+0] = new StackTraceElement("Android", "MODEL", android.os.Build.MODEL, -1);&&&&&&& trace2[trace.length+1] = new StackTraceElement("Android", "VERSION", android.os.Build.VERSION.RELEASE, -1);&&&&&&& trace2[trace.length+2] = new StackTraceElement("Android", "FINGERPRINT", android.os.Build.FINGERPRINT, -1);    //追加信息,因为后面会回调默认的处理方法&&&&&&& ex.setStackTrace(trace2);&&&&&&& ex.printStackTrace(printWriter);     //把上面获取的堆栈信息转为字符串,打印出来&&&&&&& String stacktrace = result.toString();&&&&&&& printWriter.close();&&&&&&& Log.e(TAG, stacktrace);&&&&&&& //这里把刚才异常堆栈信息写入SD卡的Log日志里面&&&&&&& if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) &&&&&&& {&&&&&&&&&&& String sdcardPath = Environment.getExternalStorageDirectory().getPath();&&&&&&&&&&& writeLog(stacktrace, sdcardPath + "/mythou");&&&&&&& }&&&&&&& defaultUEH.uncaughtException(thread, ex);&&& }  //写入Log信息的方法,写入到SD卡里面&&& private void writeLog(String log, String name) &&& {&&&&&&& CharSequence timestamp = DateFormat.format("yyyyMMdd_kkmmss", System.currentTimeMillis());&&&&&&& String filename = name + "_" + timestamp + ".log";&&&&&&& try &&&&&&& {&&&&&&&&&&& FileOutputStream stream = new FileOutputStream(filename);&&&&&&&&&&& OutputStreamWriter output = new OutputStreamWriter(stream);&&&&&&&&&&& BufferedWriter bw = new BufferedWriter(output);       //写入相关Log到文件&&&&&&&&&&& bw.write(log);&&&&&&&&&&& bw.newLine();&&&&&&&&&&& bw.close();&&&&&&&&&&& output.close();&&&&&&& } &&&&&&& catch (IOException e) &&&&&&& {&&&&&&&&&&& e.printStackTrace();&&&&&&& }&&& }}上面就是实现了获取处理跟踪信息的方法,上面的方法是参照VLC的异常处理机制编写的。做了一些简单修改。不过上面只是获取了异常信息,如果程序安装到用户机器上,我们没法获取到这些信息,总不能让用户把机器拿过来给你,然后你把Log拷贝出来吧。(这个我以前做嵌入式的时候到试过,让客户把机器拿过来,拷贝里面的Log,那时候做的机器无法联网。现在想起来都纠结,O(∩_∩)O哈哈~) 为了不再纠结,我们需要一个可以把Log发送到我们服务器的功能,下面是把一个服务信息发送到我们指定服务器功能。3、通过网络发送Log 代码如下:   public class SendCrashLog extends AsyncTask&String, String, Boolean& &&& {&&&&&&& public SendCrashLog() { }&&&&&&& @Override&&&&&&& protected Boolean doInBackground(String... params) &&&&&&& {&&&&&&&&&&& if (params[0].length() == 0)&&&&&&&&&&&&&&&&&&&&&&&&&& HttpClient httpClient = new DefaultHttpClient();       //你的服务器,这里只是举个例子。把异常信息当作http请求发送到服务器&&&&&&&&&&& HttpPost httpPost = new HttpPost("http://www.mythou/getlog.php");       //这里把相关的异常信息转为http post请求的数据参数&&&&&&&&&&& try {&&&&&&&&&&&&&&& List&NameValuePair& nameValuePairs = new ArrayList&NameValuePair&(1);&&&&&&&&&&&&&&& nameValuePairs.add(new BasicNameValuePair("model", params[0]));&&&&&&&&&&&&&&& nameValuePairs.add(new BasicNameValuePair("device", params[1]));&&&&&&&&&&&&&&& httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));         //发送相关请求信息&&&&&&&&&&&&&&& httpClient.execute(httpPost);&&&&&&&&&&& } catch (ClientProtocolException e) {&&&&&&&&&&&&&&& e.printStackTrace();&&&&&&&&&&&&&&&&&&&&&&&&&& } catch (IOException e) {&&&&&&&&&&&&&&& e.printStackTrace();&&&&&&&&&&&&&&&&&&&&&&&&&& }&&&&&&&&&&& Log.d(TAG, "Device model sent.");&&&&&&&&&&&&&&&&&& }&&&&&&& @Override&&&&&&& protected void onPostExecute(Boolean result) {&&&&&&& }&&& }上面就是我上一篇文章讲的异步任务的使用,我们在异步任务里面编写了一个发送http请求的服务,用来把相关的异常信息发送到我们指定的服务器上面。这个需要你的服务器解析发送的http请求,这个难度不大,一般做个web的人都知道如何做。在上面的异常处理里面再调用这里的发送方法: 代码如下:SendCrashLogsendLog = new SendCrashLog();//刚才的异常信息字符串sendLog .execute(stacktrace);通过上面的方法就可以把异常信息发送到指定的服务器,也就可以跟踪客户使用软件的情况,方便我们修改程序的问题。当然这个信息收集一般都隐私和后台流量问题,这个需要在程序里面做点提示,免得背上流氓软件的骂名。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具android-adb捕获崩溃异常(4)
我自己写的Demo:
1.以下为异常捕捉处理代码
import java.io.BufferedR
import java.io.F
import java.io.FileInputS
import java.io.FileNotFoundE
import java.io.FileOutputS
import java.io.IOE
import java.io.InputStreamR
import java.io.PrintW
import java.io.StringW
import java.io.W
import java.lang.Thread.UncaughtExceptionH
import java.lang.reflect.F
import java.text.DateF
import java.text.SimpleDateF
import java.util.D
import java.util.HashM
import java.util.M
import android.content.C
import android.content.pm.PackageI
import android.content.pm.PackageM
import android.content.pm.PackageManager.NameNotFoundE
import android.os.B
import android.os.E
import android.os.L
import android.util.L
import android.widget.T
* UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
需要在Application中注册,为了要在程序启动器就监控整个程序。
public class CrashHandler implements UncaughtExceptionHandler {
public static final String TAG = &CrashHandler&;
/** 崩溃异常日志保存路径:*/
private String path = &/storage/emulated/0/ZhaiDaiSource/crash/&;
private String path = &/mnt/sdcard/crash/&;
private String preFileName = &ExceptionCatch_Save_Send&;
//系统默认的UncaughtException处理类
private Thread.UncaughtExceptionHandler mDefaultH
//CrashHandler实例
private static CrashH
//程序的Context对象
private Context mC
//用来存储设备信息和异常信息
private Map&String, String& infos = new HashMap&String, String&();
//用于格式化日期,作为日志文件名的一部分
private DateFormat formatter = new SimpleDateFormat(&yyyy-MM-dd-HH-mm-ss&);
/** 保证只有一个CrashHandler实例 */
private CrashHandler() {}
/** 获取CrashHandler实例 ,单例模式 */
public static CrashHandler getInstance() {
if(instance == null)
instance = new CrashHandler();
public void init(Context context) {
mContext =
//获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
//设置该CrashHandler为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
* 当UncaughtException发生时会转入该函数来处理
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
//如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(TAG, &error : &, e);
//退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
private boolean handleException(Throwable ex) {
if (ex == null) {
Log.e(TAG, &error : &, ex);
//收集设备参数信息
collectDeviceInfo(mContext);
//使用Toast来显示异常信息
new Thread() {
public void run() {
Looper.prepare();
Toast.makeText(mContext, &很抱歉,程序出现异常,即将退出.&, Toast.LENGTH_SHORT).show();
Looper.loop();
}.start();
//保存日志文件
saveCatchInfo2File(ex);
* 收集设备参数信息
* @param ctx
public void collectDeviceInfo(Context ctx) {
PackageManager pm = ctx.getPackageManager();
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
if (pi != null) {
String versionName = pi.versionName == null ? &null& : pi.versionN
String versionCode = pi.versionCode + &&;
infos.put(&versionName&, versionName);
infos.put(&versionCode&, versionCode);
} catch (NameNotFoundException e) {
Log.e(TAG, &an error occured when collect package info&, e);
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
infos.put(field.getName(), field.get(null).toString());
Log.d(TAG, field.getName() + & : & + field.get(null));
} catch (Exception e) {
Log.e(TAG, &an error occured when collect crash info&, e);
* 保存错误信息到文件中
* @param ex
返回文件名称,便于将文件传送到服务器
private String saveCatchInfo2File(Throwable ex) {
StringBuffer sb = new StringBuffer();
for (Map.Entry&String, String& entry : infos.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(key + &=& + value + &\n&);
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 result = writer.toString();
sb.append(result);
long timestamp = System.currentTimeMillis();
String time = formatter.format(new Date());
String fileName = preFileName + time + &-& + timestamp + &.log&;
/*使用SDcard_and_InnerStore.java 类获取 路径 就不需要这个判断了*/
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String path = &/mnt/sdcard/crash/&;
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
FileOutputStream fos = new FileOutputStream(path + fileName);
fos.write(sb.toString().getBytes());
//发送给开发人员
sendCrashLog2PM(path+fileName);
fos.close();
return fileN
} catch (Exception e) {
Log.e(TAG, &an error occured while writing file...&, e);
* 将捕获的导致崩溃的错误信息发送给开发人员
* 目前只将log日志保存在sdcard 和输出到LogCat中,并未发送给后台。
private void sendCrashLog2PM(String fileName){
if(!new File(fileName).exists()){
Toast.makeText(mContext, &日志文件不存在!&, Toast.LENGTH_SHORT).show();
FileInputStream fis =
BufferedReader reader =
String s =
fis = new FileInputStream(fileName);
reader = new BufferedReader(new InputStreamReader(fis, &GBK&));
while(true){
s = reader.readLine();
if(s == null)
//由于目前尚未确定以何种方式发送,所以先打出log日志。
Log.i(&info&, s.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
reader.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
2.BaseApplication
import android.app.A
import android.content.C
public class CatchExceptionApplication extends Application {
public void onCreate() {
super.onCreate();
CrashHandler catchHandler = CrashHandler.getInstance();
catchHandler.init(getApplicationContext());
3. 清单文件添加application和权限
&?xml version=&1.0& encoding=&utf-8&?&
&manifest xmlns:android=&/apk/res/android&
package=&com.example.exceptioncatch_save_send&
android:versionCode=&1&
android:versionName=&1.0& &
android:minSdkVersion=&14&
android:targetSdkVersion=&22& /&
&uses-permission android:name=&android.permission.READ_EXTERNAL_STORAGE&/&
&uses-permission android:name=&android.permission.WRITE_EXTERNAL_STORAGE&/&
&application
android:allowBackup=&true&
android:icon=&@drawable/ic_launcher&
android:label=&@string/app_name&
android:theme=&@style/AppTheme&
android:name=&com.example.exceptioncatch_save_send.base.CatchExceptionApplication&&
android:name=&.MainActivity&
android:label=&@string/app_name& &
&intent-filter&
&action android:name=&android.intent.action.MAIN& /&
&category android:name=&android.intent.category.LAUNCHER& /&
&/intent-filter&
&/activity&
&/application&
&/manifest&
======================================================
4.代码校验:
import java.io.F
import com.example.exceptioncatch_save_send.utils.SDCard_and_InnerS
import android.app.A
import android.os.B
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String sdorInner=SDCard_and_InnerStore.getSDorInStore(this) + File.separator +&ZhaiDaiSource& + File.separator + &head.jpg&;
System.out.println(&sdorInner = &+sdorInner);
System.out.println(s.equals(&hello&));
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:158460次
积分:3015
积分:3015
排名:第12987名
原创:150篇
转载:53篇
评论:18条
(1)(11)(8)(5)(13)(5)(3)(17)(26)(6)(12)(5)(22)(13)(20)(26)(10)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'1456人阅读
android(409)
Android Studio(83)
异常Exception(51)
Android 架构(42)
from : &http://blog.csdn.net/android_cmos/article/details/
& & 由于自己最近在跟一个项目,怎么说呢,项目功能真的是太多了,有时测试的MM忙不过来,有些隐形的bug没发现出来,但是我认为整体稳定性不够好,有时会Crash掉,这也给那些出去演示的市场部伙伴带来了不少的尴尬,虽然说现在属于测试阶段,但毕竟是上线的项目,用户体验不好,有时直接可能会杀死一个产品,而市场部的伙伴在演示的时候也不知道程序崩溃crash具体的操作流程,因为挂的那么突然 = = !,所以每次演示回来都会提出一些UI和程序挂掉的BUG,于是经常会出现如下的对话场景,然而作为程序猿傲娇的本能,“怎么可能?你能给我重现吗?......”,”并不能,但是balabala.....“,好吧,有问题总得改吧,但是他们也只能说出大概挂掉的地方,于是,你就得跟这个bug,看的你是一脸懵逼,根本不知道挂在哪里,好伐???!!!要是你能告诉我挂在那一行,是什么原因,我就至少可以有针对性的改啊。
& & & & 好了,说了这么多,我相信应该有人和我同样的感觉吧,要是能记录下挂掉的行数和原因那该多好啊,于是我搜索了一下,还真有这样的,满足我的需求。它可以自动捕获程序异常,并记录存储在本地,最主要的是它可以自动上传到邮箱和发送到服务器,而且原作者对此方法进行了封装,只要进行简单的配置就可以使用了。
& & & & 这里我就直接给出作者的文章地址(文章地址在文末)吧,不过,我这里做一些小的补充,因为就算有了别人的框架,我按照他的说明还是没完全成功,并不能发送到邮箱,只能保存异常信息到本地sd卡上,作为并没接触过邮件发送的我,也不知道原因出在哪,我看到好多人在下载源代码的链接下面留言说不能用,以为真的不能用,但是我不甘心,于是我又搜索了一些资料,终于看出了一些端倪,原来是我的邮箱的smtp服务功能没开启,邮箱为了安全起见,默认是关闭的,也就是不能自动发送邮件。
& & & &好的,下面我给出此框架的使用步骤吧。
& & & &使用本框架前,你需要以下jar包 &android-crash-1.0.jar &activation.jar &additionnal.jar &mail.jar 后面的3个是可选的,如果你用邮件的方式的话,就需要它们,如果采用服务器的方式,就不用了。这几个jar包,。
首先先说使用步骤吧:
1,添加jar包
①,如果你是Eclipse用户,你想用到邮件的发送来处理异常信息,那你得需要将上面的4个jar包添加到你的项目中,具体步骤不会的可百度。
②,如果你是Android studio用户,你需要在build.gradle(Project:xxx)下的repository中添加如下代码段
在build.gradle(Module:xxx) 中的dependencies添加如下依赖
后面的3个是可选的,如果用邮件的方式发送的话,需要添加jar包,和添加相应的依赖
其实上述的添加依赖是可以自动完成的,当你把jar包导入后,然后邮件你的jar包,会出现add to library,你添加后,会在依赖中发现已经帮你自动添加了。
2,属性配置
自定义一个类,让其继承于Application,并在AndroidManifest.xml中的application节点中使用name属性,将类名添加进去,这样当程序一启动就会先执行继承自application类里面的配置,最后要别忘了添加权限,一个是网络权限,一个是往sd卡写的权限
特别要注意的是,对于自动发送邮件的,一定要邮箱开启SMTP服务功能,否则程序会报一个自动验证失败的异常,发送不了邮件。
具体怎么设置SMTP服务,请点击下面的链接&/article/0aadc88cd0d6473.html &
本框架的作者原文链接如下&http://blog.csdn.net/maosidiaoxian/article/details/ &具体的原理可参见此文
& &&这也是我后来在运用中才发现的,所以就也写在这里好了,下面的内容是介绍一个非常强大、非常牛掰的一个bug收集服务器.免去了自己搭建的功夫,以及邮件查看时要下载日志的不便。
& & &腾讯 Bugly,是腾讯公司为移动开发者开放的服务之一,面向移动开发者提供专业的 Crash 监控、崩溃分析等质量跟踪服务。Bugly 能帮助移动互联网开发者更及时地发现掌控异常,更全面的了解定位异常,更高效的修复解决异常。
& & 这里我就不浪费笔墨在此去教如何使用了,毕竟官方的更专业,相信你也更相信官方的文档。链接如下:/androidfast
& & &给张官方示例的截图看看,相信你会喜欢上使用它的
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:521381次
积分:7957
积分:7957
排名:第2920名
原创:271篇
转载:319篇
评论:69条
解读java源码深入学习,提升能力
(9)(14)(7)(9)(3)(17)(15)(8)(27)(7)(17)(7)(10)(16)(24)(29)(43)(36)(28)(65)(70)(25)(88)(16)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'相关文章推荐
http://blog.csdn.net/android_cmos/article/details/
由于自己最近在跟一个项目,怎么说呢,项目功能真的...
原文链接:http://blog.csdn.net/liuhe688/article/details/6584143
大家都知道,现在安装Android系统的手机版本和设备千差万别,在模...
原文链接:http://blog.csdn.net/liuhe688/article/details/6584143
大家都知道,现在安装Android系统的手机版本和设备千差万...
1.什么是crashandroid应用程序不可避免的会发生crash,也称之为崩溃,表现形式为闪退或是程序已停止运行。2.发生crash的原因发生crash的原因有很多:
程序本身bug
在做android项目开发时,大家都知道如果程序出错了,会弹出来一个强制退出的弹出框,这个本身没什么问题,但是这个UI实在是太丑了,别说用户接受不了,就连我们自己本身可能都接受不了。虽然我们在发布程序...
* 自定义的 异常处理类 , 实现了 UncaughtExceptionHandler接口
public class CrashHandler implements...
最近在写Android程序崩溃异常处理,完成之后,稍加封装与大家分享。
我的思路是这样的,在程序崩溃之后,将异常信息保存到一个日志文件中,然后对该文件进行处理,比如发送到邮箱,或发送到服务器。
...
他的最新文章
讲师:董晓杰
讲师:姚远
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)相关文章推荐
在Android开发过程中,如果有Crash,我们往往想看到具体Crash的情景,但是在发布版本后,应用万一出现崩溃现象,就会出现一个弹窗说应用崩溃了,如果给用户看到,会有很大不良印象,如果是我,我觉...
假如你开发的app有这个需求的话:崩溃后自动重启。你可以参照下文:
在开发过程中,虽然经过测试,但在发布后,在广大用户各种各样的运行环境和操作下,可能会发生一些异想不到的错误导致程序崩溃。将这些错误信息收集起来并反馈给开发者,对于开发者改进优化程序是相当重要的。好了,...
本文主要介绍如何实现app崩溃后捕获异常或自动重启,请看文章!
Android异常捕获放置崩溃弹框
简单的Android应用崩溃重启方法,也可实现崩溃log收集等
概述:典型的Activity 生命周期众所周知,就不用多说了吧;我们知道,Activity除了受用户操作所导致的正常的生命周期方法调度,还有一些异常情况,比如当资源相关的系统配置发生了改变以及系统内存...
大家都知道,现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试,所以在程序发布出去之后,如果出现了...
在我们开发Android应用程序的时候总是难免遇到程序崩溃的问题:(很抱歉,“××”已停止运行。)
每次看到这个问题心都是哇凉哇凉的
一般遇到这样问题,有两种可能:
1、自己的代码写得不够精密,...
android开发中经常会遇到程序异常,而已常常会遇到一出现异常APP就自动重启了,而已如果你的项目中应用到Fragment的切换的话,会出行页面重叠的现象。今天为了解决这个问题看了不少大牛的博客。最...
他的最新文章
讲师:董晓杰
讲师:姚远
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 按键精灵异常崩溃 的文章

 

随机推荐