/**
* 根据地址返回经纬度
* @param addr
* @return 返回经纬度数据, latLng[0]经度,latLng[1]维度
*/
public static String[] getCoordinate(String addr) {
String[] latLng = new String[2]
String address = null
try {
address = java.net.URLEncoder.encode(addr, "UTF-8")
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace()
}
String output = "csv"
//密钥可以随便写一个key=abc
String key = "abc"
String url = "http://maps.google.com/maps/geo?q=" + address + "&output=" + output + "&key=" + key
URL googleMapURL = null
URLConnection httpsConn = null
// 进行转码
try {
googleMapURL = new URL(url)
} catch (MalformedURLException e) {
e.printStackTrace()
}
try {
httpsConn = (URLConnection)googleMapURL.openConnection()
if (httpsConn != null) {
InputStreamReader insr = new InputStreamReader(httpsConn.getInputStream(), "UTF-8")
BufferedReader br = new BufferedReader(insr)
String data = null
if ((data = br.readLine()) != null) {
String[] retList = data.split(",")
/*
* String latitude = retList[2]String longitude =
* retList[3]
*
* System.out.println("纬度"+ latitude)
* System.out.println("经度"+ longitude)
*/
if (retList.length >2 &&("200".equals(retList[0]))) {
latLng[0] = retList[2]
latLng[1] = retList[3]
}
}
insr.close()
}
} catch (IOException e) {
e.printStackTrace()
}
return latLng
}
配对箱线图,常见于配对样本的数据分析中。
例如下图示例,为了研究某些基因在肿瘤组织和正常组织中是否具有表达量的显著不同,在取样时,往往会在同一患者个体中同时获取肿瘤和临近正常组织,两个组织样本就是配对关系。当然在这类研究中,往往需要调查很多的患者,因此会获得大量的配对样本。随后,通过qPCR或RNA-seq等方法定量基因表达后,以箱线图呈现特定基因在肿瘤组织和正常组织中的整体表达水平,并在箱线图中以散点表示具体的样本,此时对于具有配对关系的肿瘤组织和正常组织样本,就可以通过连线连接起来。
这种配对箱线图的好处是,除了能够表现两组的整体差异,还能够清晰地呈现单个样本的前后改变。
本篇教程,就让我们带大家学习如何使用R语言绘制这种配对箱线图。
类似地,假设我们也期望查看某基因(例如MAP2)在肿瘤组织和正常组织中的表达改变情况,在收集了配对样本并检测了这些样本中基因表达水平后,配置这样一张表。
samples是样本名称;MAP2是基因MAP2在各样本中的表达值;group1是样本分组,告知它们来源于肿瘤组织还是正常组织;group2是配对样本信息,配对的两样本设置为同一亚组。
备注: 该示例数据集可点击这里获取。
随后,将上述示例数据导入R中。
绘制箱线图表示两组基因的整体表达水平,并以散点表示样本,配对样本间以连线连接。
这样,配对箱线图就获得了。
箱线图描述了组间基因表达水平改变的趋势,在该图中可以看到MAP2基因的表达在肿瘤组织和正常组织中是不一致的。后续如有需要,不妨执行配对样本的t检验等,计算显著性p值,作为评判基因表达显著差异的指标。
app报错处理流程在android应用进程启动流程中,进程启动之初,在RuntimeInit中:
private static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!")
/* set default handlerthis applies to all threads in the VM */
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler())
.......
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
为该进程设置异常处理:
1、调用AMS的handleApplicationCrash方法
2、kill该进程
private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
try {
// Don't re-enter -- avoid infinite loops if crash-reporting crashes.
if (mCrashing) return
mCrashing = true
if (mApplicationObject == null) {
Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e)
} else {
StringBuilder message = new StringBuilder()
message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n")
final String processName = ActivityThread.currentProcessName()
if (processName != null) {
message.append("Process: ").append(processName).append(", ")
}
message.append("PID: ").append(Process.myPid())
Clog_e(TAG, message.toString(), e)
}
........
// Bring up crash dialog, wait for it to be dismissed
ActivityManagerNative.getDefault().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.CrashInfo(e))
} catch (Throwable t2) {
if (t2 instanceof DeadObjectException) {
// System process is deadignore
} else {
try {
Clog_e(TAG, "Error reporting crash", t2)
} catch (Throwable t3) {
// Even Clog_e() fails! Oh well.
}
}
} finally {
// Try everything to make sure this process goes away.
Process.killProcess(Process.myPid())
System.exit(10)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
AMS.handleApplicationCrash
1、从正在运行的进程集合(mProcessNames)中找到该进程
2、获取进程名称,并且使用其添加一条日志记录到dropbox目录下
3、进入AppErrors错误处理流程crashApplication
public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
ProcessRecord r = findAppProcess(app, "Crash")
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName)
handleApplicationCrashInner("crash", r, processName, crashInfo)
}
1
2
3
4
5
6
7
1
2
3
4
5
6
7
private ProcessRecord findAppProcess(IBinder app, String reason) {
if (app == null) {
return null
}
synchronized (this) {
final int NP = mProcessNames.getMap().size()
for (int ip=0ip<NPip++) {
SparseArray<ProcessRecord>apps = mProcessNames.getMap().valueAt(ip)
final int NA = apps.size()
for (int ia=0ia<NAia++) {
ProcessRecord p = apps.valueAt(ia)
if (p.thread != null &&p.thread.asBinder() == app) {
return p
}
}
}
return null
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,ApplicationErrorReport.CrashInfo crashInfo) {
EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
UserHandle.getUserId(Binder.getCallingUid()), processName,
r == null ? -1 : r.info.flags,
crashInfo.exceptionClassName,
crashInfo.exceptionMessage,
crashInfo.throwFileName,
crashInfo.throwLineNumber)
addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo)
mAppErrors.crashApplication(r, crashInfo)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
AppErrors中处理流程:
void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
final long origId = Binder.clearCallingIdentity()
try {
crashApplicationInner(r, crashInfo)
} finally {
Binder.restoreCallingIdentity(origId)
}
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
........
AppErrorResult result = new AppErrorResult()
TaskRecord task
synchronized (mService) {
//如果该进程设置了IActivityController则直接返回,不弹出报错提示窗口
if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
timeMillis)) {
return
}
//有正在运行的instrumentation,也立即退出,不弹出报错提示窗口
if (r != null &&r.instrumentationClass != null) {
return
}
......
AppErrorDialog.Data data = new AppErrorDialog.Data()
data.result = result
data.proc = r
// 进程记录为空或者在一分钟内已经crash了两次了,就直接退出,不提示报错弹窗
// quit right away without showing a crash dialog.
if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
return
}
//像AMS发送SHOW_ERROR_UI_MSG消息弹出报错提示框,提示框弹出条件为:已经弹出了的不再弹,是后台进程并且当前系统设置不显示后台进程报错弹框的不弹。
final Message msg = Message.obtain()
msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG
task = data.task
msg.obj = data
mService.mUiHandler.sendMessage(msg)
}
//根据弹窗后的点击或者未弹窗但是设置的状态获取结果,结果有如下几种:FORCE_QUIT、
//FORCE_QUIT_AND_REPORT、RESTART、MUTE、TIMEOUT、CANCEL 7种
int res = result.get()
Intent appErrorIntent = null
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res)
if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
res = AppErrorDialog.FORCE_QUIT
}
synchronized (mService) {
//返回结果为MUTE,则停止报告本次crash
if (res == AppErrorDialog.MUTE) {
stopReportingCrashesLocked(r)
}
//返回为RESTART,则清除现有进程信息processRecord并且重新拉起该进程
if (res == AppErrorDialog.RESTART) {
mService.removeProcessLocked(r, false, true, "crash")
if (task != null) {
try {
mService.startActivityFromRecents(task.taskId,
ActivityOptions.makeBasic().toBundle())
} catch (IllegalArgumentException e) {
// Hmm, that didn't work, app might have crashed before creating a
// recents entry. Let's see if we have a safe-to-restart intent.
final Set<String>cats = task.intent.getCategories()
if (cats != null &&cats.contains(Intent.CATEGORY_LAUNCHER)) {
mService.startActivityInPackage(task.mCallingUid,
task.mCallingPackage, task.intent,
null, null, null, 0, 0,
ActivityOptions.makeBasic().toBundle(),
task.userId, null, null)
}
}
}
}
//FORCE_QUIT,则从任务栈中移除,并且移除进程信息,移除焦点信息
if (res == AppErrorDialog.FORCE_QUIT) {
long orig = Binder.clearCallingIdentity()
try {
// Kill it with fire!
mService.mStackSupervisor.handleAppCrashLocked(r)
if (!r.persistent) {
mService.removeProcessLocked(r, false, false, "crash")
mService.mStackSupervisor.resumeFocusedStackTopActivityLocked()
}
} finally {
Binder.restoreCallingIdentity(orig)
}
}
//FORCE_QUIT_AND_REPORT则生成一action为ACTION_APP_ERROR的intent,并且拉起该activity,这也就是一些bugreport应用的主要数据来源,注册ACTION_APP_ERROR的action后,系统在每次crash并且用户选择退出并且回传错误报告的时候,就会主动拉起该应用的页面。
if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo)
}
if (r != null &&!r.isolated &&res != AppErrorDialog.RESTART) {
// XXX Can't keep track of crash time for isolated processes,
// since they don't have a persistent identity.
mProcessCrashTimes.put(r.info.processName, r.uid,
SystemClock.uptimeMillis())
}
}
if (appErrorIntent != null) {
try {
mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId))
} catch (ActivityNotFoundException e) {
Slog.w(TAG, "bug report receiver dissappeared", e)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
makeAppCrashingLocked:
返回true则继续往下走进入弹窗显示,返回false则不再显示弹窗
private boolean makeAppCrashingLocked(ProcessRecord app,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
app.crashing = true
//生成错误报告
app.crashingReport = generateProcessError(app,
ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace)
//移除该应用所有广播
startAppProblemLocked(app)
//停止屏幕冻结
app.stopFreezingAllLocked()
//一分钟内报错两次如果允许显示后台进程报错则返回false,否则都是返回true,
如果不是persistent则移除杀掉该进程移除进程信息,处理app die,移除任务栈中的信息
如果是persistent,则仅仅移除当前聚焦的栈顶信息。
return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
data)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
handleShowAppErrorUi
弹出报错提示窗
已经显示着报错窗口的不再弹,不显示后台进程报错的的时候后台进程报错不弹出
void handleShowAppErrorUi(Message msg) {
AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0
synchronized (mService) {
ProcessRecord proc = data.proc
AppErrorResult res = data.result
if (proc != null &&proc.crashDialog != null) {
Slog.e(TAG, "App already has crash dialog: " + proc)
if (res != null) {
res.set(AppErrorDialog.ALREADY_SHOWING)
}
return
}
boolean isBackground = (UserHandle.getAppId(proc.uid)
>= Process.FIRST_APPLICATION_UID
&&proc.pid != MY_PID)
for (int userId : mService.mUserController.getCurrentProfileIdsLocked()) {
isBackground &= (proc.userId != userId)
}
if (isBackground &&!showBackground) {
Slog.w(TAG, "Skipping crash dialog of " + proc + ": background")
if (res != null) {
res.set(AppErrorDialog.BACKGROUND_USER)
}
return
}
final boolean crashSilenced = mAppsNotReportingCrashes != null &&
mAppsNotReportingCrashes.contains(proc.info.packageName)
if ((mService.canShowErrorDialogs() || showBackground) &&!crashSilenced) {
//这里将参数中的data用到了新建的apperrdialog中,并且赋给了processrecord中的crashDialog变量,
这里也就跟上面获取弹窗点击结果进行了关联
proc.crashDialog = new AppErrorDialog(mContext, mService, data)
} else {
// The device is asleep, so just pretend that the user
// saw a crash dialog and hit "force quit".
if (res != null) {
res.set(AppErrorDialog.CANT_SHOW)
}
}
}
// If we've created a crash dialog, show it without the lock held
if(data.proc.crashDialog != null) {
data.proc.crashDialog.show()
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
removeProcessLocked
该方法在整个弹窗前和弹窗后的处理流程中多次调用到,主要执行移除进程记(removeProcessNameLocked),再次杀进程(kill)确保证进程被杀后处理app死亡后的处理(handleAppDiedLocked)
boolean removeProcessLocked(ProcessRecord app,
boolean callerWillRestart, boolean allowRestart, String reason) {
final String name = app.processName
final int uid = app.uid
if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
"Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")")
ProcessRecord old = mProcessNames.get(name, uid)
if (old != app) {
// This process is no longer active, so nothing to do.
Slog.w(TAG, "Ignoring remove of inactive process: " + app)
return false
}
removeProcessNameLocked(name, uid)
if (mHeavyWeightProcess == app) {
mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
mHeavyWeightProcess.userId, 0))
mHeavyWeightProcess = null
}
boolean needRestart = false
if (app.pid >0 &&app.pid != MY_PID) {
int pid = app.pid
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(pid)
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app)
}
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid)
if (app.isolated) {
mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid)
}
boolean willRestart = false
if (app.persistent &&!app.isolated) {
if (!callerWillRestart) {
willRestart = true
} else {
needRestart = true
}
}
app.kill(reason, true)
handleAppDiedLocked(app, willRestart, allowRestart)
if (willRestart) {
removeLruProcessLocked(app)
addAppLocked(app.info, false, null /* ABI override */)
}
} else {
mRemovedProcesses.add(app)
}
return needRestart
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50