reoger的记录

--以后的你会感激现在那么努力的自己

0%

最近有一个这样的需求,需要知道某个view的展示率,但是这个view嵌套在一个滑动布局中,在当前view已经被添加到滑动布局的前提下,该view也不一定会展示,可能会出现的情况如下所示:

可能存在的情况.png

那么,我们怎么判断当前的view是否展示了呢?

我的实现思路如下:

  1. 首先,在添加view的时候,判断当前view是否展示,如果展示,直接上报即可。如果没有展示,而是如图所示的情况,那就存储一个sp的值,用于表示当前的view没有上报。
  2. 在滑动布局中,进行滑动监听。在滑动的过程中,判断当前的view是否上报,在没有上报的情况下,继续判断view是否显示,如果在混动过程中view显示了,就上报view显示了,并存储一个sp的值,用于表示当前的view已经上报了。

上面的语言用代码表示为:
在添加view的逻辑中,用如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//addView代表该view被添加到当前布局了
if (addView()) {
//parentView 即滑动布局
parentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
parentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
//这里是判断当前布局是否可见
if (CustomMainScrollView.checkIsVisible(mContext, parentView)) {
reportSkinShareCard(gamemaster_app_cardshow_new.OP_VISIBLE, false);
}else{
//设置状态为未上报
PreferencesUtils.getInstance().putBoolean(HAS_REPORT_SHOW_SKIN_THEME_CARD, false);
}
}
});
}

然后在滑动布局中,监听滚动事件,调用下面的代码:

1
2
3
4
5
6
7
8
9
10
11
 private void reportSkinThemeCard(Context context, View skinThemeView) {
boolean hasReport = PreferencesUtils.getInstance().getBoolean(HAS_REPORT_SHOW_SKIN_THEME_CARD, false);

if (!hasReport && checkIsVisible(context, skinThemeView) && mSkinThemeView.getChildCount() != 0 ) {
byte cardStyle = AbTestLogicManager.isSkinWithImageTestValue()?gamemaster_app_cardshow_new.CARD_TYPE_SKIN_WITH_IMAGE:gamemaster_app_cardshow_new.CRAD_SKIN_WITH_TEXT;

// todo 在这里进行上报操作
PreferencesUtils.getInstance().putBoolean(PreferenceConstants.HAS_REPORT_SHOW_SKIN_THEME_CARD, true);
//最后,更新状态,避免重复上报
}
}

在补充一个检查当前view是否显示的方法:

1
2
3
4
5
6
7
8
9
10
11
12
public static Boolean checkIsVisible(Context context, View view) {
int screenWidth = getScreenMetrics(context).x;
int screenHeight = getScreenMetrics(context).y;
Rect rect = new Rect(0, 0, screenWidth, screenHeight);
int[] location = new int[2];
view.getLocationInWindow(location);
if (view.getLocalVisibleRect(rect)) {
return true;
} else {
return false;
}
}

主要介绍几个知识点:

参考资料

java中常用的classLoader

说到android中的classLoader,就不能不先说说java中的classLoader是什么。
所谓classLoader就是负责将编译好的class文件加载到指定位置的实现类。具体来说,我们编写java代码时,需要将其编译成.class文件,最终运行时就需要将这些class文件加载到内存才能运行,而加载这些class文件的方法就可以成为classLoader。
在java中常用的classLoader有以下三种:

Bootstrap Classloder

这个类加载使用C++语言实现,是虚拟机自身的一部分。他是三个类加载器中最顶层的加载类,主要负责加载%JAVA_HOME%/lib下的核心类或者jar加载到内存中。(值得注意的是,Bootstrao Loader被设计成只能加载包名为java、javax、sun等开头的类.)

Extention Classloder

扩展类的加载器,由java语言实现,主要负载加载%JAVA_HOME%/lib/ext目录下的类库,或者是系统指定的类库。

AppClassloader

主要负责加载系统类路径或者指定路径下的类库。
以上三种是java中定义的ClassLoader。

下面介绍android中常用的类加载器。

classLoader

所有的classLoader的基类,他是一个抽象类,所有的classLoader最终都会继承自他,我们如果需要自定义classLoader也需要直接或者间接的继承他,并实现其中的findClass方法,并通过defineClass创建一个类实例。自定义类加载的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class NetworkClassLoader extends ClassLoader {
String host;
int port;

public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}

private byte[] loadClassData(String name) {
// load the class data from the connection
//省略
}
}

BaseDexClassLoader

BaseDexClassLoader继承自ClassLoader,只是对其进行了进一步的封装,并没有实现,他有两个直接的子类PathClassLoaderDexClassLoader
简单介绍一下他的构造函数:

1
2
3
4
5
6
public BaseDexClassLoader(String dexPath, File optimizedDirectory, String librarySearchPath, ClassLoader parent) {
//dexPath 代表目标类所在的apk、DEX或者JAR文件的路径
//optimizedDirectory用于指定解压出来的dex文件存放的路径
//librarySearchPath用于指定类中所使用的C/C++库存放的路径
//parent 用于指定该加载器的父加载器,一般为当前执行类的加载器
}

关于BaseDexClassLoader还有一点要补充的是,由于dex文件被包含在APK或者jar文件中,因此在加载目标类之前需要先从APK或者jar文件中加压处dex文件,optimizedDirectory即为指定解压出来的dex文件存放的路径,这也是对apk中dex根据平台ODEX优化的过程。

DexClassLoader

DexClassLoader用于加载包含dex的JAR或者APK文件,但是他不能加载jar或者apk文件。他最终加载的都是dex文件,虽然他是从.jar或者.zip,.apk等结尾的文件中加载,但是他们最终都会生成一个对应的dex文件,他操作的还是dex文件。DexClassLoader继承自BaseDexClassLoader,原理如下:

1
2
3
4
5
6
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
}

由代码不能看出,DexClassLoader只是简单的对BaseDexClassLoader进行了一层封装,并且指定了optimizedDirectory的路径为一个新的文件路径,DexClassLoader通过指定自己的optimizedDirectory,所以它可以加载外部的dex,因为这个dex会被复制到内部路径的optimizedDirectory。
所以,DexClassLoader一般用来作为动态加载的加载器。

PathClassLoader

PathClassLoader也是继承自BaseDexClassLoader,他主要用于加载apk,一般应用于加载android的系统类和app应用的类。他的实现如下:

1
2
3
4
5
6
7
8
9
10
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}

public PathClassLoader(String dexPath, String libraryPath,
ClassLoader parent) {
super(dexPath, null, libraryPath, parent);
}
}

可以看到,PathClassLoader将optimizedDirectory置为null,而optimizedDirectory是用来指定apk或者jar解压出来的dex存放的位置,如果optimizedDirectory为null,则使用其默认路径/data/dalvik-cache,因此无法加载外部的apk的dex,只能加载内部的dex,这些大都是存在系统中已经安装过的apk里面的。

URLClassLoader

URLClassLoader只能加载jar文件,但是dalvik虚拟机不能识别jar,所以在android中无法使用这个加载器。

InMemoryDexClassLoader

InMemoryDexClassLoader也是继承自BeseDexClassLoader,是API26新增的加载器,用于加载内存中的dex文件。

DelegateLastClassLoader

DelegateLastClassLoader继承自PathClassLoader,是API27新增的加载器,用于指定最后的查找策略,查找顺序如下:先判断自己是否加载此类,然后在判断此类的加载器是否加载过此类,最后委托给指定的父加载器。

classloader的双亲委托模型

classLoader双亲委托模型,当要加载某个类时,先判断自己是否有加载过此类,如果自己没有加在过此类的话,进而判断父类是否加载过,如果某个父类加在过这个类的话,就直接返回,不重复加载。如果一直到顶级父类都没有加载此类的话,这个加载任务就会分发下来,最后用当前类加载器去加载该类。

类加载机制实现热修复方案

通过使用dexClassloader动态修改加载dex的顺序即可达到热修复的目的。

参考资料


AOP 基本思想

刚接触编程的时候,一般先接触的c语言这类的OOP(Procedure Oriented,即面向过程)语言,面相过程是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。

然后,我们就会学到另一种更符合我们思维方式的一种思想,OOP(Object-Oriented Programming,即面向过程程序设计)语言,面向过程其实是最为实际的一种思考方式,就算是面向对象的方法也是含有面向过程的思想。可以说面向过程是一种基础的方法。它考虑的是实际地实现。一般的面向过程是从上往下步步求精,所以面向过程最重要的是模块化的思想方法。对比面向过程,面向对象的方法主要是把事物给对象化,对象包括属性与行为。当程序规模不是很大时,面向过程的方法还会体现出一种优势。因为程序的流程很清楚,按着模块与函数的方法可以很好的组织。
但是,在重复代码很多,需要重复利用的情况下,面相对象程序设计也显得很鸡肋,必要每次都主动去调用该方法,而且有特殊需求的时候还不能去需改写好的方法,因为这可能会造成其他其他调用该方法的地方出现问题。

这个时候AOP就出现了。AOP是Aspect Oriented Programming的缩写,即『面向切面编程』。它和我们平时接触到的OOP都是编程的不同思想,OOP,即『面向对象编程』,它提倡的是将功能模块化,对象化,而AOP的思想,则不太一样,它提倡的是针对同一类问题的统一处理,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

最后总结成一句话就是:
在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

编程实践

讲了思想,我们通过具体的例子来进行说明。我们实现为方法自动添加log日志,不同于以前的主动调用,我们通过Aspect来实现AOP注入。

项目代码托管:https://github.com/Reoger/AOPTest

首先是配置:app下的build.gradle文件,配置类似如下代码:

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
apply plugin: 'com.android.application'
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.9'
classpath 'org.aspectj:aspectjweaver:1.8.9'
}
}
repositories {
mavenCentral()
}
final def log = project.logger
final def variants = project.android.applicationVariants
variants.all { variant ->
if (!variant.buildType.isDebuggable()) {
log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
return;
}

JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = ["-showWeaveInfo",
"-1.8",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
log.debug "ajc args: " + Arrays.toString(args)

MessageHandler handler = new MessageHandler(true);
new Main().run(args, handler);
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break;
case IMessage.WARNING:
log.warn message.message, message.thrown
break;
case IMessage.INFO:
log.info message.message, message.thrown
break;
case IMessage.DEBUG:
log.debug message.message, message.thrown
break;
}
}
}
}

android {
compileSdkVersion 25
buildToolsVersion '25.0.0'
defaultConfig {
applicationId "com.example.cm.aoptest"
minSdkVersion 20
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'org.aspectj:aspectjrt:1.8.9'
testCompile 'junit:junit:4.12'
}

然后就是实现我们的要实现的注入的log方法,AspectLogTest.java代码如下:

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
import android.util.Log;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
* Created by CM on 2018/1/18.
*
*/
@Aspect
public class AspectLogTest {

@Target(ElementType.METHOD) //可以注解在方法 上
@Retention(RetentionPolicy.RUNTIME) //运行时(执行时)存在
public @interface AspectLog {
String value();
}

final static String TAG = "TAG";

@Pointcut("execution(@com.example.cm.aoptest.log.AspectLogTest.AspectLog * *(..))")
public void logForActivity(){

}

@Before("logForActivity()")
public Object doRealLog(JoinPoint joinPoint){
try {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
AspectLog aspectJAnnotation = methodSignature.getMethod().getAnnotation(AspectLog.class);
String log = aspectJAnnotation.value();
Log.d(TAG, "doRealLog: 打印日志"+log);
} catch (Exception e) {
e.printStackTrace();
}

return true;
}
}

写好了接口,我们来实现自动注入代码,这里我们还是需要借助注解来实现。如果我们向打印onCreate()onStart()等方法的中的信息,我们在MainActivity中这么写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@AspectLogTest.AspectLog(value = "来自OnStop的日志信息")
@Override
protected void onStop() {
super.onStop();
}

@AspectLogTest.AspectLog(value = "来自OnPause的日志信息")
@Override
protected void onPause() {
super.onPause();
}

@AspectLogTest.AspectLog(value = "来自OnCreate的日志信息")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

然后就实现这里自动log功能。
当然,从这个例子看起来好像和自己手动写Log.d()没有区别,只是用注解的方式调用而已。但是这里仅仅是为了展示他的功能,真正使用的时候我们可以通过他们来实现复杂的控制。

介绍一下Aspect常见的注解。

  • @Aspect 把当前类标识为一个切面供容器读取
  • @Before 表示一个前置增强方法
  • @AfterReturning 表示一个后置增强方法
  • @AfterThrowing 异常抛出增强
  • @After final增强,不管是抛出异常或是正常退出都会执行
  • @Around 环绕增强,先执行注入的方法,只有返回对应现场才能执行被注入的方法。
  • @DeclareParents 引介增强

介绍一下execution切点函数,其定义为execution([方法修饰符] [返回类型] 方法名 参数 [异常模式])
在上例中,我们的execution函数为:

1
execution(@com.example.cm.aoptest.log.AspectLogTest.AspectLog * *(..))

注意这里的方法名需要添加包名,*表示匹配任意字符,..表示匹配任意字符,可以匹配任意多个元素。
+必须跟在类名后面,表示类本身和继承或扩展制定类的所有类。

基础概念

  • PointCut 切入点:想要动态添加代码的连接点
  • Advice 通知 :向切点中注入代码实现方法
  • Aspect 切面 :切入点和通知的集合。
  • Joint Point 连接点:所有目标方法都是连接点
  • Weaving 编织 将切面代码注入到目标中,并生成代码混合到.class的过程。

参考链接

debug 技巧

关于android studio的debug技巧,前面的两篇参考文章已经写的特别好了,也没必要再写一次了,主要就记录一下debug的关键概念和快捷键。至于如何debug,就请参考前面两篇文章。

工具栏介绍

上图从左往右看,名称和作用如下表所示。

名称 作用 备注 快捷键
show Execution Point 定位到当前正在调试的位置 无备注 alt+F10
step over 单步跳过 一步一步执行,遇到方法会直接执行方法,然后进入下一步,不会进入方法内容 F8
step into 单步跳入 单步向下执行,如果当前是自定义方法,hi进入方法内部,系统方法则不进入方法内部 F7
Force step into 强制单步跳入 与单步跳入不同的是,不管什么方法他都会进入 Alt + Shfit + F7
step out 单步跳出 与单步跳入相对,表示从方法体中跳出,回到进入方法的位置,以继续断点 shfit + F8
run to cursor 执行到光标处 直接从当前位置运行到光标处,但是能被中间的断点拦截。 alt + F9
Evalyate Exoression 计算表达式 支持在点点过程中,通过直接赋值或者表达式方式,修改任意表俩个的值。 alt+F8

再加来几个快捷键。

快捷键 功能 说明
右击断点 为断点设置执行条件,或打印信息 只能针对本断点生效
alt + 单击 查看断点时变量的值
ctrl+alt+F8 为断点添加执行条件,或打印信息 这个可以对所有的断点生效

工具篇

uiautorviewer

可以通过这个工具快速定位到UI控件的ID,并通过ID快速找到相应的逻辑。

DDMS

可以利用ddms这个工具,实现截屏,查看线程和堆信息,日志信息,进程,广播状态信息,模拟来电,呼叫和短信等功能。
具体使用方法参考这里https://developer.android.com/studio/profile/monitor.html

命令篇

adb shell am

am 就是activity manager的简称,可以用于启动activity、打开或关闭进程、发送广播等操作。
关于具体的命令,可以参考这里http://blog.csdn.net/soslinken/article/details/50245865.
然后,这里就记录常用的adb shell am命令。
[注:这里默认省略了adb shell]

命令 作用 备注 示例
am start -n <package name>/<ativity name> 启动acivity -n 表示以组件式启动,还可以 am start -a android.settings.INPUT_METHOD_SETTINGS//使用Action方式打开系统设置-输入法设置
am start -a -n --es extra "hello" --ei pid 10 <package name>/<ativity name> 待参数的启动activity –es 表示带string,–ei 表示整型数据,都是以键值对的形式 am start -a -n --es extra "hello" --ei pid 10 com.reoger.app/com.example.cm.myapplication.NextActivity
am broadcast -a <action> 启动广播 还可以通过--user指定用户发送广播 com.android.broadcast.test
am broadcast -a <action> --es <key> <value> 带信息的发送广播 –es表示字符串,还有–ez(布尔值)等多种类型数据,都是以键值对的形式 am broadcast -a com.android.broadcast.test --es adb_extra "hello"
am startservice <package name>/<service name> 启动服务 可以通过--user<USER_ID>指定启动的用户 am startservice com.reoger.app/com.example.cm.myapplication.MyService
am force-stop <package name> 关闭指定包名的应用程序 am force-stop com.reoger.app
am kill <package name> 杀死与应该程序包想关联的所有进程,但只会杀死安全进程 可以通过--user <USER_ID>指定用户 am kill com.reoger.app
am kill -all 杀死全部的后台进程 am kill -all

详情参考这里:http://blog.csdn.net/soslinken/article/details/50245865

adb shell pm

pm即是 package manager的简称,可以用于安装应用、查询应用信息、系统权限、控制应用。

命令 作用 备注 示例
pm list packages [options] [fileter] 打印所有已经安装的应用的包名 options 常用的有-3 表示只显示第三方应用的包名,filter表示按名字筛选 pm list packages -e 显示可用的应用和包名
pm list permission [options] [group] 打印权限 -g表示按组列出,-s表示简短打印 pm list permission-groups 打印所有已知的权限组
grant <package_name> <permission> 授予应用权限 必须android 6.0及以上的设备 grant com.reoger.app android.permission.WRITE_EXTERNAL_STORAGE
revoke <package_name> <permission> 撤销应用权限 必须android 6.0及以上的设备 revoke com.reoger.app android.permission.WRITE_EXTERNAL_STORAGE
pm clear <package name> 清除应用数据 pm clear com.reoger.app
pm enable <package or component> 使得packaege或componet可用 只针对第系统应用 pm enable com.reoger.app
pm hide <package or component> 隐藏package或componet 被隐藏应用在管理中变得不可见,桌面图标也会消失 pm hide com.reoger.app
pm unhide <package or component> 取消隐藏package或componet 桌面图标需要重新添加 pm unhide com.reoger.app

详情请参考这里:https://www.cnblogs.com/JianXu/p/5380882.html

adb shell dumysys

命令 作用
dumpsys cpuinfo 查看CPU信息
dumpsys activity 查看一大堆信息,包括activity、broadcasts、providers、permissions等等信息
dumpsys activity top 获取当前android系统中与用户交互的activity的详细信息
dumpsys activity activities 显示当前所有运行的任务栈,可以与管道- grep XXX结合使用,用于筛选我们需要的任务栈
dumpsys activity meminfo <package name> 显示应用内存使用的情况
dumpsys activity package <package name> 显示apk的信息

其中的dumpsys activity [options] [WHAT]参数可选如下:

option 含义
-a 包括所有可用server状态
-c 包括client状态,即app端情况
-p package 限定输出指定包名

其中WHAT参数可选如下:

WHAT 解释 对应源码
a[ctivities] activity状态 dumpActivitiesLocked()
b[roadcasts] [PACKAGE_NAME] broadcast状态 dumpBroadcastsLocked()
s[ervices] [COMP_SPEC …] service状态 newServiceDumperLocked().dumpLocked
prov[iders] [COMP_SPEC …] content provider状态 dumpProvidersLocked()
p[rocesses] [PACKAGE_NAME] 进程状态 dumpProcessesLocked()
o[om] 内存管理 dumpOomLocked()
i[ntents] [PACKAGE_NAME] pending intent状态 dumpPendingIntentsLocked()
r[ecents] 最近activity dumpRecentsLocked()
perm[issions] URI授权情况 dumpPermissionsLocked()
all 所有activities信息 dumpActivity()
top 顶部activity信息 dumpActivity()
package package相关信息 dump()

最后,附上我用于测试adb 命令的demo:https://github.com/Reoger/adbTest

参考链接

debug 技巧

关于android studio的debug技巧,前面的两篇参考文章已经写的特别好了,也没必要再写一次了,主要就记录一下debug的关键概念和快捷键。至于如何debug,就请参考前面两篇文章。

工具栏介绍

上图从左往右看,名称和作用如下表所示。

名称 作用 备注 快捷键
show Execution Point 定位到当前正在调试的位置 无备注 alt+F10
step over 单步跳过 一步一步执行,遇到方法会直接执行方法,然后进入下一步,不会进入方法内容 F8
step into 单步跳入 单步向下执行,如果当前是自定义方法,hi进入方法内部,系统方法则不进入方法内部 F7
Force step into 强制单步跳入 与单步跳入不同的是,不管什么方法他都会进入 Alt + Shfit + F7
step out 单步跳出 与单步跳入相对,表示从方法体中跳出,回到进入方法的位置,以继续断点 shfit + F8
run to cursor 执行到光标处 直接从当前位置运行到光标处,但是能被中间的断点拦截。 alt + F9
Evalyate Exoression 计算表达式 支持在点点过程中,通过直接赋值或者表达式方式,修改任意表俩个的值。 alt+F8

再加来几个快捷键。

快捷键 功能 说明
右击断点 为断点设置执行条件,或打印信息 只能针对本断点生效
alt + 单击 查看断点时变量的值
ctrl+alt+F8 为断点添加执行条件,或打印信息 这个可以对所有的断点生效

工具篇

uiautorviewer

可以通过这个工具快速定位到UI控件的ID,并通过ID快速找到相应的逻辑。

DDMS

可以利用ddms这个工具,实现截屏,查看线程和堆信息,日志信息,进程,广播状态信息,模拟来电,呼叫和短信等功能。
具体使用方法参考这里https://developer.android.com/studio/profile/monitor.html

命令篇

adb shell am

am 就是activity manager的简称,可以用于启动activity、打开或关闭进程、发送广播等操作。
关于具体的命令,可以参考这里http://blog.csdn.net/soslinken/article/details/50245865.
然后,这里就记录常用的adb shell am命令。
[注:这里默认省略了adb shell]

命令 作用 备注 示例
am start -n <package name>/<ativity name> 启动acivity -n 表示以组件式启动,还可以 am start -a android.settings.INPUT_METHOD_SETTINGS//使用Action方式打开系统设置-输入法设置
am start -a -n --es extra "hello" --ei pid 10 <package name>/<ativity name> 待参数的启动activity –es 表示带string,–ei 表示整型数据,都是以键值对的形式 am start -a -n --es extra "hello" --ei pid 10 com.reoger.app/com.example.cm.myapplication.NextActivity
am broadcast -a <action> 启动广播 还可以通过--user指定用户发送广播 com.android.broadcast.test
am broadcast -a <action> --es <key> <value> 带信息的发送广播 –es表示字符串,还有–ez(布尔值)等多种类型数据,都是以键值对的形式 am broadcast -a com.android.broadcast.test --es adb_extra "hello"
am startservice <package name>/<service name> 启动服务 可以通过--user<USER_ID>指定启动的用户 am startservice com.reoger.app/com.example.cm.myapplication.MyService
am force-stop <package name> 关闭指定包名的应用程序 am force-stop com.reoger.app
am kill <package name> 杀死与应该程序包想关联的所有进程,但只会杀死安全进程 可以通过--user <USER_ID>指定用户 am kill com.reoger.app
am kill -all 杀死全部的后台进程 am kill -all

详情参考这里:http://blog.csdn.net/soslinken/article/details/50245865

adb shell pm

pm即是 package manager的简称,可以用于安装应用、查询应用信息、系统权限、控制应用。

命令 作用 备注 示例
pm list packages [options] [fileter] 打印所有已经安装的应用的包名 options 常用的有-3 表示只显示第三方应用的包名,filter表示按名字筛选 pm list packages -e 显示可用的应用和包名
pm list permission [options] [group] 打印权限 -g表示按组列出,-s表示简短打印 pm list permission-groups 打印所有已知的权限组
grant <package_name> <permission> 授予应用权限 必须android 6.0及以上的设备 grant com.reoger.app android.permission.WRITE_EXTERNAL_STORAGE
revoke <package_name> <permission> 撤销应用权限 必须android 6.0及以上的设备 revoke com.reoger.app android.permission.WRITE_EXTERNAL_STORAGE
pm clear <package name> 清除应用数据 pm clear com.reoger.app
pm enable <package or component> 使得packaege或componet可用 只针对第系统应用 pm enable com.reoger.app
pm hide <package or component> 隐藏package或componet 被隐藏应用在管理中变得不可见,桌面图标也会消失 pm hide com.reoger.app
pm unhide <package or component> 取消隐藏package或componet 桌面图标需要重新添加 pm unhide com.reoger.app

详情请参考这里:https://www.cnblogs.com/JianXu/p/5380882.html

adb shell dumysys

命令 作用
dumpsys cpuinfo 查看CPU信息
dumpsys activity 查看一大堆信息,包括activity、broadcasts、providers、permissions等等信息
dumpsys activity top 获取当前android系统中与用户交互的activity的详细信息
dumpsys activity activities 显示当前所有运行的任务栈,可以与管道- grep XXX结合使用,用于筛选我们需要的任务栈
dumpsys activity meminfo <package name> 显示应用内存使用的情况
dumpsys activity package <package name> 显示apk的信息

其中的dumpsys activity [options] [WHAT]参数可选如下:

option 含义
-a 包括所有可用server状态
-c 包括client状态,即app端情况
-p package 限定输出指定包名

其中WHAT参数可选如下:

WHAT 解释 对应源码
a[ctivities] activity状态 dumpActivitiesLocked()
b[roadcasts] [PACKAGE_NAME] broadcast状态 dumpBroadcastsLocked()
s[ervices] [COMP_SPEC …] service状态 newServiceDumperLocked().dumpLocked
prov[iders] [COMP_SPEC …] content provider状态 dumpProvidersLocked()
p[rocesses] [PACKAGE_NAME] 进程状态 dumpProcessesLocked()
o[om] 内存管理 dumpOomLocked()
i[ntents] [PACKAGE_NAME] pending intent状态 dumpPendingIntentsLocked()
r[ecents] 最近activity dumpRecentsLocked()
perm[issions] URI授权情况 dumpPermissionsLocked()
all 所有activities信息 dumpActivity()
top 顶部activity信息 dumpActivity()
package package相关信息 dump()

最后,附上我用于测试adb 命令的demo:https://github.com/Reoger/adbTest

Gradle 是一个能通过插件形式自定义构建逻辑的优秀构建工具。

以下的一些特性让我们选择了 Gradle:

  • 使用领域专用语言(DSL)来描述和控制构建逻辑
  • 构建文件基于 Groovy,并允许通过 DSL 来声明元素、使用代码操作 DSL 元素这样的混
    合方式来自定义构建逻辑
  • 内置了 Maven 和 Ivy 来进行依赖管理
  • 相当灵活。允许使用最好的实现,但是不会强制实现的形式
  • 插件可以提供它们的 DSL 和 API 来定义构建文件
  • 优秀的 API 工具与 IDE 集成

这里主要记录几个比较常用,重要的点。

android Task

  • assemble 组合项目所有输出,他可以细分成assemableDebugassembleRelease
  • check 执行所有检查,他拥有 lint 依赖
  • connectedCheck 在一个连接的设备或者模拟器上执行检查,他们可以在所有连接的设备上并行执行检查,他拥有connectedAndroidTest依赖
  • deviceCheck 通过APIs连接远程设备来执行检查,主要用于CI(持续集成)服务上。
  • build 执行assemlecheck的所有工作
  • clean 清空项目的输出。
  • installDebug 安装测试版的apk
  • installRelease 安装发布版的apk
  • uninstall 卸载安装,他包含三个动作uninstallDebug卸载测试版本, uninstallRelease卸载发行版本和uninstallDebugAndroidTest卸载android测试。

gradle 添加依赖

gradle的依赖主要分成本地包依赖和远程包依赖。
依赖的关键字主要包括:

  1. compile 源代码(src/main/java)编译时的依赖
  2. runtime 源代码(src/main/java)执行时的依赖
  3. testCompile 测试代码(src/main/test)编译时的依赖
  4. testRuntime 测试代码(src/main/test)执行时的依赖
  5. archives 项目打包时的依赖
  6. provided 只编译,并不将jar包导入到apk中。

依赖格式:

1
2
3
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
}

其中的group表示组织,name表示要依赖的库,vesion表示版本。
我们可以简写成

1
2
3
dependencies {
compile 'org.hibernate:hibernate-core:3.6.7.Final'
}

当然,不单只有对jar包的依赖,还可以有对文件的依赖,对项目的依赖,他们的写法依次如下:

1
2
3
4
5
6
7


dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) //将本地lib目录下所有的jar包进行依赖
compile files('libs/picasso-2.4.0.jar')
compile project(':libraries:lib1') //对项目lib1添加依赖
}

##本地依赖
上面讲到的就是本地依赖的方式:

1
2
3
4
5
6
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
android {
...
}

外部依赖

首先需要添加远程仓库,android中至少添加一个远程仓库,例如使用开放的maven仓库。

1
2
3
repositories{
mavenCentral()
}

然后,就对添加具体依赖。

1
2
3
dependencies{
compile group: 'commons-collections',name: 'commons-collections', version: '3.2'
}

混淆

启动混淆非常简单,只需要在build.gradle中启动即可。

1
2
3
4
5
6
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

其中的minfyEnabled默认是false,即不混淆,因为启动混淆编译速度会比较慢。
与混淆相关的还有一个shrinkResources属性,可以通过将其设置为true,设置资不打包没用的资源。

混淆通用规则:

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
#指定压缩级别
-optimizationpasses 5

#不跳过非公共的库的类成员
-dontskipnonpubliclibraryclassmembers

#混淆时采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

#把混淆类中的方法名也混淆了
-useuniqueclassmembernames

#优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification

#将文件来源重命名为“SourceFile”字符串
-renamesourcefileattribute SourceFile
#保留行号
-keepattributes SourceFile,LineNumberTable

#保持所有实现 Serializable 接口的类成员
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}

#Fragment不需要在AndroidManifest.xml中注册,需要额外保护下
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment

# 保持测试相关的代码
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**

补充的混淆规则:

  1. 第三方库混淆规则。这个比较常见,直接接入官方说明文档。

  2. model实体类,典型在转化json的时候,必须保证model不被混淆,因此需加入–keep public class

  3. JNI中调用的类以及方法不可被混淆

  4. WebView中JavaScript调用的接口不混淆

  5. AndroidMainfest、四大组件以及Application的子类不混淆

  6. Parcelable的子类和Creator静态成员变量不混淆,否则会产生Android.os.BadParcelableException异常

  7. Layout布局使用的View构造函数、android:onClick等。

apk打包流程

打包流程

  1. aapt打包res资源文件,生成R文件。
  2. 处理aidl,生成java文件
  3. 编译java 生成class文件
  4. 通过dex命令,将class文件生成dex文件
  5. apkbuilder阶段,将资源、dex、so合并成apk
  6. 对apk进行签名
  7. zipalign阶段,将签名后的apk进行对齐

参考连接

sdk 目录下各目录详解

sdk目录下的目录如下:
dir.png

下面针对一些工具进行介绍:

  1. add-ons
    这里保存着附加库,第三方公司为Android平台开发的附加功能。例如googleMaps
  2. build tools(重要)
    这里保存着一些Android开发常用的工具,例如adb、aidl等等。下面是我的tools目录下的工具包。
    platforms.png
  • android
    这个其实就是Android SDK Manager,用于管理SDK的下载、更新和删除。
  • ddms
    这个工具集成了Dalvik(为Android 平台定制的虚拟机(VM)),能够让你在模拟器或者设备上管理进程并协助调试。你可以使用它杀死进程,选择某个特定的进程来调试,产生跟踪数据,观察堆(heap)和线程信息,截取模拟器或设备的屏幕画面,还有更多的功能。
  • draw9patch
    该工具允许你使用所见即所得(WYSIWYG)的编辑器轻松地创建NinePatch图形。它也可以预览经过拉伸的图像,高亮显示内容区域。
  • hierarchyviewer
    Hierarchyview和UiAutomatorviewer作用类似,都是用于查看当前界面控件,但Hierarchyviewer能显示的属性更为全面(设备需要root,调用的API权限比UiAutomator更高)
  • jobb
    这个工具可以用来加密、解密apk
  • lint
    是代码扫描分析工具,它可以帮助我们发现代码结构/质量问题,同时提供一些解决方案,而且这个过程不需要我们手写测试用例。
  • mksdcard
    帮助你创建磁盘映像(disk image),你可以在模拟器环境下使用磁盘映像来模拟外部存储卡(例如SD 卡)。
  • monitor
    Monitor工具具有强大的监控功能,他提供良好界面和众多监控功能,包括devicse监控、update Heap、
  • monkeyrunner
    的压力测试应用,模拟用户随机按键。
  • traceview
    这个工具可以将你的Android 应用程序产生的跟踪日志(trace log)转换为图形化的分析视图。
  • uiautomatorviewer
    用于进行UI测试。
  1. docs
    这里面是Android SDK API参考文档。
  2. emulator
    这里存放的是一些安卓模拟器
  3. extras
    扩展开发包,在此文件夹下保存着额外的usb驱动、intel硬件加速。
  4. patcher
    增量更新,用于更新记录。
  5. platforms
    是每个平台SDK真正的文件,存放不同版本的Android系统。里面会根据APILevel划分的SDK版本,本人下载的是Android 23,进入之后的目录如下:
    platforms-tools.png
    针对上面的目录简单介绍如下;
  • data
    保存着一些系统资源。
  • optional
    存放一些可选择的支持库,譬如http client就可以依赖本目录下的org.apache.http.legacyjar包。
  • skins
    存这Android模拟器的皮肤。
  • templates
    工程的默认模板。
  1. platforms-tools(重要)
    版本通用的工具,比如adb、aidl、dexdump等等。目录结果如下:
    tools.png
  • adb
    Android Debug Bridge,Android调试桥接器,简称ADB,是用于管理模拟器或真机状态的万能工具,通俗一点讲adb就是pc和移动设备通信的桥梁,它采用了c/s模型,包括三个部分:客户端部分、服务端部分和守护进程部分。
  • dmtracedump
    是将整个调用过程和时间分析结合,以函数调用图的形式表现出来。
  • etc1tool
    etc1tool是一个命令行工具,可以将PNG图像压缩为etc1标准,并且可以进行解压缩。
  • fastboot
    Fastboot是Android快速升级的一种方法,Fastboot的协议fastboot_protocol.txt在源码目录./bootable/bootloader/legacy下可以找到。
    Fastboot客户端是作为Android系统编译的一部分,编译后位于./out/host/linux-x86/bin/fastboot目录下。
    Fastboot命令实例:sudo fastboot flash kernel path-to-kernel/uImage
    烧写rootfs类似:sudo fastboot flash system path-to-system/system.img
  • hprof-conv
    hprof-conv工具可以将Android SDK工具生成的HPROF文件生成一个标准的格式,主要用于性能测试。
  • make_f2fs
    转化成f2fs文件格式的文件。
  • mke2fs
    mke2fs命令被用于创建磁盘分区上的“etc2/etc3”文件系统。
  • sqlite3
    在adb命令模式下,查看数据库的信息。
  1. skins
    Android模拟器的皮肤。
  2. sources
    各版本的sdk源码。
  3. system-images
    模拟器映像文件。从android-14开始将模拟器映像文件整理在这里(原来放在platforms下)
  4. tools
    各个版本自带工具,包含重要的工具DDMS
  5. AVD Manager
    Android手机模拟配置工具,用于配置模拟器。
  6. SDK maager
    SDK管理器,用于SDK的更新、下载、删除。

参考链接:

mysql是一个比较轻量级的数据库,在日常的开发过程中经常会用到,这里记录一下我在用mysql数据库时遇到的坑。

坑一,check约束无效。

在使用mysql数据库的时候,我们经常需要对数据进行约束,例如,我们有一个这样的表,

user_id user_name user_sex user_age user_socer
int varchar(10) varchar(1) int int

对应的mysql常见语句可以为:

1
2
3
4
5
6
7
8
CREATE TABLE `usr` (
`user_id` int(11) NOT NULL,
`user_name` varchar(10) NOT NULL,
`user_sex` varchar(1) NOT NULL,
`user_age` int(11) NOT NULL,
`user_socer` int(11) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

注意,这里指定的主键为use_id,且指定的方式入上述语句。

这个时候,如果我们想对其中的项进行约束,例如user_sex,我们只希望出现f代表女生,和m代表男生,其他的值都是无效的,这个时候用check语句是没有效果的,这个时候我们可以通过enum或者set类型来对其数据进行约束,具体实现为:
方式一:
创建时指定:

1
2
3
4
5
6
7
8
CREATE TABLE `usr` (
`user_id` int(11) NOT NULL,
`user_name` varchar(10) NOT NULL,
`user_sex` SET('f','m') NOT NULL,
`user_age` int(11) NOT NULL,
`user_socer` int(11) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

或者用enum来实现:

1
2
3
4
5
6
7
8
CREATE TABLE `usr` (
`user_id` int(11) NOT NULL,
`user_name` varchar(10) NOT NULL,
`user_sex` enum('f','m') NOT NULL,
`user_age` int(11) NOT NULL,
`user_socer` int(11) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

方式二:
在已经创建表的基础上,修改表的数据类型:

1
ALTER TABLE usr MODIFY COLUMN user_sex SET('f','m');

或者

1
ALTER TABLE usr MODIFY COLUMN user_sex enum('f','m');

至于添加其他的约束条件可以参考这里.

坑二,无法建立外键约束

如果公共关键字在一个关系中是主关键字,那么这个公共关键字被称为另一个关系的外键。由此可见,外键表示了两个关系之间的相关联系。以另一个关系的外键作主关键字的表被称为主表,具有此外键的表被称为主表的从表。

先记录一下完整的外键建立流程吧,假设我们已经建立了上面的usr数据库,我们还需要建立一个action数据库来记录用户的行为,其各内容如表格所示:
|action_id|action_user_id|action_time|action_conten|
|—-|—|—|–|
|int|int|time|varchar(50)|

我们可以使用如下的sql语句进行创建:

1
2
3
4
5
6
7
CREATE TABLE `action` (
`action_id` int NOT NULL ,
`action_user_id` int NOT NULL ,
`action_time` time NOT NULL ,
`action_content` varchar(50) NOT NULL ,
PRIMARY KEY (`action_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建完成之后,我们需要在actionusr表中创建索引。本例中,我们将设置usr表中的usr_idaction表中action_usr_id的外键,下面介绍三种方式来创建外键。

首先介绍建立外键的几个必要条件:

  • 两个表必须是InnoDB表类型。
  • 使用在外键关系的域必须为索引型(Index)。
  • 使用在外键关系的域必须与数据类型相同。
  • 外键的不能是主键

稍微对上面的必要条件进行一个简单的说明,

方式一、通过sql语句

1.创建索引
首先为user表中的user_id创建索引:

1
ALTER TABLE usr ADD INDEX idx_user (user_id);

这里的idx_user是创建的索引的名字,并不重要,我们可以随便去,并且我们后面也不会用到它。我们只需要创建了他就好了。
下面我们来为action表中的action_user_id创建索引:

1
ALTER TABLE action ADD INDEX idx_action (action_user_id);

2.创建外键

再创建了索引之后,我们就可以创建外键了,sql语句如下:

1
2
3
ALTER TABLE `action` ADD FOREIGN KEY (`action_user_id`) 
REFERENCES `usr` (`user_id`)
ON DELETE RESTRICT ON UPDATE RESTRICT;

这里对上面的sql语句进行一个简单的说明,第一行指定了我们的外键为action表中的action_user_id
第二行指定了从键为usr表中的user_id;至于第三行代码,主要对外键的属性进行设置,简单介绍一下四个属性的作用:

  • RESTRICT :父表删除(更新)且外键对应子表记录存在时,则不允许删除(更新)。
  • CASCADE :父表删除(更新)时,外键对应子表记录同时删除(更新)。
  • SET NULL :父表删除(更新)时,外键对应子表记录同时置为NULL.(必须允许为NULL)
  • NO ACTION:父表删除(更新)且外键对应子表记录存在时,则不允许删除(更新)。

到此,我们的外键就建立完毕了,如果一切比较顺利的话还是比较简单的。
上面是通过sql语句直接创建外键,不是特别直观,下面通过介绍两个工具的使用来介绍如何创建外键。

方式二、通过phpMyAdmin创建

1.创建索引
创建索引
相同的,我们也需要为action表中的action_user_id也创建一个索引。

2.创建外键

创建外键

创建外键成功

方式三、通过navicat创建

  1. 创建索引

这一步可以省略,因为通过navicat创建外键时会自动创建索引,这一步也可以手动操作。

选择: 设计表 -> 索引 -> 填写相应参数 -> 保存。

创建索引
2. 创建外键
创建外键也很简单,只需要选择:
设计表 -> 外键 -> 填写相应参数 -> 点击保存。即可。

创建外键

坑:外键和从键的类型和长度必须一致,甚至于属性也需要一致,否则会创建失败,创建失败的的代号为:1215 。
提示为:1215 Cannot add the foreign key constraint。
这个时候就仔细查看一下主从建之间是不是存在某些差别。

参考链接

之前在window 10上安装elasticSearch是很简单的,但是真正要linux系统上安装时,还是出现了许多的问题,下面就是我记录的我遇到的一些问题。

整体流程

  1. 下载elasticSearch5.6.1的压缩包,然后解压到指定文件夹下,参考解压命令:
1
tar -zxvf elasticsearch5.6.1.tar
  1. 为其创建新用户(root用户无法启动),参考命令如下:

    1
    2
    3
    [root]# adduser elsearch
    [root]# passwd elsearch
    [root]# chown -R elsearch:elsearch elasticSearch5.6.1/
  2. 切换到指定用户,并运行.参考命令:

    1
    2
    3
    4
    5
    [root]# su elsearch
    [elsearch]$ cd elasticSearch5.6.1/bin
    [elsearch]$ ./elasticSearch

    在正常启动之后,应该就能通过访问http://localhost:9200来使用elasticsearch了
  3. 配置ip地址访问。
    这里和windows下修改的地方一样,但是不一样的是,这里出现的问题会很多,要修改的内容参考如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    vim  elasticsearch-5.6.1/config/elasticsearch.yml

    ---
    cluster.name: EsMaster # 集群master的名称

    node.name: master # 当前结点的名称
    node.master: true # 设置为master节点

    bootstrap.memory_lock: false # 关闭内存锁定
    bootstrap.system_call_filter: false

    network.host: 127.0.0.1 # 这里修改成你要绑定的id


    http.cors.enabled: true # 设置跨域访问,为后面的head-master的配置
    http.cors.allow-origin: "*"

    ---
    保存,重启elasticsearch,发现诸多问题,下面是我遇到一些问题的记录。
  4. 问题及解决方案

    1
    2
    3
    4
    5
    6
    7
    ERROR: [3] bootstrap checks failed
    #文件句柄太少,至少要65536
    [1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
    #最大线程数太少,至少2048个(经典的2048游戏)
    [2]: max number of threads [1024] for user [king] is too low, increase to at least [2048]
    #虚拟内存太少,至少262144
    [3]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

[1]解决方案:

1
2
3
4
5
6
7
[root]# vi /etc/security/limits.conf

# 添加如下配置:
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096

[2]解决方案:

1
2
3
4
5
6
[root]#  vi /etc/security/limits.d/90-nproc.conf 


* soft nproc 1024
改成
* soft nproc 2048

[3]解决方案:

1
2
3
4
5
6
[root]# vim /etc/sysctl.conf 
添加如下代码:
vm.max_map_count=655360

保存后,执行
sysctl -p

最后,还有一个错:

1
system call filters failed to install; check the logs and fix your configur                                                                                                             ation or disable system call filters at your own risk

解决方案:
在elasticsearch.yml文件中配置如下:

1
2
3
4
5
[root]# vim elasticsearch.yml

---
bootstrap.memory_lock: false
bootstrap.system_call_filter: false

差不多解决上面的问题,应该就能正常运行elsearch了。

远程访问

我这里是利用ssh进行远程访问,记录一下基础的运行方式:
避免断开连接后elasticsearch就停止运行的运行方式:

1
nohup bin/elasticsearch &

当然,也直接直接进行如下命令来运行:

1
bin/elasticsearch -d

关闭ElasticSearch服务就需要用到ps命令,参考如下:

1
2
3
4
5
6
[elsearch]$  ps -ef|grep elastic
elsearch 22097 1 0 15:06 ? 00:01:24 /usr/bin/java -Xms2g -Xmx2g
...


[root]# kill -9 22097

【ps】 在选择启动方式的时候,虽然两种方式都能通过ssh启动elasticsearch服务,但是笔者实践证明,非主节点通过bin/elasticsearch -d这条命令启动的服务不能加入到集群中,所以推荐多用nohup bin/elasticsearch &来避免踩雷。

还有一点就是安装head-master,其实也没有太多的坑,只需要按照步骤一步一步来就OK了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
git clone git://github.com/mobz/elasticsearch-head.git
(如果 没有安装git,也可以采用其他方式下载head-master)

cd elasticsearch-head

npm install

(如果提示npm是无效命令,则需要先安装npm,参考步骤如下)

--安装npm
curl --silent --location https://rpm.nodesource.com/setup_5.x | bash -

yum install -y nodejs

输入下面的命令是检验:
[root@]# node -v

[root@]# npm -v
如果不提示是无效命令即成功安装。
----

在安装之后,进行简单的配置:
修改elasticsearch-head下Gruntfile.js文件,默认监听在127.0.0.1下9200端口:
connect关键字下,options项中添加一项:

1
hostname: '0.0.0.0',

保存退出后,输入

1
npm run start

来启动head-master。
然后通过浏览器 http://localhost:9100 来访问。

到此,记录结束。


最后,记录两个比较有用的操作命令

远程启动服务:

1
2
3
4
5
6
方式1:

nohup bin/elasticsearch &

方式2:
./elasticsearch -d

远程关闭服务:

1
2
3
4
5
通过: 
ps -ef|grep elastic
获取elastic的PID
然后通过kill命令杀死就OK:
kill -9 22789

彩蛋

抄袭一下利用pscp传输文件的命令。

1、把服务器上的/root/dir目录取回本地”C:\My Documents\data"目录

1
C:\>pscp.exe -r root@192.168.32.50:/root/dir "C:\My Documents\data\"

2、把服务器上的/root/file文件取回来本地当前目录

1
C:\>pscp.exe root@192.168.32.50:/root/file .

3、把本地目录dir、文件file传输到Linux服务器的/root/,并指定服务器端口2009

1
C:\>pscp.exe -P 2009 -r dir file root@192.168.32.50:/root/

4、把本地文件file传输到Linux服务器的/root/

1
C:\>pscp.exe file root@192.168.32.50:/root/

它会提示你输入密码,就像Linux下使用scp那样。

参考链接