长连接与短连接以及Android的socket-IO

TCP/IP是什么?

TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。

在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
在传输层中有TCP协议与UDP协议。
在应用层有FTP、HTTP、TELNET、SMTP、DNS等协议。

Socket是什么呢?

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,一组接口,把复杂的TCP/IP协议族隐藏在Socket接口后面

#短连接

连接->传输数据->关闭连接

HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。
也可以这样说:短连接是指SOCKET连接后发送后接收完数据后马上断开连接。

#长连接

连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。

长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。

http的长连接:
HTTP也可以建立长连接的,使用Connection:keep-alive,HTTP 1.1默认进行持久连接。HTTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持(貌
似最新的 http1.0 可以显示的指定 keep-alive),但还是无状态的,或者说是不可以信任的。

参考文章

http://www.jianshu.com/p/584707554ed7

http://blog.csdn.net/sdkfjksf/article/details/51645315

Android H5 采用Gradle管理离线包

H5离线访问

离线访问,就是先将H5放在本地,提高加载速度

H5要有一个版本号(线上版本号)

为了实现同一资源的线上和离线访问,Native需要对H5的静态资源请求进行拦截判断,将静态资源“映射”到sd卡资源,即实现一个处理H5资源的本地路由

H5 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import com.squareup.okhttp.OkHttpClient
import com.squareup.okhttp.Request
import com.squareup.okhttp.Response
import groovy.json.JsonSlurper

import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream

buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.squareup.okhttp:okhttp:2.4.0'
}
}

task updateH5 << {
File tmp = new File("Meiya/build/tmp/h5")
File assets_h5 = new File("Meiya/assets/h5")

def deleteFile;
deleteFile = { File file ->
if (!file.exists()) return
if (file.isFile()) {
file.delete();
} else {
file.listFiles().each {
deleteFile(it)
}
file.delete()
}
}
deleteFile(tmp)
deleteFile(assets_h5)

assets_h5.mkdirs()
tmp.mkdirs()

// def SIGNATURE = "knOV3ucpaNHZ6wpiXIkyK3acasNWz8bbskYxMkPu5zNImXKssgFkgpn020D5"
// def URL_HOST_MEIYA = "api.meiyaapp.com"

// def URL_CONFIGURATION = "http://${URL_HOST_MEIYA}/v1/configurations?signature=${SIGNATURE}"

OkHttpClient client = new OkHttpClient();
JsonSlurper slurper = new JsonSlurper()

//先获取最新的h5版本
// def h5_version = slurper.parseText(
// httpGetString(client, URL_CONFIGURATION)).data.h5_version
def h5_version = project.H5_VERSION
println "h5 version: ${h5_version}"

//再获取所有的zip包下载地址。
def h5_package_map_string = httpGetString(client, "http://st0.meiyaapp.com/app/${h5_version}/H5PackageMap.json");
//H5PackageMap.json --> Meiya/assets/h5/H5PackageMap.json
writeToLocalH5PackageMapFile(h5_package_map_string, assets_h5)
def h5_package_map = slurper.parseText(h5_package_map_string)

//下载所有的zip包。

h5_package_map.H5PackageList.values().each { value ->
//http://st0.meiyaapp.com/app/a0d6fce8f08fb3c5617e.zip ---> Meiya/build/tmp/h5/a0d6fce8f08fb3c5617e.zip
httpDownloadFile(client, value, new File(tmp, parseFileNameFromUrl(value)))
}
//解压
tmp.listFiles().each { zip ->
if (zip.getName().endsWith("zip")) {
//Meiya/build/tmp/h5/a0d6fce8f08fb3c5617e.zip --> a0d6fce8f08fb3c5617e/*
unZipIt(zip.getAbsolutePath(), tmp.getAbsolutePath())

String md5 = removeExtFromFileName(zip.getName())
File src = new File(tmp, md5)
File asset_dest = new File(assets_h5, md5)
if (!src.exists()) {
throw new Exception(src.getAbsolutePath() + " is not exited")
}
if (!src.renameTo(asset_dest)) {
throw new Exception(src.getAbsolutePath() + " rename failed.")
}
println "${src.getAbsolutePath()} --> ${asset_dest.getAbsolutePath()}"
}
}
"git status".execute()
"git add . --all".execute()
println "git commit -m \"Update h5 to $h5_version\""
}

/**
* Unzip it
* @param zipFile input zip file
* @param output zip file output folder
*/

private void unZipIt(String zipFile, String outputFolder) {


byte[] buffer = new byte[1024];

try {
//create output directory is not exists
File folder = new File(outputFolder);
if (!folder.exists()) {
folder.mkdir();
}

//get the zip file content
ZipInputStream zis =
new ZipInputStream(new FileInputStream(zipFile));
//get the zipped file list entry
ZipEntry ze = zis.getNextEntry();

while (ze != null) {
String fileName = ze.getName();
File newFile = new File(outputFolder + File.separator + fileName);

if (ze.isDirectory()) {
newFile.mkdirs()
ze = zis.getNextEntry();
continue;
}

// System.out.println("file unzip : " + newFile.getName());

//create all non exists folders
//else you will hit FileNotFoundException for compressed folder
new File(newFile.getParent()).mkdirs();

FileOutputStream fos = new FileOutputStream(newFile);

int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}

fos.close();
ze = zis.getNextEntry();
}

zis.closeEntry();
zis.close();

System.out.println("Done");

} catch (IOException ex) {
ex.printStackTrace();
}
}

private String writeToLocalH5PackageMapFile(String content, File assets_h5) {
File local_h5_package_map_file = new File(assets_h5, "H5PackageMap.json")
local_h5_package_map_file.delete()

local_h5_package_map_file << content
}

private String parseFileNameFromUrl(String url) {
if (url.contains("?")) {
url = url.substring(0, url.lastIndexOf("?"));
}
return url.substring(url.lastIndexOf('/') + 1, url.length());
}

private String removeExtFromFileName(String fileName) {
return fileName.substring(0, fileName.lastIndexOf('.'));
}

private String httpGetString(OkHttpClient client, String url) {
Request req = new Request.Builder()
.url(url)
.header("Accept", "application/json")
.build();
Response response = client.newCall(req).execute()

return response.body().string()
}

private void httpDownloadFile(OkHttpClient client, String url, File dest) {
if (dest.exists()) return

Request req = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(req).execute()

def out = dest.newOutputStream()
out << response.body().byteStream()
out.flush()
out.close()
}

#参考文章

https://segmentfault.com/a/1190000004263182

Android RecycleView 图片瀑布流的实现

布局文件

1
2
3
4
<android.support.v7.widget.RecyclerView
android:id="@+id/vRecycleView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

初始化RecycleView

1
2
3
4
5
6
7
private void initRecyclerView(RecyclerView recyclerView) {
recyclerView.setHasFixedSize(true); // 设置固定大小
initRecyclerLayoutManager(recyclerView); // 初始化布局
initRecyclerAdapter(recyclerView); // 初始化适配器
initItemDecoration(recyclerView); // 初始化装饰
initItemAnimator(recyclerView); // 初始化动画效果
}

初始化适配器

1
2
3
4
private void initRecyclerAdapter(RecyclerView recyclerView) {
mAdapter = new MyImageAdapter(mGanHuoDataList,getContext());
recyclerView.setAdapter(mAdapter);
}

初始化布局

1
2
3
4
5
private void initRecyclerLayoutManager(RecyclerView recyclerView) {
// 错列网格布局
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,
StaggeredGridLayoutManager.VERTICAL));
}

初始化分割线

1
2
3
private void initItemDecoration(RecyclerView recyclerView) {
recyclerView.addItemDecoration(new MyItemDecoration(getContext()));
}

初始化动画效果

1
2
3
private void initItemAnimator(RecyclerView recyclerView) {
recyclerView.setItemAnimator(new DefaultItemAnimator()); // 默认动画
}

适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
GanHuoData ganHuoData=mGanHuoDataList.get(position);
//随机高度模仿瀑布流
if(mHeights.size()<=position){
mHeights.add((int)(500+Math.random()*300));
}
ViewGroup.LayoutParams lp=holder.ivImage.getLayoutParams();
lp.height=mHeights.get(position);
holder.ivImage.setLayoutParams(lp);
holder.itemView.setLayoutParams(lp);
Glide.with(mContext).load(ganHuoData.url).placeholder(R.mipmap.small).into(holder.ivImage);

}


<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:id="@+id/ivImage"
xmlns:android="http://schemas.android.com/apk/res/android"/>
//注意 ScaleType要设定不然高度有问题

分割线装饰

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
public class MyItemDecoration extends RecyclerView.ItemDecoration {

private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
private Drawable mDivider;

public MyItemDecoration(Context context) {
final TypedArray array = context.obtainStyledAttributes(ATTRS);
mDivider = array.getDrawable(0);
array.recycle();
}

@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawHorizontal(c, parent);
drawVertical(c, parent);
}

// 水平线
public void drawHorizontal(Canvas c, RecyclerView parent) {

final int childCount = parent.getChildCount();

// 在每一个子控件的底部画线
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);

final int left = child.getLeft() + child.getPaddingLeft();
final int right = child.getWidth() + child.getLeft() - child.getPaddingRight();
final int top = child.getBottom() - mDivider.getIntrinsicHeight() - child.getPaddingBottom();
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}

// 竖直线
public void drawVertical(Canvas c, RecyclerView parent) {

final int childCount = parent.getChildCount();

// 在每一个子控件的右侧画线
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
int right = child.getRight() - child.getPaddingRight();
int left = right - mDivider.getIntrinsicWidth();
final int top = child.getTop() + child.getPaddingTop();
final int bottom = child.getTop() + child.getHeight() - child.getPaddingBottom();

mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}

// Item之间的留白
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight());
}
}

项目地址

https://github.com/guosen/Volley

Android 动画初探

#Tween动画
(Creates an animation by performing a series of transformations on a single image with an Animation)

  • 缩放
  • 平移
  • 渐变
  • 旋转

    xml实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?xml version="1.0" encoding="utf-8"?>
    <set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together"
    android:duration="2000">
    <alpha
    android:fromAlpha="1.0"
    android:toAlpha="0.0"
    ></alpha>
    <scale
    android:fromXScale="0"
    android:fromYScale="0"
    android:pivotX="0.5"
    android:pivotY="0.5"
    android:toXScale="50dp"
    android:toYScale="50dp"/>
    </set>
    //alpha 渐变透明度动画效果
    //scale 渐变尺寸伸缩动画效果
    //translate 画面位置移动动画效果
    //rotate 画面旋转动画效果

###调用动画

1
2
3
ImageView image = (ImageView) findViewById(R.id.image);
Animation hyperspaceJump = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
image.startAnimation(hyperspaceJump);

插值器

用于修改一个动画过程中的速率,可以定义各种各样的非线性变化函数,比如加速、减速等。

在Android中所有的插值器都是Interpolator 的子类,通过 android:interpolator 属性你可以引用不同的插值器

#Frame 动画

逐帧播放动画

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"] >
<item
android:drawable="@[package:]drawable/drawable_resource_name"
android:duration="integer" />
</animation-list>

调用代码

1
2
3
4
ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketAnimation.start();</span>

#参考文献
http://www.lightskystreet.com/2015/05/23/anim_basic_knowledge/

AndFix使用说明(android 热修复打补丁)

#介绍

开源框架阿里巴巴的AndFix,允许APP在不重新发布版本的情况下修复线上的bug。支持Android 2.3 到 6.0。

#使用方式

##添加依赖库

1
compile 'com.alipay.euler:andfix:0.4.0@aar'

##添加so文件
可以参考https://github.com/zhonghanwen/AndFix-Ndk-Build-ADT

#Application代码

##

1
2
3
patchManager = new PatchManager(this);
patchManager.init(getAppVersion());//current version
patchManager.loadPatch();


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
try {
patchManager.addPatch(Environment.getExternalStorageDirectory() + "/v.apatch");
Log.i("MyApplication","success");
}catch (Exception ex){
Log.i("MyApplication",ex.getMessage());
Log.i("MyApplication",Environment.getExternalStorageDirectory().toString());
}

public String getAppVersion(){
String appversion="";
try {
appversion = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
}catch (PackageManager.NameNotFoundException ex){

}finally {

}

return appversion;
}

#生成补丁文件Patch

##工具 apkpatch

1
./apkpatch.sh -f volly2.apk -t volly.apk -k guosen.jks -p 123456 -a lin -e 123456

2016 新浪微博 Android 面试题

静态内部类、内部类、匿名内部类,为什么内部类会持有外部类的引用?持有的引用是this?还是其它?

##
1.静态内部类:使用static修饰的内部类
2.匿名内部类:使用new生成的内部类
3.因为内部类的产生依赖于外部类,持有的引用是类名.this。

ArrayList和Vector的主要区别是什么?

ArrayList在Java1.2引入,用于替换Vector

Vector:

##
-线程同步
-当Vector中的元素超过它的初始大小时,Vector会将它的容量翻倍

#ArrayList:

##
1.线程不同步,但性能很好
2.当ArrayList中的元素超过它的初始大小时,ArrayList只增加50%的大小

#Java中try catch finally的执行顺序

##先执行try中代码发生异常执行catch中代码,最后一定会执行finally中代码

#switch是否能作用在byte上,是否能作用在long上,是否能作用在String上?

##switch支持使用byte类型,不支持long类型,String支持在java1.7引入

#Activity和Fragment生命周期有哪些?

##

1
2
 Activity——onCreate->onStart->onResume->onPause->onStop->onDestroy
Fragment——onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestroyView->onDestroy->onDetach

#onInterceptTouchEvent()和onTouchEvent()的区别?

onInterceptTouchEvent()用于拦截触摸事件

onTouchEvent()用于处理触摸事件

#RemoteView在哪些功能中使用

##APPwidget和Notification中

#SurfaceView和View的区别是什么?

##SurfaceView中采用了双缓存技术,在单独的线程中更新界面
View在UI线程中更新界面

#讲一下android中进程的优先级?

#一面

##service生命周期,可以执行耗时操作吗?
JNI开发流程
Java线程池,线程同步
自己设计一个图片加载框架
自定义View相关方法
http ResponseCode
插件化,动态加载
性能优化,MAT
AsyncTask原理

#二面
所使用的开源框架的实现原理,源码
没看过,被pass了
去面试之前把用到的开源框架源码分析一定要看看啊

Android 触摸事件分发详解(翻译)

#android 怎样处理触摸事件

1.每一个用户触摸事件都被当作是一个MotionEvent对象;

2.描述用户的当前行为
-ACTION_DOWN
-ACTION_UP
-ACTION_MOVE
-ACTION_POINTER_DOWN
-ACTION_POINTER_UP
-ACTION_CANCEL
3.数据包括
-触摸的位置(x,y)
-手指数
-时间点
4.手势(gesture)就是从ACTION_DOWN到ACTION_UP之间过程

#android处理触摸事件流程
1.事件的起始点是Activity的dispatchTouchEvent()
2.事件是从上一层往下传递(ViewGroup->子View),并且可以在任意一层intercept(拦截事件)
3.任何没有被消费的事件最终都会到Activity的onTouchEvent()去处理
4.监听器onTouchListener可以拦截onTouch()z在任意一个View和viewGroup;

#android处理触摸事各个流程
1.Activity.dispatchTouchEvent()
这个是最先被调用的
分发事件到Root view(attch to window)
2.view.onTouchEvent()
-发送事件到监听(如果有view.onTouchListener.onTouch())
-如果没有消费会调用自己的View.onTouchEvent()
3.viewGroup.dispatchTouchEvent()
-oninterceptTouchEvent(检查是否粗腰传递给子View)
-对于每个子控件,以相反的顺序分发事件
-如果没有子控件处理事件,就会传到OnTouchListener.onTouch()
-如果没有监听 onToucheEvent()
4.Intercept (拦截事件)跳过子控件

#自定义Touch事件
1.重写onTouchEvent方法;
2.消费事件(return true)
3.有用的常量ViewConfiguration
-getScaledTouchSlop()
(拖动最短距离)
-getScaledMinimumFlingVelocity(最少平滑距离)
-getLongPressTimeout()
判定为长按时间值;

原文:http://trinea.github.io/download/pdf/android/PRE_andevcon_mastering-the-android-touch-system.pdf
事例项目:https://github.com/guosen/custom-touch-examples

Android 网络请求OKHttp+Retrofit

#简介

Retrofit是Square开发的网络服务库, 简化Get/Post网络服务的使用, 配合Rx和Dagger有更好的效果. Retrofit已经更新到第2.0版, 本文介绍一些常见的使用方式.

https://github.com/guosen/Volley

#引入(gradle)

##

1
2
3
4
compile 'com.android.support:appcompat-v7:23.2.1'
compile 'com.squareup.retrofit:retrofit:2.0.0-beta1'
compile 'com.squareup.okhttp:okhttp:2.4.0'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Created by shouwang on 16/4/7.
*/
public interface ApiService {
String END_POINT="http://api.meiyaapp.cn/";

@Headers("Cache-Control: public, max-age=3600")
@GET("v1/users/{id}?signature=123456")
Call<HttpResponse<UserInfo>> getUserInfo(
@Path("id") int id,
@Query("with_recipients") int with_recipients,
@Query("with_talent") int with_talent
);
}
//其中的@Headers 是在这边增加头部 实现缓存功能

注:在retrofit2.0里去掉了CallBack接口参数。

#定义接口服务类,用来管理和创建ApiService

##

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
public class ApiManager {
public static final String HEADER_ACCEPT_JSON = "application/json";
public static final String HEADER_ACCEPT = "Accept";
private ApiService mApiService;
private static ApiManager sInstance;
private Context mContext;
public ApiManager(Context context) {
mContext=context;
}

private ApiService createService() {
OkHttpClient client=new OkHttpClient();
//----------
//设置头部 例如返回类型是Json/text
//-----------
client.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
final Request originalRequest = chain.request();
final Request requestWithUserAgent = originalRequest.newBuilder()
.addHeader(HEADER_ACCEPT, HEADER_ACCEPT_JSON)
.build();
Response response = chain.proceed(requestWithUserAgent);
return response;
}
});
//日志拦截 https://github.com/square/okhttp/wiki/Interceptors
client.interceptors().add(new LoggingInterceptor());
client.interceptors().add(new CacheInterceptor(mContext));

File cacheFile = new File(mContext.getCacheDir(), "[缓存目录]");
Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb
client.setCache(cache);




//设置请求 并设置HttpClient (OKHttp)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiService.END_POINT)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();


return retrofit.create(ApiService.class);

}

public ApiService getService() {
if (mApiService == null) {
synchronized (this) {
if (mApiService == null)
mApiService = createService();
}
}
return mApiService;
}

public static ApiManager getInstance(Context context) {
if (sInstance == null) {
sInstance = new ApiManager(context.getApplicationContext());
}
return sInstance;
}

#Interceptor

##Interceptor是拦截器, 在发送之前, 添加一些参数, 或者获取一些信息. loggingInterceptor是打印参数.

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
public class CacheInterceptor implements Interceptor {
private Context mContext;
public CacheInterceptor(Context context){
mContext=context;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if(!NetworkUtil.isNetworkAvailable(mContext)){
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
// Logger.t(TAG).w("no network");
}
Response originalResponse = chain.proceed(request);
if(NetworkUtil.isNetworkAvailable(mContext)){
//有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
String cacheControl = request.cacheControl().toString();
return originalResponse.newBuilder()
.header("Cache-Control", cacheControl)
.removeHeader("Pragma")
.build();
}else{
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=2419200")
.removeHeader("Pragma")
.build();
}
}
}

#Activity里的调用

##

1
2
3
4
5
6
7
8
9
10
11
12
13

Call<HttpResponse<UserInfo>> call=ApiManager.getInstance(this).getService().getUserInfo(91625, 0, 0);
call.enqueue(new Callback<HttpResponse<UserInfo>>() {
@Override
public void onFailure(Throwable t) {
Log.i("MainActivity",t.getMessage());
}

@Override
public void onResponse(Response<HttpResponse<UserInfo>> response, Retrofit retrofit) {
Log.i("MainActivity",response.body().data.username+" ++++++++++");
}
});

Hexo Yilia 主题配置基于swiftype的站内搜索引擎

swiftype

swiftype是为web及移动提供站内搜索的服务,原理十分简单,就是抓取你所配置的网页数据。

#注册

https://swiftype.com/ 在网站上注册账号,获取Key以及安装脚本;

#修改配置文件

##打开Yilia的_config.yml文件吗,末尾加入如下代码

1
2
swift_search:
enable: true

打开目录hexo\themes\yilia\layout_partial,打开文件left-col.ejs

添加 swiftype 代码

1
2
3
4
5
6
<% if (theme.swift_search&&theme.swift_search.enable){ %>
<form class="search" action="<%- config.root %>search/index.html" method="get" accept-charset="utf-8">
<label>Search</label>
<input type="text" id="st-search-input" class="st-default-search-input " maxlength="30" placeholder="Search" />
</form>
<% } %>

在主题目录的css/style.styl文件添加

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
.search
padding 1em 0 0 2.5em
input
line-height line-height+0.2
border 1px solid color-white
color color-white
background transparent
padding-left 4em
@media tablet
width 4em
transition .5s width
&:focus
width 8em
label
display none
form input.st-default-search-input {
font-size: 12px;
padding: 4px 9px 4px 27px;
height: 20px;
width: 190px;
position: absolute;
left: 32px;
top: 70px;
color: #666;
border: 1px solid #ccc;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
-ms-border-radius: 15px;
-o-border-radius: 15px;
border-radius: 15px;
-webkit-box-shadow: inset 0 1px 3px 0 rgba(0,0,0,0.17);
-moz-box-shadow: inset 0 1px 3px 0 rgba(0,0,0,0.17);
box-shadow: inset 0 1px 3px 0 rgba(0,0,0,0.17);
outline: none;
background: #fcfcfc url(/img/search.png) no-repeat 7px 7px;
}

这里面设置搜索框的位置

1
2
3
position: absolute;
left: 32px;
top: 70px;

并且必须修改main.style

1
2
3
4
.left-col {
z-index: -1;
}
//在overlay里

参考文章:http://www.xianingtan.xyz/2015/08/28/Hexo-Yilia-%E4%B8%BB%E9%A2%98%E9%85%8D%E7%BD%AE%E5%9F%BA%E4%BA%8Eswiftype%E7%9A%84%E7%AB%99%E5%86%85%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/

Shell脚本的初步探析

slide]

shell编程

演讲者:守望

[slide data-transition=”vertical3d”]

什么是shell? {:&.flexbox.vleft}

[slide]

shell {:&.flexbox.vleft}

[ʃel]俗称壳(命令解析器)

[slide]
是一个命令行解释器,一种为用户提供了一个向内核发送请求以便运行程序的界面系统级程序,用户可以用shell来启动、挂起、甚至编写一些程序.例:sh是第一种Unix Shell,Windows Explorer是一个典型的图形界面Shell。 {:&.flexbox.vleft}
[slide data-transition=”vertical3d”]
shell的分类 {:&.flexbox.vleft}

  • Bourne shell:1979年起Unix开始使用(sh,ksh,Bash);
  • c shell:在BSD版的Unix语言与c语言类似所以因此得名(csh, tcsh);
  • Bourne Again shell (bash)
  • Korn shell (ksh)
  • POSIX shell (sh)
    [slide]
    #shell编程?一门语言?
    [slide data-transition=”vertical3d”]

    shell脚本(shell script),是一种为shell编写的脚本程序,易编写易调试灵活性,shell脚本是解释执行的脚本语言,在shell中可直接调起Linux的命令。

    [slide]

    与高级编程语言

[slide data-transition=”vertical3d”]
理论上讲,只要一门语言提供了解释器(而不仅是编译器),这门语言就可以胜任脚本编程,常见的解释型语言都是可以用作脚本编程的,如:Perl、 Tcl、Python、PHP、Ruby。Perl是最老牌的脚本编程语言了,Python这些年也成了一些linux发行版的预置解释器。 {:&.flexbox.vleft}
[slide]

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/php
<?php
for ($i=0; $i < 10; $i++)
echo $i . "\n";
?>


/usr/bin/php test.php
或者:
chmod +x test.php
./test.php

[slide data-transition=”vertical3d”]

#环境
[slide]
shell编程跟java、php编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。 {:&.flexbox.vleft}
[slide style=”background-image:url(‘/img/bg1.png’)”]

一个简单的shell脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
cd ~
mkdir shell_tut
cd shell_tut

for ((i=0; i<2; i++)); do
touch test_$i.txt
done
#第1行:指定脚本解释器,这里是用/bin/sh做解释器的
#第2行:切换到当前用户的home目录
#第3行:创建一个目录shell_tu
#第4行:循环创建文件
#运行 chmod +x ./test1.sh

[slide data-transition=”vertical3d”]

##变量

1
your_name="qinjx"

  1. 在命名变量名时,变量名称只能是英文字母和数字,而且首字母不能是数字
  2. 等号=两边不能有空格
  3. 如果变量值有空格,可用双引号” “或单引号’ ‘来包围变量值,但两者是有区别:双引号” “内的一些特殊字符,可以保持原有的特性
    ##使用变量
1
2
3
your_name="qinjx"
echo $your_name
echo ${your_name}

1
2
3
for skill in Ada Coffe Action Java do
echo "I am good at ${skill}Script"
done

[slide data-transition=”vertical3d”]

#字符串
[slide]

1
2
3
4
5
6
7
8
9
str='this is a string'
#单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
#单引号字串中不能出现单引号(对单引号使用转义符后也不行)

your_name='qinjx'
str="Hello, I know your are \"$your_name\"! \n"

#双引号里可以有变量
#双引号里可以出现转义字符

[slide]

#条件判断与流程控制

1
2
3
4
5
6
7
if condition
then
command1
command2
...
commandN
fi

1
for var in item1 item2 ... itemN; do command1; command2… done;

1
2
3
4
while condition
do
command
done

另外还有case语句;until语句
[slide]

shell函数

[slide]

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
funWithReturn(){
echo "The function is to get the sum of two numbers..."
echo -n "Input first number: "
read aNum
echo -n "Input another number: "
read anotherNum
echo "The two numbers are $aNum and $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "The sum of two numbers is $? !"

[slide]

重定向 Redirection {:&.flexbox.vleft}

stdin(<或<<)、stdout(>或>>)、stderr(2>或2>>)

##将一条命令执行结果(标准输出,或者错误输出,本来都要打印到屏幕上面的) 重定向其它输出设备(文件,打开文件操作符,或打印机等等)
[slide]
alt text
[slide data-transition=”vertical3d”]

输出重定向

1
2
3
4
5
command-line1 [1-n] > file或文件操作符或设备
ls 1>suc.txt
who > users
cat users
#1,2分别是标准输出,错误输出。

>与>>(不覆盖追加在内容后面)

例如:echo ‘追加在后面’ >> users
[slide]

输入重定向

1
command-line [n] < file或文件描述符&设备
1
2
$ wc -l users
2 users
1
command1 < infile > outfile

[slide data-transition=”vertical3d”]

Here Document

Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式Shell脚本或程序

1
2
3
4
5
6
7
8
9
command << delimiter
document
delimite

$ wc -l << EOF
这是第一行
这是第二行
这是第三行
EOF


1
2
3
4
5
6
#!/bin/bash
cat << EOF
这是第一行
这是第二行
这是第三行
EOF

[slide data-transition=”vertical3d”]

管道 {:&.flexbox.vleft}

管道命令操作符是:”|”,它仅能处理经由前面一个指令传出的正确输出信息,也就是 standard output 的信息,对于 stdandard error 信息没有直接处理能力。然后,传递给下一个命令,作为标准的输入.

alt text

1
cat suc.txt|grep -n 'D'

[slide]

grep、awk、sed

三剑客

对创建和修改文本文件的人来说是一个强大工具

[slide]

grep

1
2
3
4
5
6
7
8
grep [-acinv] [--color=auto] '搜寻字符串' filename
选项与参数:
-a :将 binary 文件以 text 文件的方式搜寻数据
-c :计算找到 '搜寻字符串' 的次数
-i :忽略大小写的不同,所以大小写视为相同
-n :顺便输出行号
-v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!
--color=auto :可以将找到的关键词部分加上颜色的显示喔!

1
grep -n 't[ae]st' shell_ppt/regular_express.txt

[slide]

awk {:&.flexbox.vleft}

读入有’\n’换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是”空白键” 或 “[tab]键”。
alt text

1
cat shell_ppt/regular_awk.txt |awk -F ':' '{println $0}'

[slide data-transition=”vertical3d”]

sed

##sed可以说是一个编辑器逐行处理输入,然后把结果发送到屏幕

1
2
3
4
sed 's/test/mytest/g' shell_ppt/regular_awk.txt
#如果没有g标记就只能替换每行第一个
#命令 a/ 在当前行后面加入一行文本
#命令 c/ 新文本改变本行文本等等


1
sed '2d' shell_ppt/regular_awk.txt

[slide]

shell脚本在实际中的用处

[slide]

That’s All Thankyou!