extends ViewGroup extends View`
-
-
-
-
-
-
-
-
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\212\240\345\274\272/\350\247\206\351\242\221\346\222\255\346\224\276\347\233\270\345\205\263\345\206\205\345\256\271\346\200\273\347\273\223.md" "b/Android\345\212\240\345\274\272/\350\247\206\351\242\221\346\222\255\346\224\276\347\233\270\345\205\263\345\206\205\345\256\271\346\200\273\347\273\223.md"
deleted file mode 100644
index feee5ad3..00000000
--- "a/Android\345\212\240\345\274\272/\350\247\206\351\242\221\346\222\255\346\224\276\347\233\270\345\205\263\345\206\205\345\256\271\346\200\273\347\273\223.md"
+++ /dev/null
@@ -1,72 +0,0 @@
-视频播放相关内容总结
-===
-
-##Surface简介
-- `Surface`就是“表面”的意思。在`SDK`的文档中,对`Surface`的描述是这样的:“`Handle onto a raw buffer that is being managed by the screen compositor`”,
- 翻译成中文就是“由屏幕显示内容合成器`(screen compositor)`所管理的原生缓冲器的句柄”, 这句话包括下面两个意思:
- - 通过Surface(因为Surface是句柄)就可以获得原生缓冲器以及其中的内容。就像在C语言中,可以通过一个文件的句柄,就可以获得文件的内容一样;
- - 原生缓冲器(rawbuffer)是用于保存当前窗口的像素数据的。
-- 简单的说`Surface`对应了一块屏幕缓冲区,每个`Window`对应一个`Surface`,任何`View`都是画在`Surface`上的,传统的`view`共享一块屏幕缓冲区,所有的绘制必须在`UI`线程中进行
-- 我们不能直接操作Surface实例,要通过SurfaceHolder,在SurfaceView中可以通过getHolder()方法获取到SurfaceHolder实例。
-- `Surface`是一个用来画图形的地方,但是我们知道画图都是在一个`Canvas`对象上面进行的,*`Surface`中的`Canvas`成员,是专门用于提供画图的地方,就像黑板一样,其中的原始缓冲区是用来保存数据的地方,
- `Surface`本身的作用类似一个句柄,得到了这个句柄就可以得到其中的`Canvas`、原始缓冲区以及其他方面的内容,所以简单的说`Surface`是用来管理数据的(句柄)*。
-
-
-##SurfaceView简介
-- 简单的说`SurfaceView`就是一个有`Surface`的`View`里面内嵌了一个专门用于绘制的`Surface`,`SurfaceView`控制这个`Surface`的格式和尺寸以及绘制位置.`SurfaceView`是一个`View`也许不够严谨,
- 然而从定义中 `public class SurfaceView extends View`显示`SurfaceView`确实是派生自`View`,但是`SurfaceView`却有着自己的`Surface`,源码:
- ```java
- if (mWindow == null) {
- mWindow = new MyWindow(this);
- mLayout.type = mWindowType;
- mLayout.gravity = Gravity.LEFT|Gravity.TOP;
- mSession.addWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
- mVisible ? VISIBLE : GONE, mContentInsets);
- }
- ```
- 很明显,每个`SurfaceView`创建的时候都会创建一个`MyWindow`,`new MyWindow(this)`中的`this`正是`SurfaceView`自身,因此将`SurfaceView`和`window`绑定在一起,而前面提到过每个`window`对应一个`Surface`,
- 所以`SurfaceView`也就内嵌了一个自己的`Surface`,可以认为`SurfaceView`是来控制`Surface`的位置和尺寸。传统`View`及其派生类的更新只能在`UI`线程,然而`UI`线程还同时处理其他交互逻辑,
- 这就无法保证`view`更新的速度和帧率了,而`SurfaceView`可以用独立的线程来进行绘制,因此可以提供更高的帧率,例如游戏,摄像头取景等场景就比较适合用`SurfaceView`来实现。
-
-- `Surface`是纵深排序`(Z-ordered)`的,这表明它总在自己所在窗口的后面。
-- `Surfaceview`提供了一个可见区域,只有在这个可见区域内的`Surface`部分内容才可见,可见区域外的部分不可见,所以可以认为**`SurfaceView`就是展示`Surface`中数据的地方**,`Surface`就是管理数据的地方,
- `SurfaceView`就是展示数据的地方,只有通过`SurfaceView`才能展现`Surface`中的数据。
- 
-- `Surface`的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者`Surface`的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物`(overlays)`(例如,文本和按钮等控件)。
- 注意,如果`Surface`上面有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。
- 这样能节省资源。如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。
- **`SurfaceView`的核心在于提供了两个线程:`UI`线程和渲染线程**,两个线程通过“双缓冲”机制来达到高效的界面适时更新。
-
-##SurfaceHolder简介
-
-显示一个`Surface`的抽象接口,使你可以控制`Surface`的大小和格式以及在`Surface`上编辑像素,和监视`Surace`的改变。这个接口通常通过`SurfaceView`类实现。
-简单的说就是我们无法直接操作`Surface`只能通过`SurfaceHolder`这个接口来获取和操作`Surface`。
-SurfaceHolder`中提供了一些`lockCanvas()`:获取一个Canvas对象,并锁定之。所得到的Canvas对象,其实就是Surface中一个成员。加锁的目的其实就是为了在绘制的过程中,
-Surface中的数据不会被改变。lockCanvas是为了防止同一时刻多个线程对同一canvas写入。
-
-
-*从设计模式的角度来看,`Surface、SurfaceView、SurfaceHolder`实质上就是`MVC(Model-View-Controller)`,`Model`就是模型或者说是数据模型,更简单的可以理解成数据,在这里也就是`Surface`,
-`View`就是视图,代表用户交互界面,这里就是`SurfaceView`,`SurfaceHolder`就是`Controller.`*
-
-
-##MediaController
-
-- `MediaController`继承`FrameLayout`,通过`MediaPlayerControl`接口与`VideoView`进行结合控制,内部是通过`PopupWindow`将整个控制栏界面显示到界面上,
- 而该`PopupWindow`所显示在的位置就是通过`setAnchorView()`设置进来的`Anchor`一般可以使当前的`VideoView`或者是整个`Activity`的根布局。这里要分为小屏和全屏两种情况来进行设置。
- 如果当前的`MediaController`只是播放前下面的控制栏部分(进度条、快进、快退、暂停等)这样我们可以通过对VideoView设置点击事件,控制它的显示和隐藏。
- 如果`MediaController`为整个屏幕包括了控制栏部分、上端的信息显示部分、以及左右栏的功能部分、这时候就可以通过对`MediaController`本身设置点击事件来控制显示和隐藏。
-
-`Controller`可以用`PopupWindow`来实现,具体有两种方式:
-
- - 整个控制栏(上面的信息部分、下面的控制部分以及左右边)都在`Controller`中,`setAnchorView()`的时候就会让`Controller`中的`PopupWindow`显示出来(一直显示,但是这个`PopupWindow`是透明的),
- 真正的显示与隐藏是控制在`PopupWindow`中的`View`部分的显示与隐藏来实现。开始的时候我是想用这种方式,当时我想的是播放就播放、控制就控制,分离开来多好,但是没想到,
- 一旦有`PopupWindow`显示出来后,Activity是接收不到任何`Touch`事件的,所有的重试界面等都要放到`Controller`中实现(手势处理等)。但是也有好处,就是不管显示还是隐藏都可以去处理手势.
-
- - `PopupWindow`不是全屏的,只包含下面真正的控制部分(快进、快退、暂停等,不包含上面的信息部分和左右边),而且也不是开始就显示,显示隐藏是通过控制`PopupWindow`的显示与隐藏来进行的。
- 而对于信息部分、以及左右边都是在`Activity`的布局当中,我们通过接口回调得到`PopupWindow`的显示与隐藏来控制这些布局的显示与隐藏即可。
- 这样的话我们就需要将手势等全部放到`Activity`中去处理,但是也有一个问题,就是如果`Controller`正在显示的话`Activity`是接收不到`Touch`事件的,就无法处理手势,只能是让`Controller`消失后才能处理手势。
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/AndroidStudio\344\275\277\347\224\250\346\225\231\347\250\213(\347\254\254\344\270\200\345\274\271).md" "b/Android\345\237\272\347\241\200/AndroidStudio\344\275\277\347\224\250\346\225\231\347\250\213(\347\254\254\344\270\200\345\274\271).md"
deleted file mode 100644
index 302c87b9..00000000
--- "a/Android\345\237\272\347\241\200/AndroidStudio\344\275\277\347\224\250\346\225\231\347\250\213(\347\254\254\344\270\200\345\274\271).md"
+++ /dev/null
@@ -1,83 +0,0 @@
-AndroidStudio使用教程(第一弹)
-===
-
-`Android Studio`是一套面世不久的`IDE`(即集成开发环境),免费向谷歌及`Android`的开发人员发放。`Android Studio`以`IntelliJ IDEA`为基础,旨在取代`Eclipse`和`ADT`(`Android`开发者工具)为开发者提供更好的开发工具。
-运行相应速度、智能提示、布局文件适时多屏预览等都比`Eclipse`要强,但也不能说全部都是有点现在`Studio`中无法在一个窗口管理多个`Project`,每个`Project`都要打开一个窗口,或者是`close`当前的后再打开别的。
-
-当但是毕竟是预览版,所以只是暂时试用了下,并没有过多接触,开发中还是使用`Eclipse`。
-经过一年多的沉淀,如果已到0.8.4版本,最近准备在工作用正式开始使用,所以看了下官网的教程。准备开始了。
-
-- 安装
- 这个我就不多说了,大家都知道,官网下载安装即可。安装完成后界面和`Eclipse`有些类似,然后就新建一个`Project`,完成之后会发现一直在提示下载,
- 这是在下载`Gradle`,大约二三十M的大小,由于伟大的防火墙,所以可能需要很长时间,这里就不教大家了,对程序猿来说不是难题,大家都会科学上网。
-
-- 区别
- - 此`Project`非彼`Project`, `Android Studio`的目录结构(`Project`)代表一个`Workspace`,一个`Workspace`里面可以有多个`Module`,这里`Module`可以理解成`Eclipse`中的一个`Project`.
- `Project`代表一个完整的`Android app`,而`modules`则是`app`的一个组件,并且这个组件可以单独`build,test,debug`。`modules`可以分为下面几种:
- - Java library modules
- - Android library modules: 包含android相关代码和资源,最后生成AAR(Android ARchive)包
- - Android application modules
-
- - 结构发生了变化,在`src`目录下有一个`main`的分组同时包含了`java`和`res`.
- 
- 如图:`MyApplication`就是`Project`,而`app`就是`Module`.
-
-- 设置
- 进入后你会发现字体或样式等不符合你的习惯。
- `Windows`下点击左上角`File` -> `Settings`进入设置页面(`Mac`下为 `Android Studio` -> `Preferences`),在搜索框搜`Font`找到`Colors&Font`下的`Font`选项,我们会发现无法修改右侧字体大小。这里修改必须
- 要通过新建`Theme`进行修改的,点击`Save as`输入一个名字后,就可以修改字体了。
- 
-
- 这里可能有些人会发现我的主题是黑色的,和`IO`大会演示的一样,但是安装后默认是白色的,有些刺眼。这里可以通过设置页面中修改`Theme`来改变,
- 默认是`Intellij`, 改为`Darcula`就是黑色的了.
- 
- 很酷有木有.
-
-- 运行
- 设置好字体后,当然要走你了。
- 运行和`Eclipse`中比较像,点击绿色的箭头。 可以通过箭头左边的下拉菜单选择不同的`Module`,快捷键是`Shift+F10`
- 
-
- `AndroidStudio`默认安装会启动模拟器,如果想让安装到真机上可以配置一下。在下拉菜单中选择`Edit Configurations`选择提示或者是`USB`设备。
- 
- 
-
-- 常用快捷键介绍
- `AndroidStudio`中可以将快捷键设置成`Eclipse`中的快捷键。具体方法为在设置页面搜索`keymap`然后选择为`Eclipse`就可以了.
- 
-
- 强迫症的人伤不起,非想用默认的快捷键。
- 这里我整理下下个人常用的几个快捷键。 每个人的习惯不同,大家各取所需
- `Ctrl+S` 开个玩笑,这个键算是彻底废掉了, 因为`AndroidStudio`与`Eclipse`不同,他是自动保存的,所以我们再也不需要`Ctrl+S`了.
- `Ctrl+空格` 代码提示 (同`Eclipse`中`Alt+/`)
- `Ctrl+Shjft+N` 查找文件 (同`Eclipse`中`Ctrl+Shift+R`)
- `Ctrl+F12` 显示当前文件的结构 (同`Eclipse`中`Ctrl+0`)
- `Ctrl+Alt+L` 格式化 (同`Eclipse`中`Ctrl+Shift+F`)
- `Ctrl+Alt+O` 优化导入的包 (同`Eclipse`中`Ctrl+Shift+O`)
- `Ctrl+Q` 查看文档 (同`Eclipse`中`F2`)
- `Alt+F7` 搜寻 (同`Eclipse`中`File Search`)
- `Alt+Insert` 新建文件或生成代码(`GetSet`)(同`Eclipse`中`Alt+Shift+S后的操作`)
- `Alt+Enter` 快速修复 (同`Eclipse`中`F1`)
- `Ctrl+P` 显示方法参数
- `Shift+F10` 运行项目
- `Ctrl+Shift+Backspace` 跳转到上次修改的地方
- `Ctrl+E` 显示最近编辑列表
- `Ctrl+[或]` 跳转到大括号开头或结尾
- `Ctrl+Alt+T` 把代码包在一起(加try catch等)
- `Alt+↑或↓` 在方法间移动
- `Ctrl+Shift+F7` 高亮本文件中选中的代码
- `Alt+←或→` 切换已打开的文件视图
- `Shift+F6` 重命名
- `Ctrl+B` 快速打开该类或方法
- `F2` 快速定位到文件错误或警告位置
- `Ctrl+X` 剪切当前行
- `Ctrl+Y` 删除当前行
- `Ctrl+D` 复制当前行
- `F4` 进入源码
- `Alt+1` 开关`Project`视图
- `Ctrl+_F4` 关闭当前窗口
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/AndroidStudio\344\275\277\347\224\250\346\225\231\347\250\213(\347\254\254\344\270\203\345\274\271).md" "b/Android\345\237\272\347\241\200/AndroidStudio\344\275\277\347\224\250\346\225\231\347\250\213(\347\254\254\344\270\203\345\274\271).md"
deleted file mode 100644
index 2559e2df..00000000
--- "a/Android\345\237\272\347\241\200/AndroidStudio\344\275\277\347\224\250\346\225\231\347\250\213(\347\254\254\344\270\203\345\274\271).md"
+++ /dev/null
@@ -1,11 +0,0 @@
-AndroidStudio使用教程(第七弹)
-===
-
-本文讲解一下如何利用`Gradle`打多渠道包。
-
-
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/AndroidStudio\344\275\277\347\224\250\346\225\231\347\250\213(\347\254\254\345\205\255\345\274\271).md" "b/Android\345\237\272\347\241\200/AndroidStudio\344\275\277\347\224\250\346\225\231\347\250\213(\347\254\254\345\205\255\345\274\271).md"
deleted file mode 100644
index adfa1e72..00000000
--- "a/Android\345\237\272\347\241\200/AndroidStudio\344\275\277\347\224\250\346\225\231\347\250\213(\347\254\254\345\205\255\345\274\271).md"
+++ /dev/null
@@ -1,43 +0,0 @@
-AndroidStudio使用教程(第六弹)
-===
-
-Debug
----
-
-`Andorid Studio`中进行`debug`:
-- 在`Android Studio`中打开应用程序。
-- 点击状态栏中的`Debug`图标。
-- 在接下来的选择设备窗口选择相应的设备或创建虚拟机, 点击`OK`即可。
-`Android Studio`在`debug`时会打开`Debug`工具栏, 可以点击`Debug`图标打开`Debug`窗口。
-
-###设置断点
-与`Eclipse`十分相似, 在代码左侧位置点击一下即可, 圆点的颜色变了。
-
-###Attach the debugger to a running process
-在`debug`时不用每次都去重启应用程序。 我们可以对正在运行的程序进行`debug`:
-- 点击`Attach debugger to Android proccess`图标。
-- 设备选择窗口选择想要`debug`的设备。
-- 点击`Debug`图标打开`Debug`工具栏。
-- 在`Debug`工具栏中有`Stop Over`, `Stop Into`等图标和快捷键,这些就不仔细说明了, 和`Eclipse`都差不多。
-
-### View the system log
-在`Android DDMS`中和`Debug`工具栏中都可以查看系统`log`日志,
-- 在窗口底部栏点击`Android` 图标打开`Android DDMS`工具栏。
-- 如果此时`Logcat`窗口中的日志是空得,点击`Restart`图标。
-- 如果想要只显示当前某个进程的信息点击`Only Show Logcat from Selected Process`. 如果当时设备窗口不可见,点击右上角的`Restore Devices View`图标,该图标只有设备窗口不可见时才会显示。
-
-删除`Project`及`Module`
----
-
-很多人都在问`AndroidStudio`中如何删除`Project`,如何删除`Module`?怎么和`Eclipse`不同啊,找不到`delete`或`remove`选项。
- - 删除`Project`
- 点击左侧`File`-->`Close project`,关闭当前工程, 然后直接找到工程所在本地文件进行删除(慎重啊), 删除完之后点击最近列表中的该项目就会提示不存在,我们把他从最近项目中移除即可.你会发现,点击`remove`之后没效果,以后估计会解决。
- - 删除`Module`
- 在该`Module`邮件选择`Open Module Settings`。 
- 进入设置页后选中要删除的`Module`点击左上角的删除图标`-`. 后点击确定。
- 在该`Module`上邮件这次会发现已经有`Delete`按钮了。删除就可以了。 
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/Android\345\212\250\347\224\273.md" "b/Android\345\237\272\347\241\200/Android\345\212\250\347\224\273.md"
deleted file mode 100644
index 398f610e..00000000
--- "a/Android\345\237\272\347\241\200/Android\345\212\250\347\224\273.md"
+++ /dev/null
@@ -1,108 +0,0 @@
-Android动画
-===
-
-1. AlphaAnimation
-
- ```java
- RelativeLayout rl_splash = (RelativeLayout) findViewById(R.id.rl_splash);
- //播放动画效果
- AlphaAnimation animation = new AlphaAnimation(1.0f, 0.0f);
- //设置Alpha动画的持续时间
- animation.setDuration(2000);
- //播放Alpha动画
- rl_splash.setAnimation(animation);
- ```
-
-2. RotateAnimation
-
- ```java
- //相对于自身的哪个位置旋转,这里是相对于自身的右下角
- RotateAnimation ra = new RotateAnimation(0, 360, //从哪旋转,旋转多少度
- Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
- 1.0f);
- ra.setDuration(800);
- ra.setRepeatCount(Animation.INFINITE);
- ra.setRepeatMode(Animation.RESTART);
- iv_scan.startAnimation(ra);
- ```
-3. ScaleAnimation(缩放动画)
-
- ```java
- ScaleAnimation(float fromX, float toX, float fromY, float toY)
- Constructor to use when building a ScaleAnimation from code
- ```
-
-4. TranslateAnimation(位移动画)
-
- ```java
- TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue)
- Constructor to use when building a TranslateAnimation from code
- ```
-
-5. AnimationSet (多组动画)
-
- ```java
- ScaleAnimation sa = new ScaleAnimation(0.2f, 1.0f, 0.4f,1.0f);//缩放的动画效果,1.0f就代表窗体的总宽或者高
- sa.setDuration(400);
- TranslateAnimation ta = new TranslateAnimation(//位移动的动画效果
- Animation.RELATIVE_TO_SELF, 0,//指定这个位置是相对于谁
- Animation.RELATIVE_TO_SELF, 0.1f,
- Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, 0);
- ta.setDuration(300);
- AnimationSet set = new AnimationSet(false);//如果想播放多种动画的组合,这里就要用到了AnimationSet
- set.addAnimation(sa);
- set.addAnimation(ta);
- contentView.startAnimation(set); // 播放一组动画.
- ```
-
-6. Frame动画
-
- - 在`drawable`目录下新建一个`xml`文件,内容如下:
-
- ```xml
-
- //onshot是指定是否循环播放
- //播放这个图片持续的时间
-
-
- ```
- - 播放Frame动画
-
- ```java
- AnimationDrawable rocketAnimation;
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- ImageView rocketImage = (ImageView) findViewById(R.id.iv);
- rocketImage.setBackgroundResource(R.drawable.animlist); //将上边建的Frame动画的xml文件通过背景资源设置给图片
- rocketAnimation = (AnimationDrawable) rocketImage.getBackground(); //获取到图片的背景资源
- }
- public void start(View view) {
- if (!rocketAnimation.isRunning()) {
- rocketAnimation.start(); //播放
- }
- }
- ```
-
-7. 保持动画播放完成后的状态`animation.setFillAfter(true);`
-
- ```java
- Interpolator //定义了动画的变化速度,可以实现匀速、正加速、负加速、无规则变加速度
- AccelerateDecelerateInterpolator//先加速后减速。
- AccelerateInterpolator//逐渐加速。
- LinearInterpolator//平稳不变的
- DecelerateInterpolator//逐渐减速
- CycleInterpolator//曲线运动特效,要传递float型的参数。
- animation.setInterpolator(new LinearInterpolator());//指定动画的运行效果
- ```
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
diff --git "a/Android\345\237\272\347\241\200/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213ContentProvider.md" "b/Android\345\237\272\347\241\200/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213ContentProvider.md"
deleted file mode 100644
index ca8719d6..00000000
--- "a/Android\345\237\272\347\241\200/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213ContentProvider.md"
+++ /dev/null
@@ -1,309 +0,0 @@
-Android四大组件之ContentProvider
-===
-
-ContentProvider
----
-
-安卓应用程序默认是无法获取到其他程序的数据,这是安卓安全学的基石(沙盒原理)。但是经常我们需要给其他应用分享数据,内容提供者就是一个这种可以分享数据给其他应用的接口。
-可以简单的理解为,内容提供者就是一个可以在不同应用程序间共享数据的组件,相当于一个中间人,一个程序把数据暴露给这个中间人,另一个则通过这个中间人获取相应的数据.
-
-下面的这张图片能更直观的显示:
-
-
-- `ContentProvider`中的`getContext`和`AndroidTestCast`中的`getContext`方法一样,都是一个模拟的上下文,必须在该类初始化之后才会调用`setContext`方法将`context`设置成自己的成员变量中记录,
- 所以对于获取`getContext`的时候只能放在方法内,不能放到成员位置,因为在成员上时是null,而在方法内调用时该类就会已经初始化完了
-
-- `ContentProvider`中的`query()`后不能关闭数据库,因为其他的应用在调用该`query`方法时需要继续使用该返回值`Cursor`,所以不能关闭数据库,因为数据库关闭之后`Cursor`就不能用了,
- `Cursor`中保存的数据其实是数据库的一个引用,如果数据库关了`Cursor`就不能找到里面的数据了,`Cursor.close()`只是释放·Cursor·用到的资源。说到这里就多数一句
- `According to Dianne Hackborn (Android framework engineer) there is no need to close the database in a content provider.`以为内容提供者是因为进程启动时便加载,之后就一直存在,当进程销毁
- 释放资源时会去关闭数据库。
-
-- 如果数据是`SQLiteDatabase`,表中必须有一个`_id`的列,用来表示每条记录的唯一性。
-
-1. 继承`ContentProvider`,并实现相应的方法。
-```java
-public class NoteProvider extends ContentProvider {
- private static final int NOTES = 1;
- private static final int NOTE_ID = 2;
-
- public static final String AUTHORITY = "com.charon.demo.provider.noteprovider";
- public static final String TABLE_NAME = "note";
- // 定义一个名为`CONTENT_URI`必须为其指定一个唯一的字符串值,最好的方案是以类的全名称
- public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
-
- // 声明一个路径的检查者,参数为Uri不匹配时的返回值
- // 虽然是中间人,但也不能谁要数据我们都给,所以要检查下,只有符合我们要求的人,我们才会给他数据。
- private static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
-
- private NoteSQLiteOpenHelper mSQLiteOpenHelper;
- private SQLiteDatabase mSQLiteDatabase;
-
- static {
- // 建立匹配规则,例如发现路径为ccom.charon.demo.provider.noteprovider/note/1表示要操作note表中id为1的记录
- sUriMatcher.addURI(AUTHORITY, TABLE_NAME, NOTES);
- sUriMatcher.addURI(AUTHORITY, TABLE_NAME + "/#", NOTE_ID);
- }
-
- /**
- * Implement this to initialize your content provider on startup.
- * This method is called for all registered content providers on the
- * application main thread at application launch time. It must not perform
- * lengthy operations, or application startup will be delayed.
- *
- * You should defer nontrivial initialization (such as opening,
- * upgrading, and scanning databases) until the content provider is used
- * (via {@link #query}, {@link #insert}, etc). Deferred initialization
- * keeps application startup fast, avoids unnecessary work if the provider
- * turns out not to be needed, and stops database errors (such as a full
- * disk) from halting application launch.
- *
- * If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper}
- * is a helpful utility class that makes it easy to manage databases,
- * and will automatically defer opening until first use. If you do use
- * SQLiteOpenHelper, make sure to avoid calling
- * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or
- * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase}
- * from this method. (Instead, override
- * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the
- * database when it is first opened.)
- *
- * @return true if the provider was successfully loaded, false otherwise
- */
- @Override
- public boolean onCreate() {
- mSQLiteOpenHelper = new NoteSQLiteOpenHelper(getContext());
- return true;
- }
-
- /**
- * 内容提供者暴露的查询的方法.
- */
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- mSQLiteDatabase = mSQLiteOpenHelper.getReadableDatabase();
- Cursor cursor;
- // 1.重要的事情 ,检查 uri的路径.
- switch (sUriMatcher.match(uri)) {
- case NOTES:
- break;
- case NOTE_ID:
- String id = uri.getLastPathSegment();
- if (TextUtils.isEmpty(selection)) {
- selection = selection + "_id = " + id;
- } else {
- selection = selection + " and " + "_id = " + id;
- }
- break;
- default:
- throw new IllegalArgumentException("UnKnown Uri" + uri);
- break;
- }
- cursor = mSQLiteDatabase.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
- if (cursor != null) {
- cursor.setNotificationUri(getContext().getContentResolver(), uri);
- }
- return cursor;
- }
-
- /**
- * Implement this to handle requests for the MIME type of the data at the
- * given URI. The returned MIME type should start with
- * vnd.android.cursor.item for a single record,
- * or vnd.android.cursor.dir/ for multiple items.
- * This method can be called from multiple threads, as described in
- * Processes
- * and Threads.
- *
- * Note that there are no permissions needed for an application to
- * access this information; if your content provider requires read and/or
- * write permissions, or is not exported, all applications can still call
- * this method regardless of their access permissions. This allows them
- * to retrieve the MIME type for a URI when dispatching intents.
- *
- * @param uri the URI to query.
- * @return a MIME type string, or {@code null} if there is no type.
- */
- @Override
- public String getType(Uri uri) {
- // 注释说的很清楚了,下面是常用的格式
- // 单个记录的IMEI类型 vnd.android.cursor.item/vnd..
- // 多个记录的IMEI类型 vnd.android.cursor.dir/vnd..
- switch (sUriMatcher.match(uri)) {
- case NOTE_ID:
- // 如果uri为 content://com.charon.demo.noteprovider/note/1
- return "vnd.android.cursor.item/vnd.charon.note";
- case NOTES:
- return "vnd.android.cursor.dir/vnd.charon.note";
- default:
- return null;
- }
-
- // 这个MIME类型的作用是要匹配AndroidManifest.xml文件标签下标签的子标签的属性android:mimeType。
- // 如果不一致,则会导致对应的Activity无法启动。
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- mSQLiteDatabase = mSQLiteOpenHelper.getWritableDatabase();
- switch (sUriMatcher.match(uri)) {
- case NOTES:
- break;
-
- case NOTE_ID:
- break;
-
- default:
- throw new IllegalArgumentException("UnKnown Uri" + uri);
- break;
- }
-
- long rowId = mSQLiteDatabase.insert(TABLE_NAME, null, values);
- if (rowId > 0) {
- Uri noteUri = ContentUris.withAppendedId(CONTENT_URI, rowId);
- getContext().getContentResolver().notifyChange(noteUri, null);
- return noteUri;
- }
-
- return null;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- mSQLiteDatabase = mSQLiteOpenHelper.getWritableDatabase();
- switch (sUriMatcher.match(uri)) {
- case NOTES:
- break;
-
- case NOTE_ID:
- String id = uri.getLastPathSegment();
- if (TextUtils.isEmpty(selection)) {
- selection = selection + "_id = " + id;
- } else {
- selection = selection + " and " + "_id = " + id;
- }
- break;
-
- default:
- throw new IllegalArgumentException("UnKnown Uri" + uri);
- break;
- }
- int count = mSQLiteDatabase.delete(TABLE_NAME, selection, selectionArgs);
- getContext().getContentResolver().notifyChange(uri, null);
- return count;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- switch (sUriMatcher.match(uri)) {
- case NOTES:
-
- break;
-
- case NOTE_ID:
-
- break;
-
- default:
- throw new IllegalArgumentException("UnKnown Uri" + uri);
- break;
- }
-
- mSQLiteDatabase = mSQLiteOpenHelper.getWritableDatabase();
- int update = mSQLiteDatabase.update(TABLE_NAME, values, selection, selectionArgs);
- return update;
- }
-```
-
-2. 在清单文件中进行注册,并且指定其authorities
-```xml
-
-```
-
-3. 使用内容提供者获取数据,使用`ContentResolver`去操作`ContentProvider`, `ContentResolver`用于管理`ContentProvider`实例,并且可实现找到指定的`ContentProvider`并获取里面的数据
- ```java
- public void query(View view){
- //得到内容提供者的解析器 中间人
- ContentResolver resolver = getContentResolver();
- Cursor cursor = resolver.query(NoteProvider.CONTENT_URI, null, null, null, null);
- while(cursor.moveToNext()){
- String name = cursor.getString(cursor.getColumnIndex("name"));
- int id = cursor.getInt(cursor.getColumnIndex("id"));
- float money = cursor.getFloat(cursor.getColumnIndex("money"));
- System.out.println("id="+id+",name="+name+",money="+money);
- }
- cursor.close();
- }
- public void insert(View view){
- ContentResolver resolver = getContentResolver();
- ContentValues values = new ContentValues();
- values.put("name", "买洗头膏");
- values.put("money", 22.58f);
- resolver.insert(NoteProvider.CONTENT_URI, values);
- }
- public void update(View view){
- ContentResolver resolver = getContentResolver();
- ContentValues values = new ContentValues();
- values.put("name", "买洗头膏");
- values.put("money", 42.58f);
- resolver.update(NoteProvider.CONTENT_URI, values, "name=?", new String[]{"买洗头膏"});
- }
- public void delete(View view){
- ContentResolver resolver = getContentResolver();
- resolver.delete(NoteProvider.CONTENT_URI, "name=?", new String[]{"买洗头膏"});
- }
- ```
-
-内容观察者
----
-
-内容观察者的原理:
-`How a content provider actually stores its data under the covers is up to its designer. But all content providers implement a common interface for querying the provider and
-returning results — as well as for adding, altering, and deleting data.
-It's an interface that clients use indirectly, most generally through ContentResolver objects.
-You get a ContentResolver by calling getContentResolver() from within the implementation of an Activity or other application component:
-You can then use the ContentResolver's methods to interact with whatever content providers you're interested in.`
-
-1. 一方使用内容观察者去观察变化
- ```java
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- ContentResolver resolver = getContentResolver();
- resolver.registerContentObserver(NoteProvider.CONTENT_URI, true, new NoteObserver(new Handler()));
-
- }
-
- private class NoteObserver extends ContentObserver {
-
- public NoteObserver(Handler handler) {
- super(handler);
-
- }
- //当观察到数据发生变化的时候 会执行onchange方法.
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- Log.i(TAG,"发现有新的短信产生了...");
- //1.利用内容提供者 中间人 获取用户的短信数据.
- ContentResolver resolver = getContentResolver();
- // .. 重新查询
- cursor = ...;
- cursor.close();
- }
- }
- ```
-2. 一方在发生变化的时候去发送改变的消息
- 对于一些系统的内容提供者内部都实现了该步骤,如果是自己写程序想要暴露就必须要加上该代码。
-
- ```java
- getContext().getContentResolver().notifyChange(uri, null);
- ```
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213Service.md" "b/Android\345\237\272\347\241\200/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213Service.md"
deleted file mode 100644
index fcb8806c..00000000
--- "a/Android\345\237\272\347\241\200/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213Service.md"
+++ /dev/null
@@ -1,204 +0,0 @@
-Android四大组件之Service
-===
-
-服务的两种开启方式:
----
-
-1. startService();开启服务.
-开启服务后 服务就会长期的后台运行,即使调用者退出了.服务仍然在后台继续运行.服务和调用者没有什么关系, 调用者是不可以访问服务里面的方法.
-2. bindService();绑定服务.
-服务开启后,生命周期与调用者相关联.调用者挂了,服务也会跟着挂掉.不求同时生,但求同时死.调用者和服务绑定在一起,调用者可以间接的调用到服务里面的方法.
-
-AIDL
----
-
-本地服务:服务代码在本应用中
-远程服务:服务在另外一个应用里面(另外一个进程里面)
-aidl: android interface defination language
-IPC implementation : inter process communication
-
-服务混合调用的生命周期
----
-
-开启服务后再去绑定服务然后再去停止服务,这时服务是无法停止了.必须先解绑服务然后再停止服务,在实际开发中会经常采用这种模式,开启服务(保证服务长期后台运行) --> 绑定服务(调用服务的方法) --> 解绑服务(服务继续在后台运行) --> 停止服务(服务停止),服务只会被开启一次,如果已经开启后再去执行开启操作是没有效果的。
-
-绑定服务调用方法的原理
----
-
-1. 定义一个接口,里面定义一个方法
-```java
- public interface IService {
- public void callMethodInService();//通过该类中提供一个方法,让自定
- 义的类实现这个接口
- }
-```
-2. 在服务中自定义一个IBinder的实现类,让这个类继承Binder(Binder是IBinder的默认适配器),由于这个自定义类是私有的,为了其他类中能拿到该类,我们要定义一个接口,提供一个方法,让IBinder类去实现该接口,并在相应方法中调用自己要供别人调用的方法。
-```java
- public class TestService extends Service {
- @Override
- public IBinder onBind(Intent intent) {
- System.out.println("onbind");
- return new MyBinder();
- }
-
- private class MyBinder extends Binder implements IService{
- public void callMethodInService(){
- //实现该方法,去调用服务中的方法
- methodInService();
- }
- }
- //服务中的方法
- public void methodInService(){
- Toast.makeText(this, "我是服务里面的春哥,巴拉布拉!", 0).show();
- }
- }
-```
-3. 服务的调用类中将`onServiceConnected`方法中的第二个参数强转成接口
-```java
- public class DemoActivity extends Activity {
- private Intent intent;
- private Myconn conn;
- private IService iService;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- intent = new Intent(this,TestService.class);
- setContentView(R.layout.main);
- }
- public void start(View view) {
- startService(intent);
- }
- public void stop(View view) {
- stopService(intent);
- }
- public void bind(View view) {
- conn = new Myconn();
- //1.绑定服务 传递一个conn对象.这个conn就是一个回调接口
- bindService(intent, conn, Context.BIND_AUTO_CREATE);
- }
- public void unbind(View view) {
- unbindService(conn);
- }
- //调用服务中的方法
- public void call(View view){
- iService.callMethodInService();
- }
- private class Myconn implements ServiceConnection{
- //当服务被成功绑定的时候调用的方法.
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {//第二个参数就是服务中的onBind方法的返回值
- iService = (IService) service;
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- }
- }
-```
-
-远程服务aidl
----
-
-上面介绍了绑定服务调用服务中方法的原理,对于远程服务的绑定也是这样,
-但是这个远程服务是在另外一个程序中的,在另外一个程序中定 义的这个接口,
-在另外一个程序中是拿不到的,就算是我们在自己的应用 中也定义一个一模一样
-的接口,但是由于两个程序的报名不同,这两个接口也是不一样的,为了解决这个
-问题,谷歌的工程师给提供了aidl,我们将定义的这个接口的`.java`改成 `.aidl`,
-然后将这个接口中的`权限修饰符`都**去掉**,在另一个程序中拷贝这个aidl文
-件,然后放到同一个包名中,由于`Android`中通过包名来区分应用程序,这两个
-`aidl`的包名一样,系统会认为两个程序中的接口是同一个,这样就能够在另一
-个程序中将参数强转成这个接口,在使用`aidl`文件拷贝到自己的工程之后会自动
-生成一个接口类,这个接口类中有 一个内部类`Stub`该类继承了`Binder`并实现了
-这个接口,所以我们在自定义 `IBinder的实现类`时只需让自定义的类继承`Stub类`
-即可.
-
-1. 远程服务中定义一个接口,改成`aidl`
-```java
- package com.seal.test.service;
-
- interface IService {
- void callMethodInService();
- }
-```
-
-2. 远程服务中定义一个`Ibinder的实现类`,让这个实现类继承上面接口的`Stub类`,
-并在`onBind`方法中返回这个自定义类对象
-```java
- public class RemoteService extends Service {
- @Override
- public IBinder onBind(Intent intent) {
- System.out.println("远程服务被绑定");
- return new MyBinder();
- }
- private class MyBinder extends IService.Stub{
- @Override
- public void callMethodInService() {
- methodInService();
- }
- }
- public void methodInService(){
- System.out.println("我是远程服务里面的方法");
- }
- }
-```
-
-3. 在其他程序中想要绑定这个服务并且调用这个服务中的方法的时候首先要拷贝
-这个`aidl`文件到自己的工程,然后再`ServiceConnection`的实现类中将这个参数使
-用`asInterface`方法转成接口,通过这样来得到接口,从而调用接口中的方法
-```java
- public class CallRemoteActivity extends Activity {
- private Intent service;
- private IService iService;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- service = new Intent();
- service.setAction("com.itheima.xxxx");
- }
- public void bind(View veiw){
- bindService(service, new MyConn(), BIND_AUTO_CREATE);
- }
- public void call(View view){
- try {
- iService.callMethodInService();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- private class MyConn implements ServiceConnection{
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- iService = IService.Stub.asInterface(service);
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // TODO Auto-generated method stub
- }
- }
- }
-```
-
-最后说一下`IntentService`:
-
-`IntentService`是`Service`的子类,用来处理异步请求。客户端可以通过`startService(Intent)`方法将请求的`Intent`传递请求给`IntentService`,
-`IntentService`会将该`Intent`加入到队列中,然后对每一个`Intent`开启一个`worker thread`来进行处理,执行完所有的工作之后自动停止`Service`。
-每一个请求都会在一个单独的`worker thread`中处理,不会阻塞应用程序的主线程。`IntentService` 实际上是`Looper`、`Handler`、`Service` 的集合体,他不仅有服务的功能,还有处理和循环消息的功能.
-
-- Service:
- 1. A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
- 2. A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
-所以在`Service`中进行耗时的操作时必须要新开一个线程。
-至于为什么要使用`Service`而不是`Thread`,这个主要的区别就是生命周期不同,`Service`是Android系统的一个组件,Android系统会尽量保持`Service`的长期后台运行,
-即使内存不足杀死了该服务(很少会出现内存不足杀死服务的情况)也会在内存可用的时候去复活该服务,而`Thread`随后都会被杀死
-- IntentService
- 1. IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests throughstartService(Intent) calls;
- the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
- 2. This "work queue processor" pattern is commonly used to offload tasks from an application's main thread. The IntentService class exists to simplify this pattern and take care of the mechanics.
- To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.
- 3. All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
diff --git "a/Android\345\237\272\347\241\200/Android\347\274\226\347\240\201\350\247\204\350\214\203_v0.2.docx" "b/Android\345\237\272\347\241\200/Android\347\274\226\347\240\201\350\247\204\350\214\203_v0.2.docx"
deleted file mode 100644
index 6919f186..00000000
Binary files "a/Android\345\237\272\347\241\200/Android\347\274\226\347\240\201\350\247\204\350\214\203_v0.2.docx" and /dev/null differ
diff --git "a/Android\345\237\272\347\241\200/Android\351\235\242\350\257\225\347\237\245\350\257\206\347\202\271.doc" "b/Android\345\237\272\347\241\200/Android\351\235\242\350\257\225\347\237\245\350\257\206\347\202\271.doc"
deleted file mode 100644
index 73acdb6c..00000000
Binary files "a/Android\345\237\272\347\241\200/Android\351\235\242\350\257\225\347\237\245\350\257\206\347\202\271.doc" and /dev/null differ
diff --git "a/Android\345\237\272\347\241\200/Android\351\235\242\350\257\225\351\242\230\345\270\246\347\255\224\346\241\210.doc" "b/Android\345\237\272\347\241\200/Android\351\235\242\350\257\225\351\242\230\345\270\246\347\255\224\346\241\210.doc"
deleted file mode 100644
index 801e5250..00000000
Binary files "a/Android\345\237\272\347\241\200/Android\351\235\242\350\257\225\351\242\230\345\270\246\347\255\224\346\241\210.doc" and /dev/null differ
diff --git "a/Android\345\237\272\347\241\200/AsyncTask\345\210\206\346\236\220.md" "b/Android\345\237\272\347\241\200/AsyncTask\345\210\206\346\236\220.md"
deleted file mode 100644
index c8547081..00000000
--- "a/Android\345\237\272\347\241\200/AsyncTask\345\210\206\346\236\220.md"
+++ /dev/null
@@ -1,125 +0,0 @@
-AsyncTask分析
-===
-
-1. 经典版异步任务
- ```java
- public abstract class MyAsyncTask {
- private Handler handler = new Handler(){
- public void handleMessage(android.os.Message msg) {
- onPostExecute();
- };
- };
-
- /**
- * 后台任务执行之前 提示用户的界面操作.
- */
- public abstract void onPreExecute();
-
- /**
- * 后台任务执行之后 更新界面的操作.
- */
- public abstract void onPostExecute();
-
- /**
- * 在后台执行的一个耗时的操作.
- */
- public abstract void doInBackground();
-
-
- public void execute(){
- //1. 耗时任务执行之前通知界面更新
- onPreExecute();
- new Thread(){
- public void run() {
- doInBackground();
- handler.sendEmptyMessage(0);
- };
- }.start();
-
- }
- }
- ```
-2. 谷歌异步任务
- ```java
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- blackNumberInfos = dao.findByPage(startIndex, maxNumber);
- return null;
- }
- @Override
- protected void onPreExecute() {
- loading.setVisibility(View.VISIBLE);
- super.onPreExecute();
- }
- @Override
- protected void onPostExecute(Void result) {
- loading.setVisibility(View.INVISIBLE);
- if (adapter == null) {// 第一次加载数据 数据适配器还不存在
- adapter = new CallSmsAdapter();
- lv_callsms_safe.setAdapter(adapter);
- } else {// 有新的数据被添加进来.
- adapter.notifyDataSetChanged();// 通知数据适配器 数据变化了.
- }
- super.onPostExecute(result);
- }
- }.execute();
-
- 类的构造方法中接收三个参数,这里我们不用参数就都给它传Void,new出来AsyncTask类之后然后重写这三个方法,最后别忘了执行execute方法,其实它的内部和我们写的经典版的异步任务相同,也是里面写了一个在新的线程中去执行耗时的操作,然后用handler发送Message对象,主线程收到这个Message之后去执行onPostExecute中的内容。
-
-
- //AsyncTask ,params 异步任务执行(doBackgroud方法)需要的参数这个参数的实参可以由execute()方法的参数传入,Progess 执行的进度,result是(doBackground方法)执行后的结果
-
- new AsyncTask() {
- ProgressDialog pd;
- @Override
- protected Boolean doInBackground(String... params) { //这里返回的就是执行的接口,这个返回的结果会传递给onPostExecute的参数
- try {
- String filename = params[0];//得到execute传入的参数
- File file = new File(Environment.getExternalStorageDirectory(),filename);
- FileOutputStream fos = new FileOutputStream(file);
- SmsUtils.backUp(getApplicationContext(), fos, new BackUpStatusListener() {
- public void onBackUpProcess(int process) {
- pd.setProgress(process);
- }
-
- public void beforeBackup(int max) {
- pd.setMax(max);
- }
- });
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- @Override
- protected void onPreExecute() {
- pd = new ProgressDialog(AtoolsActivity.this);
- pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- pd.setMessage("正在备份短信");
- pd.show();
- super.onPreExecute();
- }
- @Override
- protected void onPostExecute(Boolean result) {
- pd.dismiss();
- if(result){
- Toast.makeText(getApplicationContext(), "备份成功", 0).show();
- }else{
- Toast.makeText(getApplicationContext(), "备份失败", 0).show();
- }
- super.onPostExecute(result);
- }
-
- }.execute("backup.xml"); //这里传入的参数就是doInBackgound中的参数,会传入到doInBackground中
-
- ProgressDialog有个方法
- incrementProgressBy(int num);方法,这个方法能够让进度条自动增加,如果参数为1就是进度条累加1。
-
- 可以给ProgressDialog添加一个监听dismiss的监听器。pd.setOnDismisListener(DismisListener listener);让其在取消显示后做什么事
- ```
-
-----
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/JNI_C\350\257\255\350\250\200\345\237\272\347\241\200.md" "b/Android\345\237\272\347\241\200/JNI_C\350\257\255\350\250\200\345\237\272\347\241\200.md"
deleted file mode 100644
index c492bcf2..00000000
--- "a/Android\345\237\272\347\241\200/JNI_C\350\257\255\350\250\200\345\237\272\347\241\200.md"
+++ /dev/null
@@ -1,458 +0,0 @@
-JNI_C语言基础
-===
-
-1.JNI(java native interface)
- `Java`本地开发接口,`JNI`是一个协议,这个协议用来沟通`Java`代码和外部的本地代码(`c/c++`).通过这个协议`Java`代码就可以调用外部的`c/c++`代码,外部的`c/c++`代码也可以调用java代码,
-使用JNI技术,其实就是在Java程序中,调用C语言的函数库中提供的函数,来完成一些Java语言无法完成的任务。由于Java语言和C语言结构完全不相同,因此若想让它们二者交互,则需要制定一系列的规范。
-JNI就是这组规范,此时 Java只和JNI交互,而由JNI去和C语言交互。
-JNI技术分为两部分:Java端和C语言端。且以Java端为主导。
-|- 首先,Java程序员在Java端定义一些native方法,并将这些方法以C语言头文件的方式提供给C程序员。
-|- 然后,C程序员使用C语言,来实现Java程序员提供的头文件中定义的函数。
-|- 接着,C程序员将函数打包成一个库文件,并将库文件交给Java程序员。
-|- 最后,Java程序员在Java程序中导入库文件,然后调用native方法。
-在Java程序执行的时候,若在某个类中调用了native方法,则虚拟机会通过JNI来转调用库文件中的C语言代码。提示:C代码最终是在Linux进程中执行的,而不是在虚拟机中。
-
-2.为什么要用JNI
-|- 首先,Java语言提供的类库无法满足要求(驱动开发 wifi等),且在数学运算,实时渲染的游戏上,音视频处理等方面上与C/C++相比效率稍低。
-|- 然后,Java语言无法直接操作硬件,C/C++代码不仅能操作硬件而且还能发挥硬件最佳性能。
-|- 接着,使用Java调用本地的C/C++代码所写的库,省去了重复开发的麻烦,并且可以利用很多开源的库提高程序效率。Opencore
-|- 接着,特殊的业务场景,java能反编译但是c不能,因此对于一些不想让别人知道的东西可以用c,加密等
-
-3.怎么用JNI
- 1.C/C++语言 2.掌握java jni流程 3.NDK (native develop kits )
-
-4.指针和指针变量的关系
-指针就是地址,地址就是指针
-地址就是内存单元的编号
-指针变量是存放地址(指针)的变量
-指针和指针变量是两个不同的概念
-但是要注意: 通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样
-
-
- 1\ 未经过初始化的指针变量,不能够直接使用
- 2\ 指针变量的类型 不能够相互转换
- 3\函数的变量(静态)不能够跨函数访问,失去了函数变量的访问范围(生命周期),因为方法执行完之后会释放内存,所以方法中的变量就没有了,但是地址值还是能拿到的,因为地址值是内存中真实存在的地址位置
- 4\指针声明的三种方式
- int * p; //p 是变量的名字, int * 是一个类型,这个变量存放的是int类型变量的地址。
- int* p int * p int *p
-
-5.*号的三种含义
- 1.乘法 3*5
- 2.定义指针变量 int * p;
- 3.指针运算符,如果p是一个已经定义好的指针变量,则*p表示以p的内容为地址的变量
-
-
-6.为什么要使用指针(指针的重要性)
- 直接访问硬件 (opengl 显卡绘图)
- 快速传递数据(指针表示地址)
- 返回一个以上的值(返回一个数组或者结构体的指针)
- 表示复杂的数据结构(结构体)
- 方便处理字符串
- 指针有助于理解面向对象
-
-
-7.指针和数组的关系
- 一维数组的数组名是个指针常量,它存放的是一维数组第一个元素的地址
-C中数组的定义比较死板,中括号必须放到名字的后面
-int a[5];
-printf("%#X\n",&a[0]);
-printf("%#X\n",&a);
-
-如果p是一维数组 则p[i] 等价于 *(p+i),都是得到一维数组中的第i个元素。
-
-在c语言中不会检查角标越界如int a[5]写a[5]不会报错
-
-8.动态分配内存Malloc
-
-采用malloc在椎内存中申请空间
-#include //不能省 malloc 是 memory(内存) allocate(分配)的缩写
-#include
-
-main(){
- //malloc() 在堆空间中动态的申请一块连续的内存空间(数组)
- // 参数: 指定申请的内存空间的大小(字节)
- // 返回值: 所申请空间的首地址(数组的第一个元素的地址),返回值是Void数据类型
-
- int* p = (int*) malloc( sizeof(int) ); //因为返回值是一个Void类型,所以要强转
- *p = 99;
-
- //free()释放已经分配的内存块
- //参数: 指定释放哪块内存空间(地址)
-
- free(p);
- printf("内容是 %d\n", *p); //上面的free只是释放内存块中的内容,但是打印这个内存块的地址还是能够打印出来的,因为这个内存块的地址是内存上的地址是真实存在的
- system("pause");
-}
-
-
-
-
-如果动态申请的内存不够用,那么可以继续申请内存
-用realloc
-/*
- 1\创建数组
- 2、赋值
- 3、打印
-*/
-#include
-#include
-
-void printArr(int* arr, int len){
- int i;
- for( i = 0 ; i < len; i++){
- printf("arr[ %d ]= %d\n", i, *(arr+i));
- }
-
-}
-
-
-main(){
- printf("请您输入所要创建的数组大小: \n");
- int len ;
- scanf("%d", &len); &是取地址符
-
- //动态数组创建
- int* arr = (int*) malloc( sizeof(int) * len);
-
- printf("请您为每个元素赋值: \n");
-
- int i;
- for(i = 0; i < len; i++){
- int temp;
- scanf("%d", &temp);
-
- *(arr + i) = temp;
- }
-
- //打印
- printf("数组元素的值为: \n");
- printArr(arr, len);
-
- //-----------------------------------------
-
- printf("请输入增加的元素个数: \n");
- int count;
- scanf("%d", &count);
-
- //更改数组大小
- //realloc()
- //参数1: 指定所需修改的数组
- //参数2: 指定修改后的数组的大小
- //返回值:修改后数组的首地址 (VOID)
- arr = (int*) realloc(arr, len + count);
-
- printf("请为新增加的元素赋值: \n");
-
- int j;
- for(j = len; j < len + count; j++){
- int temp;
- scanf("%d", &temp);
-
- *(arr + j) = temp;
- }
-
- //打印
- printf("数组元素的值为: \n");
- printArr(arr, len + count);
-
- system("pause");
-}
-或者有个简单的写法
-main()
-{
- int* arr =(int* ) malloc(sizeof(int)*len) ; //动态申请的内存
- int i=0;
- for(;i char str[] ={'h','e','l','l','o','\0'}; //内部转化为一个字符串的数组,并且在数组的最后一个元素拼装一个\0.
- char cc[20] = "heima 15";
- char cc[20] = {'h','e','i','m','a'};
-
-
-
-11.c文件的后缀是.c
-示例代码:
-c中的打印语句中要有类似占位符,在后面的参数对占位符的内容进行声明
-#include
-main() {
-printf("%d\n",sizeof(int)); //sizeof() 得到制定数据类型的长度(占用字节数)参数 接受一个数据类型
-printf("%d\n",sizeof(char));
-system("pause");//可以执行命令行中的命令如 system("shutdown -s -t 60");如果不加pause,运行窗口会一闪而过,因为会释放内存,把dos关闭了,所以要加上pause
-}
-
-
-12.C中的输入输出
-%d - int
-%ld – long int
-%c - char
-%f - float
-%lf – double
-%x – 十六进制输出 int 或者long int 或者short int
-%#x – 以0x开头 十六进制输出 int 或者long int 或者short int
-%o - 八进制输出
-%s – 字符串
-
-13. // c语言从键盘输入一个字符串
- //scanf() 接收键盘输入的数据,参数1: 指定接收的数据的数据类型参数 2: 指定接收的数据存放的位置
- #include
-main() {
- char c[20];
- scanf("%s", c);
- printf("%s", c);
- system("pause");
-}
-
-
-14.取地址符 &(能得到一个对象的地址)
-15.C中两个数的交换
-#include
-void swap(int* i, int* j) {
- int temp = *i;
- *i = *j;
- *j = temp;
-}
-main() {
- int i = 3;
- int j = 5;
- swap(&i, &j);
- printf("%d",i);
- printf("%d",j);
- system("pause");
-}
-
-
-16.C中的for循环
-#include
-
-/**
-打印输出数组的每一个元素
-*/
-void printArr(int* arr, int len){
- int i;
- for(i=0;i
-int add(int x,int y){
- return x+y;
-}
-main()
-{
- int (*pf)(int x, int y); //定义一个函数的指针,就是讲函数的名字改了,其它的都和函数的定义一样
- pf = add; //将pf指向add
- printf("result=%d\n", pf(3,5)); //使用pf
-
- system("pause");
-}
-
-内存的四个部分 Stack Heap CodeSegment DataSegment
-函数是存放到CodeSegment中的,这个函数的地址就是CodeSegment中的这个函数的地址,我们得到函数的地址如果去访问这个地址就相当于调用了这个函数
-
-19.结构体(类似于java中的类)
-#include
-struct Student
-{
- int age; //4
- float score; //4
- long id; //4
- char sex; //1
-};
-int main(void)
-{
- struct Student st={80,55.6f,10001,'F'};
- printf("st.age=%d\n",st.age);
-
- printf("结构体的长度为%d\n",sizeof(st));//打印出来的结果是16为什么呢? 编译器为了方便起见 做了处理,它将所有的变量的长度都统一成最大的长度
-
- struct Student* pst = &st;//结构体的指针
-
- printf("st.age=%d\n",(*pst).age);//(*pst)就是得到结构体,由于*的优先级比较低,通常要用括号括起来。
-
- printf("age=%d\n",pst->age);//这一行是上一行的简单写法,pst->age 在计算机内部会被转换为 (*pst).age pst->age的含义: pst所指向的结构体变量中的age这个成员
- system("pause");
-
-}
-
-
-结构体的三种写法
-第一种
-struct Student
-{
- int age;
- float score;
- char sex;
-}
-
-第二种
-struct Student2
-{
-int age;
-float score;
-char sex;
-} st2;//相当于java中直接弄了一个对象
-
-第三种
-struct
-{
-int age;
-float score;
-char sex;
-} st3;
-
-
-
-
-20.Union联合体
-#include
-main() {
- struct date { int year, month, day; }today;
- union { long i; int k; char ii; double d; } mix;
-
- printf("date:%d\n",sizeof(struct date));
- printf("mix:%d\n",sizeof(mix));
- mix.i = 33;
- mix.ii = 'a';
- printf("i=%d\n",mix.i); //结果是96,因为联合体是一个公用的内存空间,在存ii的时候将i的值给覆盖了
- //110100000101
-
- system("pause");
-}
- 联合体是一个公用的内存空间,联合体长度为: 占有字节数最大的元素的长度(字节数)
-21.枚举
-enum WeekDay {
-Monday=8,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
-};//这里一定要加分号
-
-int main(void)
-{
- enum WeekDay day = Sunday;
- printf("%d\n",day);//打印出来是14,因为是从8开始往后逐个加1
- system("pause");
- return 0;
-}
-默认的情况是从0开始往后递加
-
-
-22.typedef
-定义别名
-声明自定义数据类型,配合各种原有数据类型来达到简化编程的目的的类型定义关键字。
-typedef int haha; //定义数据类型的别名.
-int main(void)
-{
- haha i = 3;这里haha就相当于int
- printf("i=%d\n",i);
-}
-
-每一个指针占四个字节
-
-
-23.多级指针
-#include
-main() {
- int i = 88;
- int* p = &i;
- int** q = &p; //指针的指针前面要加两个*
- int*** r = &q;
- printf("i=%d\n",***r);
- system("pause");
-}
-
-
-
-C语言常见术语:
-库函数:
-|- 为了代码重用,在C语言中提供了一些常用的、用于执行一些标准任务(如输入/出)的函数,这些函数事先被编译,并生成目标代码,然后将生成的目标代码打包成一个库文件,以供再次使用。 库文件中的函数被称为库函数,库文件被称为函数库。
-通过头文件的方式 把函数库里面所有的函数暴露 .h
-|- 在Windows中C语言库函数中的目标代码都是以.obj为后缀的,Linux中是以 .o为后缀。
-提示:单个目标代码是无法直接执行的,目标代码在运行之前需要使用连接程序将目标代码和其他库函数连接在一起后生成可执行的文件。Windows ->.exe .dll
-Linux -> .so 动态库
- .a 静态库
-头文件:
-|- 头文件中存放的是对某个库中所定义的函数、宏、类型、全局变量等进行声明,它类似于一份仓库清单。若用户程序中需要使用某个库中的函数,则只需要将该库所对应的头文件include到程序中即可。
- |- 头文件中定义的是库中所有函数的函数原型。而函数的具体实现则是在库文件中。
- |- 简单的说:头文件是给编译器用的,库文件是给连接器用的。
-|- 在连接器连接程序时,会依据用户程序中导入的头文件,将对应的库函数导入到程序中。头文件以.h为后缀名。
-函数库:
-|- 动态库:在编译用户程序时不会将用户程序内使用的库函数连接到用户程序的目标代码中,只有在运行时,且用户程序执行到相关函数时才会调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。 .so 动态库
-|- 静态库:在编译用户程序时会将其内使用的库函数连接到目标代码中,程序运行时不再需要动态库。使用静态库生成可执行文件比较大。
-在Linux中:
-|- 静态库命名一般为:lib+库名+.a 。
-|- 如:libcxy.a 其中lib说明此文件是一个库文件,cxy是库的名称,.a说明是静态的。
-|- 动态库命名一般为:lib+库名+.so 。.so说明是动态的。
-Windows 下的动态库 .dll
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/JNI\345\237\272\347\241\200.md" "b/Android\345\237\272\347\241\200/JNI\345\237\272\347\241\200.md"
deleted file mode 100644
index 2ef664bb..00000000
--- "a/Android\345\237\272\347\241\200/JNI\345\237\272\347\241\200.md"
+++ /dev/null
@@ -1,376 +0,0 @@
-JNI基础
-===
-
-1. 将java中的字符串转换成C中字符串的工具方法
- ```
- char* Jstring2CStr(JNIEnv* env, jstring jstr){
- char* rtn = NULL;
- jclass clsstring = (*env)->FindClass(env,"java/lang/String");
- jstring strencode = (*env)->NewStringUTF(env,"GB2312");
- jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
- jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");
- jsize alen = (*env)->GetArrayLength(env,barr);
- jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
- if(alen > 0)
- {
- rtn = (char*)malloc(alen+1); //"\0"
- memcpy(rtn,ba,alen);
- rtn[alen]=0;
- }
- (*env)->ReleaseByteArrayElements(env,barr,ba,0); //
- return rtn;
- }
- ```
-
-2. 程序被运行要经历两个步骤(1.编译 2.链接)
- 编译就是将源文件编译成二进制代码,而链接则是将二进制代码转换成可执行的文件如.exe等头文件.(函数的声明,函数的清单文件)作用: 给编译器看的.
- 库函数: 头文件里面函数的实现.
- 作用:给连接器看的.
-
-3. jni开发的常见错误:
- 错误1: 忘记编写android.mk文件 unknown file: ./jni/Android.mk
- Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk
- /cygdrive/c/android-ndk-r7b/build/core/add-application.mk:133: Android NDK: Aborting... 。 停止。
- 错误2: ndk-build 没有任何反应.
- 忘记配置android.mk脚本
- 错误3: $ ndk-build jni/Android.mk:4: 遗漏分隔符 。 停止。
-中文的回车或者换行
-
- 错误4:java.lang.UnsatisfiedLinkError: hello
-忘记加载了c代码的.so库 或者 函数的签名不正确,没有找到与之对应的c代码
-
- 错误5:07-30 java.lang.UnsatisfiedLinkError: Library Hel1o not found
-没有找到对应的c代码库
-
- 错误6: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
- 07-30 11:53:17.898: INFO/DEBUG(31): Build fingerprint:
- 'generic/sdk/generic/:2.2/FRF91/43546:eng/test-keys'
-
- c代码里面有严重的逻辑错误,产生内存的泄露.
-
- 错误7:
- make: *** [obj/local/armeabi/objs/Hello/Hello.o] Error 1
- 编译的时候 程序出现了问题,c语言的语法有问题
- c语言代码编译错误的时候 先去解决第一个错误.
-
-4. Java调用JNI的前提
- 开发所使用的电脑(windows系统, x86的CPU)
- 目标代码: android手机上运行的.( linux系统, arm的CPU)
- 所以我们要模拟手机的系统,手机的处理器 生成手机上可以运行的二进制代码这就要用到交叉编译;
- 根据运行的设备的不同,可以将cpu分为:
- |- arm结构 :主要在移动手持、嵌入式设备上。
- |- x86结构 : 主要在台式机、笔记本上使用。如Intel和AMD的CPU 。
-
- 交叉编译: 在一种操作系统平台或者cpu平台下 编译生成 另外一个平台(cpu)可以运行的二进制代码.(使用NDK中的ndk-build命令)
-
-工具一: 交叉编译的工具链: NDK
-NDK全称:Native Development Kit 。
-|- NDK是一系列工具的集合,它有很多作用。
- |- 首先,NDK可以帮助开发者快速开发C(或C++)的动态库。
- |- 其次,NDK集成了交叉编译器。使用NDK,我们可以将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
-NDK工具是提供给Linux系统用的(随着版本的升级也可以直接在Windows下使用,但是现在仍不完善有bug),所以要在windows下使用ndk的工具,必须要提供一个工具(linux环境的模拟器)
-
-工具二: cygwin(windows下linux系统环境的模拟器, 主要是为了能够运行ndk的工具)
-安装 devel shell
-
-linux 特点:所有的设备 硬件 都是以文件的方式定义的.
-
-工具三: cdt(c/c++ develop tools) eclipse 的一个插件 用来让c\c++代码 语法高亮显示.
- adt(android develop tools)
-
-
-步骤四:
- 为了不用每次使用ndk-build命令都要进入到ndk的安装目录,这里要进行Path变量的配置。
-配置cygwin的环境变量: 在cygwin安装目录,etc目录,profile的文件 32行 添加ndk工具所在的目录.
-PATH="/usr/local/bin:/usr/bin:/cygdrive/d/android-ndk-r7b:${PATH}"在这个后面加上:ndk-build的路径(注意:在linux中路径的分隔符不是分号而是冒号),改成这样
-PATH="/usr/local/bin:/usr/bin:${PATH}:/cygdrive/d/android-ndk-r7b" //注意这里的路径是在linux系统下的ndk路径而不是windows下的路径
-
-
-5. JNI开发步骤:
- 1.创建一个android工程
- 2.JAVA代码中写声明native 方法 public native String helloFromJNI();
- 3.用javah工具生成头文件
- 4. 创建jni目录,引入头文件,根据头文件实现c代码
- 5.编写Android.mk文件
- 6.Ndk编译生成动态库
- 7.Java代码load 动态库.调用native代码
-
-六.JNI开发之Java中调用C代码步骤
- 1.在java中定义一个要调用的C的方法(本地方法)
- //1.定义一个native的方法
- public native String helloFromC();
- 2..在工程中新建一个jni文件夹(然后在这个文件夹中写c代码,在C中实现java里面定义的c方法默认的时候是自己手写c的方法名,但是很麻烦这里要参考七里面提供的方式,用javah编译后,然后拷贝h的头文件到jni文件夹中,在从h文件拷贝方法的名字,然后实现该方法).
- #include
- #include
-//这个方法的名字的写法固定Java_表示这个方法由Java调用,cn_itcast_ndk表示java的包名DemoActivity表示java中调用这个方法的类名helloFromC表示java中调用这个方法的方法名字
-```
-jstring Java_cn_itcast_ndk_DemoActivity_helloFromC (JNIEnv* env , jobject obj){//这两个参数是固定必不可少的
- //return (*(*env)).NewStringUTF(env,"hello from c!");//调用NewStringUTF这个方法new出来一个java中的String类型的字符串
- return (*env)->NewStringUTF(env,"hello from c!" );//这个写法和上面这个注释掉的一样,只是更简洁一点
-}
-```
-3.在jni文件夹中编写android.mk文件,在这个文件夹中声明要编译的c文件名以后编译后生成的文件名
-```
-LOCAL_PATH := $(call my-dir) //将jni所在的目录返回去到LOCAL_PATH
-#clear_vars 一个函数 初始化编译工具链的所有的变量.
-#特点:清空所有的以LOCAL_开头的变量,但是不会清空LOCAL_PATH的变量
- include $(CLEAR_VARS)
-#指定编译后的文件的名称 符合linux系统下makefile的语法.
-LOCAL_MODULE := Hello
-#指定编译的源文件的名称 ,编译器非常智能
-LOCAL_SRC_FILES := Hello.c
- #指定编译后的文件的类型. 默认编译成动态库 BUILD_SHARED_LIBRARY 扩展名.so .so代码体积很小
-# 静态库 BUILD_STATIC_LIBRARY 扩展名.a .a代码体积很大
-include $(BUILD_SHARED_LIBRARY)
-```
-4.cmd进入到当前的工程的文件夹中(也可以进入到当前工程的jni目录中),然后运行ndk-build工具就能将c文件编译成一个可执行的二进制文件. ->.so,注意用ndk-build编译之后一定要刷新,不然eclipse会缓存旧的不加载新的进来
-5.刷新工程,就能看到多出了两个文件夹
-6.在java中将要调用的c代码加载到java虚拟机中,通过静态代码块的方式
- ```
- public class DemoActivity extends Activity {
- //1.定义一个native的方法
- public native String helloFromC();
-
- static{
- //5.把要调用的c代码 给加载到java虚拟机里面
- System. loadLibrary("Hello");//注意写的是Hello不要加后缀
- }
- }
- ```
-7.调用c代码
- ```
- public void click(View view){
- //调用c代码
- Toast.makeText(this, helloFromC(), 1).show();
-
- }
- ```
-
-七、利用jdk的工具javah动态生成c方法名
- 在上面的调用c中的方法的时候,在c中区实现这个方法的时候的方法名字写起来很复杂,而且容易出去,在java在jdk中提供了一个工具javah,我们只要在windows的dos窗口cmd到classes目录下去执行javah 包名.类名就能够由class文件动态的生成一个c的h文件,在这个h文件中有该class文件中的native方法的名字
- 我们只要拷贝这个h文件到自己工程的jni目录中,然后在c文件中引入这个h文件,并拷贝这个h文件中的方法去实现就可以了
- #include //这个<>是引入工具的h文件
- #include "cn_itcast_ndk2_DemoActivity.h" //对于自己工程中的h文件用""来引入或者引入#include 也可以
-
-JNIEXPORT jstring JNICALL Java_cn_itcast_ndk2_DemoActivity_hello_1_1_1from_1_1_1c //拷贝h文件中生成的方法名
- (JNIEnv * env, jobject obj){
- return (*env)->NewStringUTF(env,"hello_from_c 2!" );
-
-}
- 然后就和上面的步骤一样了
-
-
-注意上面的这个javah的用法师在jdk1.6中用的,如果在jdk1.7中就不能这样用了
-对于jdk1.7在使用javah的工具的时候就不能够直接进入到classes目录下直接运行命令了,而是要将sdk中的platforms下的android版本中的android.jar这个路径加载到classPath的环境变量中(麻烦),或者是直接进入到src目录下用javah包名.类名(简单常用)
-
-八、如何在c中向logcat中打印日志
- 如果想像logcat打印日志就要用到谷歌在ndk中提供的一个工具log.h的头文件
- 步骤:
- 1.在c文件的头上面导入文件,加入下面的这四行代码
- #include //导入log.h
- #define LOG_TAG "clog" //指定打印到logcat的Tag
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) //对后面的这个打印日志的方法起一个别名是LOGD
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
- 2.在android.mk中加载文件
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
-
- LOCAL_MODULE := Hello
- LOCAL_SRC_FILES := Hello.c
- LOCAL_LDLIBS += -llog //新增加这一句,作用是 #把c语言调用的log函数对应的函数库加入到编译的运行时里面 #liblog.so,如果还要加载其他的就在后面继续 -lXXX
- include $(BUILD_SHARED_LIBRARY)
-
- 3.在c的代码中直接使用LOGD或者LOGI就能向logcat中输入打印信息
- JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add
- (JNIEnv * env, jobject obj, jint x, jint y){
- LOGI( "x=%d",x);
- LOGD( "y=%d",y);
- int result = x+y;
- LOGD( "result=%d",result);
- return result;
-}
-
-
-
-
-
-九、如何将java的数据传递给c语言
- 就是java在方法中传值,然后c通过参数得到数据处理后返回和上面的一样
-
-
-
-十、将c中的字符串数组转成java中的string用到jni.h中的一个方法
- jstring (*NewStringUTF)(JNIEnv*, const char*);
-
-
-十一、C中调用java
-c语言回调java的场景.
-1.如果有一个操作已经有方便的java实现,才用c调用java可以避免重复发明一个轮子.
-2.想在c代码里面通知界面更新ui.
-
-C调用java的 思想类似于java中的反射,我们在c中就是通过反射的c实现来找到java中的这个方法,
- 在getMethodID的第二个参数是一个方法的签名,这里我们可以通过jdk提供的一个工具javap,来到classes目录下,然后用 javap -s 类名.方法名 来得到一个方法的签名,这样就能列出来所有方法的签名
-
-```
-/**
- * env JNIEnv* java虚拟机环境的指针.
- *
- *jobject obj ,哪个对象调用的这个native的方法 , obj就代表的是哪个对象
- */
-JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callmethod1
- (JNIEnv * env, jobject obj){
- //思考 java中的反射
- //1.找到某一个类的字节码
- // jclass (*FindClass)(JNIEnv*, const char*);
- jclass jclazz = (*env)->FindClass(env,"cn/itcast/ndk4/DataProvider" );
- if(jclazz==0){
- LOGI( "LOAD CLAZZ ERROR");
- } else{
- LOGI( "LOAD CLAZZ success" );
- }
- //2.找到类的字节码里面的方法.
- // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
-
- jmethodID methodid = (*env)->GetMethodID(env,jclazz,"helloFromJava", "()V"); //最后一个参数是方法的签名
- if(methodid==0){
- LOGI( "LOAD methodid ERROR" );
- } else{
- LOGI( "LOAD methodid success" );
- }
-
- //3.调用方法
- //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
- (*env)->CallVoidMethod(env,obj,methodid);
-}
-```
-
-十二、小知识
-1.Android的API提供了SystemClock类,这个类中有一个方法
-public static void sleep(long ms),这个方法内部对Thread.sleep进行了封装对异常进行了try catch,平时用Thread.sleep还要自己进行捕捉,所以可以使用SystemColock.sleep()还简单
-2.Java中通过java虚拟机来调用c的代码,首先将c的库加载到虚拟机中,但是其实这个c代码并不是运行在java虚拟机中的,而是运行在虚拟机之外的一个单独的进程中
-
-
-十三、自定义一个View控件(用于表示锅炉的压力大小)
- 1.写一个类继承View(View是Android中所有能显示到界面上的东西全的父类)
- 2.重写onDraw()方法,这个方法是该控件被画到桌面上的时候调用的方法。
-
-
-
-
-十四、C++与C代码的不同
- C++文件的后缀是cpp
- C++与C的不同就是C++提供了模板、继承、抽象等
-```
-//将java字符串转成C++字符串的工具方法
-char* Jstring2CStr(JNIEnv* env, jstring jstr)
-{
- char* rtn = NULL;
- jclass clsstring = (env)->FindClass("java/lang/String");
- jstring strencode = (env)->NewStringUTF("GB2312");
- jmethodID mid = (env)->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
- jbyteArray barr= (jbyteArray)(env)->CallObjectMethod(jstr,mid,strencode); // String .getByte("GB2312");
- jsize alen = (env)->GetArrayLength(barr);
- jbyte* ba = (env)->GetByteArrayElements(barr,JNI_FALSE);
- if(alen > 0)
- {
- rtn = (char*)malloc(alen+1); //"\0"
- memcpy(rtn,ba,alen);
- rtn[alen]=0;
- }
- (env)->ReleaseByteArrayElements(barr,ba,0); //
- return rtn;
-}
-JNIEXPORT jstring JNICALL Java_cn_itcast_cpp_DemoActivity_HelloFromC
- (JNIEnv * env, jobject obj){
- //C代码
- //return (*env)->NewStringUTF(env,"haha from c"); 在C中env代表的是C中结构体的指针的指针
- //c++代码
- return env->NewStringUTF("haha from cpp");//在C++中env代表的是C++中结构体的指针
-}
-```
-
-十五、对于JNI中的中文乱码问题
- 老版本的ndk r7之前 r6 r5 r5 crystal r4(编译的时候 语言集 是iso-8859-1)
-在使用老版本ndk 编译出来的so文件的时候 要手动的进行转码.先用iso8859-1解码,再用utf-8编码,在r7(包括)之后的我们只要将C文件的格式改为UTF-8就可以了
-
-十六、文件的格式及格式转换
- 格式转换的原理:
- 1.读取一段数据到内存
- 2.分析这一段数据
- 3.修改里面的内容
- 4.写到文件里面
-
-文件的格式:
- 文件的存储方式是二进制0101这样
- 那么怎么设别文件的类型呢?
- 1.根据扩展名
- 2.根据文件的头信息(头信息才是一个文件的真正的格式),有些文件我们修改了扩展名也可以打开,这是因为打开文件的程序区扫描了文件的头信息,并用头信息中的类型来打开了这个文件
-
-十七、C中读取数据
-```
-#include
-main(){
-//用 法: FILE *fopen(char *filename, char *type); //第二个参数是打开的方式 rt就是读文件, rb就是读二进制
- FILE* fp = fopen("1.txt","rt");
-//用 法: int fread (void *ptr, int size, int nitems, FILE *stream);
- //ptr要读的数据 放在哪一块内存空间里面.
- //size 一次读的数据的长度.
- //nitems 读多少次
- //stream 从哪个文件里面 读
-
- char* buffer = malloc(sizeof(char)*12);
- int len= fread(buffer,sizeof(char),12,fp);
-printf("读了%d个char\n",len);
- printf("str=%s\n",buffer);
- fclose(fp); //关闭掉流
-
- system("pause");
-}
-```
-十八、C中写文件
-```
-#include
-main(){
-//用 法: FILE *fopen(char *filename, char *type);
- FILE* fp = fopen("1.txt","wt");
-//用 法: int fwrite(void *ptr, int size, int nitems, FILE *stream);
- //ptr要向文件写的是哪一块内存里面的数据
- //size 一次写的数据的长度.
- //nitems 写多少次
- //stream 写到哪个文件里面
- char* str="hello from c";
- int len = fwrite(str,sizeof(char),12,fp);
- printf("写了%d个char\n",len);
- fclose(fp); //关闭掉流
-
- system("pause");
-}
-```
-十九、C语言文件操作模式
-“rt” 只读打开一个文本文件,只允许读数据
-“wt” 只写打开或建立一个文本文件,只允许写数据
-“at” 追加打开一个文本文件,并在文件末尾写数据
-“rb” 只读打开一个二进制文件,只允许读数据
-“wb” 只写打开或建立一个二进制文件,只允许写数据
-“ab” 追加打开一个二进制文件,并在文件末尾写数据
-“rt+” 读写打开一个文本文件,允许读和写
-“wt+” 读写打开或建立一个文本文件,允许读写
-“at+” 读写打开一个文本文件,允许读,或在文件末追加数据
-“rb+” 读写打开一个二进制文件,允许读和写
-“wb+” 读写打开或建立一个二进制文件,允许读和写
-“ab+” 读写打开一个二进制文件,允许读,或在文件末追加数据
-
-对于文件使用方式有以下几点说明:
-
- 文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是:
-
-r(read): 读
-w(write): 写
-a(append): 追加
-t(text): 文本文件,可省略不写
-b(banary): 二进制文件
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/Java+Android\351\235\242\350\257\225\351\242\230\345\244\247\345\205\250.doc" "b/Android\345\237\272\347\241\200/Java+Android\351\235\242\350\257\225\351\242\230\345\244\247\345\205\250.doc"
deleted file mode 100644
index 2d8e9ad3..00000000
Binary files "a/Android\345\237\272\347\241\200/Java+Android\351\235\242\350\257\225\351\242\230\345\244\247\345\205\250.doc" and /dev/null differ
diff --git "a/Android\345\237\272\347\241\200/This tag and its children can be replaced by one TextView and a compound drawable.md" "b/Android\345\237\272\347\241\200/This tag and its children can be replaced by one TextView and a compound drawable.md"
deleted file mode 100644
index eb8b7439..00000000
--- "a/Android\345\237\272\347\241\200/This tag and its children can be replaced by one TextView and a compound drawable.md"
+++ /dev/null
@@ -1,48 +0,0 @@
-This tag and its children can be replaced by one TextView and a compound drawable
-===
-
-写项目的时候经常会遇到在`TextView`附近显示图片的问题,一般都是嵌套一层布局。
----
-```xml
-
-
-
-
-
-
-```
-
-这样写的时候会有个`warning`提示,`warning:This tag and its children can be replaced by one TextView and a compound drawable`
-意思就是这样写不合理,可以直接用`TextView`达到这种效果
-```xml
-
-```
-代码的方式: `mBatteryLevel.setCompoundDrawables(left, top, right, bottom);`
-
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/WebView\346\200\273\347\273\223.md" "b/Android\345\237\272\347\241\200/WebView\346\200\273\347\273\223.md"
deleted file mode 100644
index 0d2beb10..00000000
--- "a/Android\345\237\272\347\241\200/WebView\346\200\273\347\273\223.md"
+++ /dev/null
@@ -1,81 +0,0 @@
-WebView总结
-===
-
-在`Android`中有`WebView Widget`,它内置了`WebKit`引擎,同时,`WebKit`也是`Mac OS X`的`Safari`网页浏览器的基础。`WebKit`是一个开源的浏览器引擎,`Chrome`浏览器也是基于它的。所以很多表现`WebView`和`Chrome`是一样的。
-
-很多文章中多会说在使用`WebView`之前,要在`AndroidManifest.xml`中添加 如下权限:
-``
-否则会出`Web page not available`错误。其实这是不全面的,如果我加载本地的页面是不用该权限的。
-
-- 设置WevView要显示的网页方法有很多:
- - `mWebView.loadUrl(“http://www.google.com“);` // 网络
- - `mWebView.loadUrl(“file:///android_asset/XX.html“);` // 本地页面,这里的格式是固定的,文件要放到`assets`目录下
- - `mWebview.postUrl(String url, byte[] postData); // 加载页面使用`Post`方式,`postData`为参数`
- ```java
- String postData = "password=password&username=username";
- mWebview.postUrl(url, EncodingUtils.getBytes(postData, "base64"));
- ```
- - mWebView.loadData(htmlString, "text/html", "utf-8"); // 加载Html数据
- ```java
- String htmlString = "Title
This is HTML text
Formatted in italics
Anothor Line
";
- mWebView.loadData(htmlString, "text/html", "utf-8"); // 加载Html数据
- ```
- - `loadData()`不能加载图片内容,如果要加载图片内容或者获得更强大的Web支持请使用`loadDataWithBaseURL()`。
- - 显示乱码
- `WebView`一般为了节省资源使用`UTF-8`编码,而`String`类型的数据主要是`Unicode`编码,因此在`loadData()`的时候需要设置相应编码让其将`Unicode`编码转成`UTF-8`但是有些时候设置后还是会出现乱码,这是因为还需要为`WebView`中的
- `Text`设置编码,
-
- ```java
- WebView mWebView = (WebView)findViewById(R.id.webview) ;
- String content = getUnicodeContent() ;
- mWebView.getSettings().setDefaultTextEncodingName(“UTF -8”) ;
- mWebView.loadData(content, “text/html”, “UTF-8”) ;
- ```
-
-- 设置WebView基本信息:
- - 如果访问的页面中有`Javascript`,则`webview`必须设置支持`Javascript`。
- `webview.getSettings().setJavaScriptEnabled(true); `
- - 触摸焦点起作用
- `requestFocus() // 如果不设置的话,会出现不能弹出软键盘等问题。`
- - 取消滚动条
- `this.setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);`
-
-- Back键的处理
- 如果用`webview`点链接看了很多页以后,如果不做任何处理,点击系统`Back`键,整个浏览器会调用`finish()`而结束自身,如果希望浏览的网页回退而不是退出浏览器,需要在当前`Activity`中处理并消费掉该`Back`事件。
-
- ```java
- public boolean onKeyDown(int keyCoder,KeyEvent event){
- if(webView.canGoBack() && keyCoder == KeyEvent.KEYCODE_BACK){
- webview.goBack(); //goBack()表示返回webView的上一页面
- return true;
- }
- return false;
- }
- ```
-
-- WebView中Padding没有效果
- `WebView`中使用`Padding`没有效果,我们在`WebView`外层包上一层布局就会有所改进,但是不能完全解决问题,正确的做法是在`WebView`的加载`css`中增加`Padding`
-
-- WebViewClient
- 如果希望点击链接由自己处理,而不是新开`Android`的系统`browser`中响应该链接。给`WebView`添加一个事件监听对象`WebViewClient`并重写其中的一些方法: `shouldOverrideUrlLoading`对网页中超链接按钮的响应。当按下某个连接时`WebViewClient`会调用这个方法,并传递按下的url。
- 1. 接收到 Http 请求的事件
-
- `onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) `
- 2. 打开链接前的事件
-
- `public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } `
- 这个函数我们可以做很多操作,比如我们读取到某些特殊的URL,于是就可以不打开地址,取消这个操作,进行预先定义的其他操作,这对一个程序是非常必要的。
- 3. 载入页面完成的事件
-
- `public void onPageFinished(WebView view, String url){ } `
- 页面载入完成,于是我们可以关闭`loading`条,切换程序动作。
- 4. 载入页面开始的事件
-
- `public void onPageStarted(WebView view, String url, Bitmap favicon)`
- 这个事件就是开始载入页面调用的,通常我们可以在这设定一个loading的页面,告诉用户程序在等待网络响应。
-
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
diff --git "a/Android\345\237\272\347\241\200/\345\244\232\347\272\277\347\250\213\346\226\255\347\202\271\344\270\213\350\275\275.md" "b/Android\345\237\272\347\241\200/\345\244\232\347\272\277\347\250\213\346\226\255\347\202\271\344\270\213\350\275\275.md"
deleted file mode 100644
index fcb449a1..00000000
--- "a/Android\345\237\272\347\241\200/\345\244\232\347\272\277\347\250\213\346\226\255\347\202\271\344\270\213\350\275\275.md"
+++ /dev/null
@@ -1,193 +0,0 @@
-多线程断点下载
-===
-
-1. 多线程下载
- ```java
- public class MultiThreadDownloader {
-
- private URL url; // 目标地址
- private File file; // 本地文件
- private long threadLen; // 每个线程下载多少
-
- private static final int THREAD_AMOUNT = 3; // 线程数
- private static final String DIR_PATH = "F:/Download"; // 下载目录
-
- public MultiThreadDownloader(String address) throws IOException {
- url = new URL(address); // 记住下载地址
- file = new File(DIR_PATH, address.substring(address.lastIndexOf("/") + 1)); // 截取地址中的文件名, 创建本地文件
- // 创建一个临时文件路径
- }
-
- public void download() throws IOException {
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(3000);
-
- long totalLen = conn.getContentLength(); // 获取文件总长度
- threadLen = (totalLen + THREAD_AMOUNT - 1) / THREAD_AMOUNT; // 计算每个线程要下载的长度
-
- // 总长度 如果能整除 线程数, 每条线程下载的长度就是 总长度 / 线程数
- // 总长度 如果不能整除 线程数, 那么每条线程下载长度就是 总长度 / 线程数 + 1
-
- RandomAccessFile raf = new RandomAccessFile(file, "rw"); // 在本地创建一个和服务端大小相同的文件
- raf.setLength(totalLen); // 设置文件的大小, 写入了若干个0
- raf.close();
-
- // 创建临时文件
-
- for (int i = 0; i < THREAD_AMOUNT; i++) // 按照线程数循环
- new DownloadThread(i).start(); // 开启线程, 每个线程将会下载一部分数据到本地文件中
- }
-
- private class DownloadThread extends Thread {
- private int id; // 用来标记当前线程是下载任务中的第几个线程
-
- public DownloadThread(int id) {
- this.id = id;
- }
-
- public void run() {
- // 从临时文件读取当前线程已完成的进度
-
- long start = id * threadLen; // 起始位置
- long end = id * threadLen + threadLen - 1; // 结束位置
- System.out.println("线程" + id + ": " + start + "-" + end);
-
- try {
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(3000);
- conn.setRequestProperty("Range", "bytes=" + start + "-" + end); // 设置当前线程下载的范围(start和end都包含)
-
- InputStream in = conn.getInputStream(); // 获取连接的输入流, 用来读取服务端数据
- RandomAccessFile raf = new RandomAccessFile(file, "rw"); // 随机读写文件, 用来向本地文件写出
- raf.seek(start); // 设置保存数据的位置
-
- byte[] buffer = new byte[1024 * 100]; // 每次拷贝100KB
- int len;
- while ((len = in.read(buffer)) != -1) {
- raf.write(buffer, 0, len); // 从服务端读取数据, 写到本地文件
- // 存储当前下载进度到临时文件
- }
- raf.close();
-
- System.out.println("线程" + id + "下载完毕");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- public static void main(String[] args) throws IOException {
- new MultiThreadDownloader("http://192.168.1.240:8080/14.Web/android-sdk_r17-windows.zip").download();
- }
- }
- ```
-
-2. 断点下载
- ```java
- public class BreakpointDownloader {
- private static final String DIR_PATH = "F:/Download"; // 下载目录
- private static final int THREAD_AMOUNT = 3; // 总线程数
-
- private URL url; // 目标下载地址
- private File dataFile; // 本地文件
- private File tempFile; // 用来存储每个线程下载的进度的临时文件
- private long threadLen; // 每个线程要下载的长度
- private long totalFinish; // 总共完成了多少
- private long totalLen; // 服务端文件总长度
- private long begin; // 用来记录开始下载时的时间
-
- public BreakpointDownloader(String address) throws IOException {
- url = new URL(address); // 记住下载地址
- dataFile = new File(DIR_PATH, address.substring(address.lastIndexOf("/") + 1)); // 截取地址中的文件名, 创建本地文件
- tempFile = new File(dataFile.getAbsolutePath() + ".temp"); // 在本地文件所在文件夹中创建临时文件
- }
-
- public void download() throws IOException {
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(3000);
-
- totalLen = conn.getContentLength(); // 获取服务端发送过来的文件长度
- threadLen = (totalLen + THREAD_AMOUNT - 1) / THREAD_AMOUNT; // 计算每个线程要下载的长度
-
- if (!dataFile.exists()) { // 如果本地文件不存在
- RandomAccessFile raf = new RandomAccessFile(dataFile, "rws"); // 在本地创建文件
- raf.setLength(totalLen); // 设置文件的大小和服务端相同
- raf.close();
- }
-
- if (!tempFile.exists()) { // 如果临时文件不存在
- RandomAccessFile raf = new RandomAccessFile(tempFile, "rws"); // 创建临时文件, 用来记录每个线程已下载多少
- for (int i = 0; i < THREAD_AMOUNT; i++) // 按照线程数循环
- raf.writeLong(0); // 写入每个线程的开始位置(都是从0开始)
- raf.close();
- }
-
- for (int i = 0; i < THREAD_AMOUNT; i++) // 按照线程数循环
- new DownloadThread(i).start(); // 开启线程, 每个线程将会下载一部分数据到本地文件中
-
- begin = System.currentTimeMillis(); // 记录开始时间
- }
-
- private class DownloadThread extends Thread {
- private int id; // 用来标记当前线程是下载任务中的第几个线程
-
- public DownloadThread(int id) {
- this.id = id;
- }
-
- public void run() {
- try {
- RandomAccessFile tempRaf = new RandomAccessFile(tempFile, "rws"); // 用来记录下载进度的临时文件
- tempRaf.seek(id * 8); // 将指针移动到当前线程的位置(每个线程写1个long值, 占8字节)
- long threadFinish = tempRaf.readLong(); // 读取当前线程已完成了多少
- synchronized(BreakpointDownloader.this) { // 多个下载线程之间同步
- totalFinish += threadFinish; // 统计所有线程总共完成了多少
- }
-
- long start = id * threadLen + threadFinish; // 计算当前线程的起始位置
- long end = id * threadLen + threadLen - 1; // 计算当前线程的结束位置
- System.out.println("线程" + id + ": " + start + "-" + end);
-
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(3000);
- conn.setRequestProperty("Range", "bytes=" + start + "-" + end); // 设置当前线程下载的范围
-
- InputStream in = conn.getInputStream(); // 获取连接的输入流
- RandomAccessFile dataRaf = new RandomAccessFile(dataFile, "rws"); // 装载数据的本地文件(可以理解为输出流)
- dataRaf.seek(start); // 设置当前线程保存数据的位置
-
- byte[] buffer = new byte[1024 * 100]; // 每次拷贝100KB
- int len;
- while ((len = in.read(buffer)) != -1) {
- dataRaf.write(buffer, 0, len); // 从服务端读取数据, 写到本地文件
- threadFinish += len; // 每次写入数据之后, 统计当前线程完成了多少
- tempRaf.seek(id * 8); // 将临时文件的指针指向当前线程的位置
- tempRaf.writeLong(threadFinish); // 将当前线程完成了多少写入到临时文件
- synchronized(BreakpointDownloader.this) { // 多个下载线程之间同步
- totalFinish += len; // 统计所有线程总共完成了多少
- }
- }
- dataRaf.close();
- tempRaf.close();
-
- System.out.println("线程" + id + "下载完毕");
- if (totalFinish == totalLen) { // 如果已完成长度等于服务端文件长度(代表下载完成)
- System.out.println("下载完成, 耗时: " + (System.currentTimeMillis() - begin));
- tempFile.delete(); // 删除临时文件
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- public static void main(String[] args) throws IOException {
- new BreakpointDownloader("http://192.168.1.240:8080/14.Web/android-sdk_r17-windows.zip").download();
- }
- }
- ```
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/\345\261\217\345\271\225\351\200\202\351\205\215.md" "b/Android\345\237\272\347\241\200/\345\261\217\345\271\225\351\200\202\351\205\215.md"
deleted file mode 100644
index 89d98f42..00000000
--- "a/Android\345\237\272\347\241\200/\345\261\217\345\271\225\351\200\202\351\205\215.md"
+++ /dev/null
@@ -1,133 +0,0 @@
-屏幕适配
-===
-
-## 基本概念
-
-Px不同设备显示效果相同。这里的“相同”是指像素数不会变,比如指定UI长度是100px,那不管分辨率是多少UI长度都是100px。也正是因为如此才造成了UI在小分辨率设备上被放大而失真,在大分辨率上被缩小。
-
-#### Screen Size(屏幕尺寸)
-一般所说的手机屏幕大小如1.6英寸、1.9英寸、2.2英寸,都是指的对角线的长度,而不是手机面积。我们可以根据勾股定理获取手机的宽和长,当然还有面积。单位为inch
-
-#### Resolution(分辨率)
-指手机屏幕垂直和水平方向上的像素个数。比如分辨率是480*320,则指设备垂直方向有480个像素点,水平方向有320个像素点。单位px * px,指的是一屏显示多少像素点。
-
-#### Dpi(dots per inch屏幕密度)
-单位dpi,指的是每inch上可以显示多少像素点即px。(每英寸中的像素数)如160dpi指手机水平或垂直方向上每英寸距离有160个像素点。假定设备分辨率为320*240,屏幕长2英寸宽1.5英寸,dpi=320/2=240/1.5=160
-
-#### Dip(Device-independent pixel,设备独立像素)
-同dp,可作长度单位,不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。dip和具体像素值的对应公式是dip值 =设备密度/160* pixel值,可以看出在dpi(像素密度)为160dpi的设备上1px=1dip
-单位dp/dip,指的是自适应屏幕密度的像素,用于指定控件宽高。就所屏幕密度变大,1dp所对应的px也会变大。
-
-#### Sp(ScaledPixels放大像素)
-主要用于字体显示(best for textsize)。根据 google 的建议,TextView 的字号最好使用 sp 做单位,而且查看TextView的源码可知 Android 默认使用 sp 作为字号单位。
-
-
-我们可以用下面的思路来解释为什么用dip代替px作单位:
-设备最终会以px作为长度单位。
-如果我们直接用px作为单位会造成UI在不同分辨率设备上出现不合适的缩放。因此我们需要一种新的单位,这种单位要最终能够以合适的系数换算成px使UI表现出合适的大小。
-Dip符合这种要求吗?
-由dip和具体像素值的对应公式dip值 =设备密度/160* pixel值 可以知
-pixel值=dip值/(设备密度/160),其中dip值是我们指定的长度大小,那么pixel值,160也是定植,也就是说UI最终的pixel值只受像素密度dip的影响,这个dip就相当于那个换算系数,这个系数的值是多少有设备商去决定。因此dip符合这种要求。
-
- 以我自己的Haier W910超级战舰(宽高比16:9)为例,上述单位的换算如下:
- 已知数据:屏幕尺寸4.5, 分辨率1280 * 720, 屏幕密度320
-
- (1)16:9的4.5寸屏幕由勾股定理计算其高约为3.9寸,宽约为2.2寸
-
- (2)则竖向dpi为1280 / 3.9 ≈ 328, 横向dpi为720 / 2.2 ≈ 327
-
- (3)工业上切割液晶板时取整为320
-
- 那么既然dip是自适应屏幕密度的,与px之间又是如何换算呢:
-
- 120dpi(ldpi低密度屏) 1dp = 0.75px (由于像素点是物理点,所以用2个像素点来显示3个dp的内容)
-
- 160dpi(mdpi中密度屏) 1dp = 1px
-
- 213dpi(tvdpi电视密度屏) 1dp = 1.33px
-
- 240dpi(hdpi高密度屏) 1dp = 1.5px
-
- 320dpi(xhdpi极高密度屏) 1dp = 2px
-
- 由上述分析结果可知,控件使用dp,文字使用sp即可满足自适应的需求。
-
-注1:分辨率限定符的匹配是向下匹配,如果没有values-land-mdpi-1024x552,比如,分辨率values-land-mdpi-1024x600的屏幕,当rom不把虚拟键计算到屏幕尺寸时,实际显示的屏幕应该是values-land-mdpi-1024x552,无法适配到values-land-mdpi-1024x600,那这样就可能适配到下一级,比如values-land-mdpi-800x480,但是现在的平板已经没有这么低的分辨率了,所以是配到无限定符的values-mdpi里,造成界面显示上的瑕疵。
-
-注2:由于分辨率限定符的匹配是向下匹配,所以如果有非主流mdpi屏幕不能精确适配到上述指定值时,values-mdpi至少可以保证app运行时不至于崩溃,同理values可以保证ldpi屏幕的平板不会因生成view而又取不到相应值而崩溃。
-
-##android为什么引进dip
-
-The reason for dip to exist is simple enough. Take for instance the T-Mobile G1. It has a pixel resolution of 320x480 pixels. Now image another device, with the same physical screen size, but more pixels, for instance 640x480. This device would have a higher pixel density than the G1.
-
-—If you specify, in your application, a button with a width of 100 pixels, it will look at lot smaller on the 640x480 device than on the 320x480 device. Now, if you specify the width of the button to be 100 dip, the button will appear to have exactly the same size on the two devices.
-
-—The density-independent pixel is equivalent to one physical pixel on a 160 dpi screen, the baseline density assumed by the platform (as described later in this document). At run time, the platform transparently handles any scaling of the dip units needed, based on the actual density of the screen in use. The conversion of dip units to screen pixels is simple: pixels = dips * (density / 160).For example, on 240 dpi screen, 1 dip would equal 1.5 physical pixels.Using dip units to define your application's UI is highly recommended, as a way of ensuring proper display of your UI on different screens.
-
-dip是一种能自适应屏幕密度的像素,这个屏幕密度就是屏幕中一英寸里面含有的像素数,打个比方说,现在有两个4寸的手机,一个分辨率是320*480,它的屏幕密度是1,二另一个是480*800的分辨率,这样他的屏幕密度就是1.5,如果我们在320*480的手机中弄了一个160dp的横线,由于他的屏幕密度是1,所以他里面dp和px是一比一的计算。这样这条横线正好占屏幕的一半,而我们将这个横线的视图发布到480*800的手机上时,虽然也是160dp,但是由于他的屏幕密度是1.5.按照dp与px的计算公式pixel值=dip值/(设备密度/160),可以得到将160dp要乘以1.5倍,这样得到的px就是240px,而这个手机的分辨率正好是480*800,所以看起来仍然是占屏幕的一半。注意:不论多少dp最后都是要通过转换成px来显示的手机的屏幕上的,至于这个dp的大小在屏幕上到底能占多少位置,就要看这个转换后的px与屏幕的宽度像素的比值了。
-
-另一个例子: 打个比方一个是4寸 480*800 的手机,屏幕密度为1.5. 另一个是7寸的1280*800的平板。屏幕密度也为1. 这样用160dp的横线,在480*800的手机上换算成px是160*1.5 = 240,这样横向正好占屏幕的一半,但是在1280*800的平板上,160dp换算后的px为,160*1 = 160px,而屏幕的宽是1280.这样这条横线显示在1280*800的平板上后,是160/1280 正好是八分之一。
-
-所以引入dp解决的是什么问题呢?同一个屏幕尺寸下,对于不同的分辨率,由于尺寸相同,分辨率不同,所以它的屏幕密度就会不一样,这样在同一尺寸的不同分辨率下的设备上,显示出来会看到所占的比例基本一样。如两个7寸的平板,一个是1280*800,一个是2560*1600,这样用dp后,虽然2560*1600的分辨率比那个要大一倍,但是它尺寸一样啊,所以屏幕的分辨率会是另一个的2倍,这样dp转成px后会乘以2.这样显示到这两个设备上所占的比例会一样
-
-一个是7寸1280*800的板,密度为1,一个是5寸 1024*600的板,密度为1.这样你用160dp的线,在前面是8分之一,在后面是六分之一,你就悲剧了,所以要做屏幕适配了
-
-## 代码
-
-```java
-DisplayMetrics displayMetrics = new DisplayMetrics();
-getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
-Log.e("@@@", "density:"+displayMetrics.density); //1
-Log.e("@@@", "densityDpi:"+displayMetrics.densityDpi); //160
-Log.e("@@@", "widthPixels:"+displayMetrics.widthPixels); //1024
-Log.e("@@@", "heightPixels:"+displayMetrics.heightPixels); //600
-```
-这个displayMetrics.densityDpi是真正的屏幕密度,可以为160dpi(mdpi标准的屏幕密度),240dpi(hdpi),320dpi(xhdpi).
-displayMetrics.density,这个不叫屏幕密度,但是在dp和px转换的时候要使用到,这个是屏幕密度的比例值,是用该设备的屏幕密度除以标准的屏幕密度得到的一个比值,如240dpi/160dpi = 1.5
-
-## 屏幕适配文件夹命名规则
-
-- 命名不区分大小写;
-- 命名形式:资源名-属性1-属性2-属性3-属性4-属性5.....
- 资源名就是资源类型名,包括:drawable, values, layout, anim, raw, menu, color, animator, xml;
- 属性1-属性2-属性3-属性4-属性5.....就是上述的属性集内的属性,如:-en-port-hdpi;
- 注意:各属性的位置顺序必须遵守优先级从高到低排列!否则编译不过
-
-- 实例说明
- - 把全部属性都用上的例子(各属性是按优先级先后排列出来的)
- values-mcc310-en-sw320dp-w720dp-h720dp-large-long-port-car-night-ldpi-notouch-keysexposed-nokeys-navexposed-nonav-v7
- - 上述例子属性的中文说明
-values-mcc310(sim卡运营商)-en(语言)-sw320dp(屏幕最小宽度)-w720dp(屏幕最佳宽度)-h720dp(屏幕最佳高度)-large(屏幕尺寸)-long(屏幕长短边模式)-port(当前屏幕横竖屏显示模式)-car(dock模式)-night(白天或夜晚)-ldpi(屏幕最佳dpi)-notouch(触摸屏模类型)-keysexposed(键盘类型)-nokey(硬按键类型)-navexposed(方向键是否可用)-nonav(方向键类型)-v7(android版本)
-
-## 手机常见分辨率
-4:3
-VGA 640*480 (Video Graphics Array)
-QVGA 320*240 (Quarter VGA)
-HVGA 480*320 (Half-size VGA)
-SVGA 800*600 (Super VGA)
-
-5:3
-WVGA 800*480 (Wide VGA)
-
-16:9
-FWVGA 854*480 (Full Wide VGA)
-HD 1920*1080 High Definition
-QHD 960*540
-720p 1280*720 标清
-1080p 1920*1080 高清
-
-
-分辨率对应DPI
-HVGA mdpi
-WVGA hdpi
-FWVGA hdpi
-QHD hdpi
-720P xhdpi
-1080P xxhdpi
-
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
-
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/\345\272\224\347\224\250\345\256\211\350\243\205.md" "b/Android\345\237\272\347\241\200/\345\272\224\347\224\250\345\256\211\350\243\205.md"
deleted file mode 100644
index e6dc7a22..00000000
--- "a/Android\345\237\272\347\241\200/\345\272\224\347\224\250\345\256\211\350\243\205.md"
+++ /dev/null
@@ -1,51 +0,0 @@
-应用安装
-===
-
-1. 在应用程序中安装程序需要权限
- ` `
-
-2. 示例代码
- 安卓中提供了安装程序的功能,我们只要启动安装程序的Activity,并把我们的数据传入即可。
-```java
-//获取到要安装的apk文件的File对象
-File file = new File(Environment.getExternalStorageDirectory(), "test.apk");
-//创建一个意图
-Intent intent = new Intent();
-//设置意图动作
-intent.setAction(Intent.ACTION_VIEW); //android.intent.action.VIEW
-//设置意图数据和类型
-intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
-//启动安装程序的Activity
-startActivity(intent);
-```
-
-**Tip:**
-- `Uri.fromFile(File file)`方法能从一个`File`对象得到它的`Uri`
-- `Intent`有`setData(Uri uri)`和`setType(String type)`方法,但是这里如果我们分开写就会报错,原因是`setData()`方法在执行的时候会自动清空所有在此之前调用的`setType`方法所设置过的type,同样`setType`方法在执行的时候也会自动清空所有在此之前调用`setData`设置的`Data`,所以这里必须使用`setDataAndType`方法而不能分开使用`setData`和`setType`.
-- `Android`中提供了安装应用程序的功能,在`Android`系统源码中`apps/PackageInstaller`中。我们找到这个`PackageInstaller`的清单文件,然后找到`PackageInstallerActivity`来查找该`Activity`的意图:如下
-`android_source/packages/apps/PackageInstaller/AndroidManifest.xml`
-```xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/\345\274\200\345\217\221\344\270\255\345\274\202\345\270\270\347\232\204\345\244\204\347\220\206.md" "b/Android\345\237\272\347\241\200/\345\274\200\345\217\221\344\270\255\345\274\202\345\270\270\347\232\204\345\244\204\347\220\206.md"
deleted file mode 100644
index 57f8ecae..00000000
--- "a/Android\345\237\272\347\241\200/\345\274\200\345\217\221\344\270\255\345\274\202\345\270\270\347\232\204\345\244\204\347\220\206.md"
+++ /dev/null
@@ -1,55 +0,0 @@
-开发中异常的处理
-===
-
-1. 实现未捕捉异常处理器
-```java
- public class MyExceptionHandler implements UncaughtExceptionHandler {
- private static final String TAG = "MyExceptionHandler";
- @Override
- public void uncaughtException(Thread arg0, Throwable arg1) {
- Logger.i(TAG, "发生了异常,但是被哥捕获了...");
- try {
- Field[] fields = Build.class.getDeclaredFields();//可以通过Build的属性来获取到手机的硬件信息,由于不同手机的硬件信息部一定有,所以要用反射得到
- StringBuffer sb = new StringBuffer();
- for(Field field: fields){
- String info = field.getName()+ ":"+field.get(null)+"\n";
- sb.append(info);
- }
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- arg1.printStackTrace(pw);//通过这个来得到异常信息
- String errorlog = sw.toString();
-
- File file = new File(Environment.getExternalStorageDirectory(),
- "error.log");
- FileOutputStream fos = new FileOutputStream(file);
- sb.append(errorlog);
- fos.write(sb.toString().getBytes());
- fos.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- android.os.Process.killProcess(android.os.Process.myPid());//这个是只能杀死自己不能杀死别人,这时候系统发现程序在自己的范围之内死了,系统就会重启程序到出现错误之前的那个Activity。
- }
- }
-```
-
-2. 让这个处理器生效
-```java
- /**
- * 代表的是当前应用程序的进程.
- */
- public class MobliesafeApplication extends Application {
- public BlackNumberInfo info;
-
- @Override
- public void onCreate() {
- super.onCreate();
- Thread.currentThread().setUncaughtExceptionHandler(new MyExceptionHandler());//这样就能够让异常的处理器设置到我们的程序中
- }
- }
-```
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/\346\225\260\346\215\256\345\255\230\345\202\250.md" "b/Android\345\237\272\347\241\200/\346\225\260\346\215\256\345\255\230\345\202\250.md"
deleted file mode 100644
index e8b548ba..00000000
--- "a/Android\345\237\272\347\241\200/\346\225\260\346\215\256\345\255\230\345\202\250.md"
+++ /dev/null
@@ -1,277 +0,0 @@
-数据存储
-===
-
-## `Android`数据存储的几种形式
-
- 1. `Internal Storage`
- `Store private data on the device memory.`
- 通过`mContext.getFilesDir()`来得到`data/data/包名/File`目录
-
- 2. `External Storage`
- `Store public data on the shared external storage.`
-
- ```java
- TextView tv = (TextView) findViewById(R.id.tv_sdsize);
- File path = Environment.getExternalStorageDirectory();
- StatFs stat = new StatFs(path.getPath());
- long blockSize = stat.getBlockSize();
- long availableBlocks = stat.getAvailableBlocks();
- long sizeAvailSize = blockSize * availableBlocks;
- String str = Formatter.formatFileSize(this, sizeAvailSize);
- tv.setText(str);
- ```
-
- 3. `SharedPreferences`
- `Store private primitive data in key-value pairs.`
- 会在`data/data/包名/shared_prefes`里面去创建相应的`xml`文件,根节点是`Map`,其实内部就是将数据保存到`Map`集合中,然后将该集合中的数据写到`xml`文件中进行保存。
- ```xml
-
- ```
-
- ```java
- //获取系统的一个sharedpreference文件 名字叫sp
- SharedPreferences sp = context.getSharedPreferences("sp", Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);
- //创建一个编辑器 可以编辑 sp
- Editor editor = sp.edit();
- editor.putString("name", name);
- editor.putString("password", password);
- editor.putBoolean("boolean", false);
- editor.putInt("int", 8888);
- editor.putFloat("float",3.14159f);
- //注意:调用 commit 提交 数据到文件.
- editor.commit();
- //editor.clear();
- ```
-
- 4. `SQLiteDatabase`
- `Store structured data in a private database.`
- `Android`平台中嵌入了一个关系型数据库`SQLite`,和其他数据库不同的是`SQLite`存储数据时不区分类型,例如一个字段声明为`Integer`类型,我们也可以将一个字符串存入,
- 一个字段声明为布尔型,我们也可以存入浮点数。除非是主键被定义为`Integer`,这时只能存储64位整数创建数据库的表时可以不指定数据类型,例如:
- ```java
- CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(20))
- CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name)
- ```
-
- `SQLite`支持大部分标准`SQL`语句,增删改查语句都是通用的,分页查询语句和`MySQL`相同
- ```java
- SELECT * FROM person LIMIT 20 OFFSET 10
- SELECT * FROM person LIMIT 10,20
- SELECT * FROM reading_history ORDER BY _id DESC LIMIT 3, 4
- DELETE FROM test WHERE _id IN (SELECT _id FROM test ORDER BY _id DESC LIMIT 3, 20)
- ```
-
- `SQLite`数据库的使用
-
- - 继承`SQLiteOpenHelper`
- ```java
- public class NoteSQLiteOpenHelper extends SQLiteOpenHelper {
-
- /**
- * name 数据库的名称 cursorfactory 游标工厂 一般设置null 默认游标工厂 version 数据库的版本
- * 版本号从1开始的
- *
- * @param context
- */
- public NoteSQLiteOpenHelper(Context context) {
- super(context, "note.db", null, 1);
- }
-
- /**
- * oncreate 方法 会在数据库第一创建的时候的是被调用 适合做数据库表结构的初始化
- */
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("create table account (id integer primary key autoincrement , name varchar(20), money varchar(20) )");
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
- db.execSQL("DROP TABLE IF EXISTS " + account);
- this.onCreate(db);
- }
- }
- ```
-
- - 获取
- ```java
- public class NoteDao {
- private NoteSQLiteOpenHelper helper;
-
- public NoteDao(Context context) {
- helper = new NoteSQLiteOpenHelper(context);
- }
-
- /**
- * 添加一条账目信息 到数据库
- *
- * @param name
- * 花销的名称
- * @param money
- * 金额
- */
- public void add(String name, float money) {
- SQLiteDatabase db = helper.getWritableDatabase();
- db.execSQL("insert into account (name,money) values (?,?)",
- new Object[] { name, money });
- // 记住 关闭.
- db.close();
- }
-
- public void delete(int id) {
- SQLiteDatabase db = helper.getWritableDatabase();
- db.execSQL("delete from account where id=?", new Object[] { id });
- db.close();
- }
-
- public void update(int id, float newmoney) {
- SQLiteDatabase db = helper.getWritableDatabase();
- db.execSQL("update account set money =? where id=?", new Object[] {
- newmoney, id });
- db.close();
- }
-
- /**
- * 返回数据库所有的条目
- *
- * @return
- */
- public List findAll() {
- // 得到可读的数据库
- SQLiteDatabase db = helper.getReadableDatabase();
- List noteBeans = new ArrayList();
- // 获取到数据库查询的结果游标
- Cursor cursor = db.rawQuery("select id,money,name from account ", null);
- while (cursor.moveToNext()) {
- int id = cursor.getInt(cursor.getColumnIndex("id"));
- String name = cursor.getString(cursor.getColumnIndex("name"));
- float money = cursor.getFloat(cursor.getColumnIndex("money"));
- NoteBean bean = new NoteBean(id, money, name);
- noteBeans.add(bean);
- bean = null;
- }
-
- db.close();
- return noteBeans;
- }
-
- /**
- * 模拟一个转账的操作. 使用数据库的事务
- *
- * @throws Exception
- */
- public void testTransaction() throws Exception {
- // 得到可写的数据库
- SQLiteDatabase db = helper.getWritableDatabase();
- db.beginTransaction(); // 开始事务
- try {
- db.execSQL("update account set money = money - 5 where id=? ",
- new String[] { "2" });
- db.execSQL("update account set money = money + 5 where id=? ",
- new String[] { "3" });
- db.setTransactionSuccessful();
- } catch (Exception e) {
- // TODO: handle exception
- } finally {
- db.endTransaction();//关闭事务.
- db.close();
- }
- }
- }
- ```
-
- ```java
- public class NoteDao2 {
- private NoteSQLiteOpenHelper helper;
-
- public NoteDao2(Context context) {
- helper = new NoteSQLiteOpenHelper(context);
- }
-
- /**
- * 添加一条账目信息 到数据库
- *
- * @param name
- * 花销的名称
- * @param money
- * 金额
- *
- * @return true 插入成功 false 失败
- */
- public boolean add(String name, float money) {
- SQLiteDatabase db = helper.getWritableDatabase();
- ContentValues values = new ContentValues();
- values.put("name", name);
- values.put("money", money);
- long rawid = db.insert("account", null, values);
- db.close();
- if (rawid > 0) {
- return true;
- } else {
- return false;
- }
- }
-
- public boolean delete(int id) {
- SQLiteDatabase db = helper.getWritableDatabase();
- int result = db.delete("account", "id=?", new String[] { id + "" });
- db.close();
- if (result > 0) {
- return true;
- } else {
- return false;
- }
- }
-
- public boolean update(int id, float newmoney) {
- SQLiteDatabase db = helper.getWritableDatabase();
- ContentValues values = new ContentValues();
- values.put("id", id);
- values.put("money", newmoney);
- int result = db.update("account", values, "id=?", new String[] { id
- + "" });
- db.close();
- if (result > 0) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * 返回数据库所有的条目
- *
- * @return
- */
- public List findAll() {
- // 得到可读的数据库
- SQLiteDatabase db = helper.getReadableDatabase();
- List noteBeans = new ArrayList();
- Cursor cursor = db.query("account", new String[] { "id", "name",
- "money" }, null, null, null, null, null);
- while (cursor.moveToNext()) {
- int id = cursor.getInt(cursor.getColumnIndex("id"));
- String name = cursor.getString(cursor.getColumnIndex("name"));
- float money = cursor.getFloat(cursor.getColumnIndex("money"));
- NoteBean bean = new NoteBean(id, money, name);
- noteBeans.add(bean);
- bean = null;
- }
- db.close();
- return noteBeans;
- }
- }
- ```
- 5. `Network`
- `Store data on the web with your own network server.`
-
-## 清除缓存&清除数据
- 清除数据会清除`/data/data/`包名中的所有文件
- 清楚缓存会清楚`getCacheDir()`目录下的内容,也就是`/data/data/<当前应用程序包名>/cache/`
-
----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/\350\265\204\346\272\220\346\226\207\344\273\266\346\213\267\350\264\235\347\232\204\344\270\211\347\247\215\346\226\271\345\274\217.md" "b/Android\345\237\272\347\241\200/\350\265\204\346\272\220\346\226\207\344\273\266\346\213\267\350\264\235\347\232\204\344\270\211\347\247\215\346\226\271\345\274\217.md"
deleted file mode 100644
index 2d8db144..00000000
--- "a/Android\345\237\272\347\241\200/\350\265\204\346\272\220\346\226\207\344\273\266\346\213\267\350\264\235\347\232\204\344\270\211\347\247\215\346\226\271\345\274\217.md"
+++ /dev/null
@@ -1,26 +0,0 @@
-资源文件拷贝的三种方式
-=====
-
-- 类加载器(类路径)
-
- - 用`Classloader.getResourceAsStream()`来读取类路径中的资源,然后用`FileOutputStream`写入到自己的应用中(*sdk开发的时候经常用这种方式*)。
- - 这种方式**必须**要将数据库`address.db`放到**src**目录下,这样编译后就会直接将`address.db`生成到`bin/classes`目录中,会在类路径下,所以可以使用`Classloader`进行加载.
-
-```java
- InputStream is = getClassLoader().getResourceAsStream("address.db");
- File file = new File(/data/data/包名/files/address.db);
- FileOutputStream fos = new FileOutputStream(file);
-```
-
-- Raw目录
-
- 将资源文件放到`res-raw`下, 然后用`getResources.openRawResource(R.raw.addresss);`(要求资源最好不超过1M,因为系统会编译`res`目录)
-
-- Assets目录
-
- 将资源文件放到`Assets`目录中。然后用`mContext.getAssets().open("address.db");`来读取该资源(`Assets`目录中的文件不会被编译,会原封不动的打包到apk中,所以一般用来存放比较大的资源文件)
-
-----
-
-- 邮箱 :charon.chui@gmail.com
-- Good Luck!
diff --git "a/Android\345\237\272\347\241\200/\351\235\242\350\257\225\347\237\245\350\257\206\347\202\271\345\207\206\345\244\207.txt" "b/Android\345\237\272\347\241\200/\351\235\242\350\257\225\347\237\245\350\257\206\347\202\271\345\207\206\345\244\207.txt"
deleted file mode 100644
index 1ebf7ecb..00000000
--- "a/Android\345\237\272\347\241\200/\351\235\242\350\257\225\347\237\245\350\257\206\347\202\271\345\207\206\345\244\207.txt"
+++ /dev/null
@@ -1,1508 +0,0 @@
-
-
-
-һ
-1˼
- (1)ԶؼUIơöЧ
- 1)Զؼ
- ΪʲôҪԶؼ
- Androidṩ˺ܶؼЩؼеҪûҪԽԽߣҪ
- ˹Ҫȫ⣬ҪûȽűȽԻ飬ʱҪԶؼû顣
- ûdzñȽϻһվ˵û顣
- AndroidеĿؼǼ̳View࣬ͨдonDrawĿؼ
- ʵԶؼ
- ʵԶؼַʽ
- һǼ̳пؼͨдطʵǵ
- ڶǼ̳ViewViewGroupҪĿؼ
- עһ̳ͨеĿؼʵԶؼһ㣬гü̳пؼʵԶؼ
- ListView:
- aListViewʲô
- ʾ
- bListView?
- ҪListViewһAdapterҪʾݽAdapterȥ
- ListViewgetViewÿһʾһĿһɵĿƳΪŻListView
- getView()þĿconvertView
- ListViewgetViewÿִһfindViewByIdʱӦֵ״ṹٱ״ṹҵָid
- òֵ״ṹܸʱÿζidȽ鷳ΪŻǿṩһViewHolder࣬
- ¼епؼеĿؼidֻһΣʱֱViewHolderȡ
- ListViewʾʱҪзػҳʾ
- 3)Ч
- ٶķࣺ
- еĶΪ֣һ֡(Frame)һǽ䶯(Tweened)
- 䶯ַΪֶͣAlphaScaleTranslateRotate
- (2)ݴ䣬Ϥ̡߳Socket̡ϤTCPUDPHTTPЭ
- 1)̸
- ģͣ
- ****OSIģ
- Ӧò
- ʾ
- Ự
-
-
- Ӳ
-
- ****TCP/IPģ
- Ӧò
-
- ʲ
-
- ͨѶҪ
- IPַ
- ˿ں
- Э
- ͨѶǰ
- **ҵԷIP
- **Ҫ͵ָ˿ڡΪ˱ʾͬӦóԸЩӦóֽбʾʾͽж˿
- **ͨŹΪͨЭ飬֯ͨЭTCP/IP
- 1)AndroidӦõĸ
- Androidȫ֧JDKTCPUDPͨAPIʹSocketServerSocketTCP/IPЭͨ;
- ҲʹDatagramSocket/DatagrampacketUDPЭͨš
- ͬʱAndroid֧JDKṩURLURLConnectionͨŵAPI
- 2)TCPUDP
- UDPЭ飺
-
- ÿݱĴС64k
- ΪӣDzɿЭ
- Ҫӣٶȿ
- TCPЭ飺
- 뽨ӣγɴݵͨ
- пɽд
- ͨӣǿɿЭ
- 뽨ӣЧʻԵ
- ע֣
- һΣ㣺ô
- ڶΣشڡ
- ΣҷŶ֪ڡ
- 3)Socket
- **SocketΪṩһֻ
- **ͨŵ˶Socket
- **ͨʵSocketͨ
- **SocketͨIO
- **SocketҪǼס̣ĵ
- 4)UDP(User Datagram Protocol)ûЭ
- UDP
- ҪDatagramSocketDatagramPacketʵUDPЭ鴫
- UDPЭһӵЭ顣ӵЭָʽͨǰԷȽӣܶԷ״ֱ̬ӷݡ
- UDPЭ鿪裺
- **Ͷˣ
- DatagramSocket
- ṩݣݷװֽУ
- DatagramPacketݰݷװУͬʱָնIPͽն˿
- ͨSocketsendݰͳȥ
- رDatagramSocketDatagramPacket
- **նˣ
- DatagramSocketһ˿ڣ
- һֽһݰͬʱװݰ
- ͨDatagramPacketreceiveյݴ붨õݰ
- ͨDatagramPackeرյķȡݰеϢ
- رDatagramSocketDatagramPacket
- UDPЭDemo()
- ****Ͷˣ
- class UDPSend
- {
- public static void main(String[] args) throws Exception
- {
- DatagramSocket ds = new DatagramSocket();
- byte[] buf = "UDPͶ".getBytes();
- DatagramPacket dp = new DatagramPacket(
- buf,buf.length,InetAddress.getByName("192.168.1.253"),10000);
- ds.send(dp);
- ds.close();
- }
- }
- ****ն
- class UDPRece
- {
- public static void main(String[] args) throws Exception
- {
- DatagramSocket ds = new DatagramSocket(10000);
- byte[] buf = new byte[1024];
- DatagramPacket dp = new DatagramPacket(buf,buf.length);
- ds.receive(dp);//Ͷ˷͵ݰյն˵ݰ
- String ip = dp.getAddress().getHosyAddress();//ȡͶ˵ip
- String data = new String(dp.getData(),0,dp.getLength());//ȡ
- int port = dp.getPort();//ȡͶ˵Ķ˿ں
- sop(ip+":"+data+":"+port);
- ds.close();
- }
- }
- עЭĸã
- ʲôЭ飿
- ͨŵһֹ
- Эã
- ֤ͨʵͨ
- 5)TCP/IPЭ飺SocketServerSocket
- ٻTCPЭͨŸ
- TCP/IPͨЭһֱ뽨ӵĿɿͨЭ顣ͨ˸һSocket,Ӷͨŵ֮γ·
- ·һ˵ijͿԽͨš
- TCP/IPЭ鿪裺
- **ͻˣ
- SocketָҪӵͶ˿ڣ
- ȡSocketеOutputStreamдУͨ緢ˣ
- ȡSocketеInputStreamȡ˵ķϢ
- رԴ
- **ˣ
- ServerSocketһ˿ڣ
- ͨServerSocketacceptȡSocket
- ʹÿͻ˶Ķȡȡͻ˷ݣ
- ͨͻ˶дϢͻˣ
- رԴ
- TCP/IPЭһDemo(Ҫգ)
- ͻˣ
- class TCPClient
- {
- public static void main(String[] args)
- {
- Socket s = new Socket("192.168.1.253",10000);
- OutputStream os = s.getOutputStream();
- out.write("TCP͵".getBytes());
- s.close();
- }
- }
- ˣ
- class TCPServer
- {
- public static void main(String[] args)
- {
- ServerSocket ss = new ServerSocket(10000);
- Socket s = ss.accept();
-
- String ip = s.getInetAddress().getHostAddress();
- sop(ip);
-
- InputStream is = s.getInputStream();
- byte[] buf = new byte[1024];
- int len = is.read(buf);
- sop(new String(buf,0,len));
- s.close();
- ss.close();
- }
- }
- 6)HTTPЭ飺
- aHTTPHyper Text Transfer Protocolд
- bW3CƶάġĿǰ汾Ϊ1.01.1
- cǿwebĻʯdzҪ
- d1.0汾״̬Э飬һֻӦһӦ˾رմ˴
- Ҫٷ½ӡӶDZȽϺԴġ
- 1.1汾״̬Э顣һӻϷ͵õεӦ
- ϴʱʱԶϵӣdzʱơ
- HTTPЭɣ
- ֣
- У
- GET / HTTP/1.1 ʽGET Դ·/ Э汾ţHTTP/1.1
- ʽõGETPOST
- GETʽĬϷʽֱַ
- ݳСurl?username=abc&password=123
- ص㣺ȫгƣ<1k
- POSTʽͨform method="post"
- ݻС
- ص㣺ȫûг
- Ϣͷ
- ģһ֮ȫ
- Ӧ֣
- ӦУ
- HTTP/1.1 200 OK Э汾:HTTP/1.1 Ӧ:200 :OK
- Ӧ룺(ʵõ30,W3C)
- Ӧ
- Ӧ룺
- 200һ
- 302/307:Դ·
- 304ԴûбĹ
- 404Դ,ҲԴ
- 500д
- ӦϢͷ
- Ӧģ
- һ֮ȫӦģʾľе
- 7)ͨм̣߳
- TCP/IPЭ飺
- ʵӦУҪϵĶȡͻݺдݵͻ;ͻҲҪϵĶȡݺдݵˡ
- ʹôͳBufferedReaderreadLine()ȡʱڸ÷ʽʵ÷ɹ֮ǰ̱߳
- ִСڴˣӦΪÿSocketһ̣߳ÿ̸߳һͻ˽ͨš
- ͻӦð̣߳һ桢Ӧûûд뵽SocketӦ
- һȡSocketӦдӷ˷ݣЩʾ
- ʹNIOʵַSocketͨ(JDK 1.4Ժʼ)
- ʹNIO API÷ʹһ߳ͬʱӵ˵пͻˣ
- ʹAIO(Asynchronous IO)ʵַͨ(JDK 1.7ʼ):
- ֧ͨ첽Channelʵ
- ڶ߳Ӧã
- a̵߳ãЧ
- b̵߳Ӧã
- ߳أ
- URL
- ȡָURLָԴĴС(getConnectionLength())
- ڱشϴһԴСͬĿļRandomAccessFile.setLength()
- ÿ߳ӦԴĸ(ĸֽڿʼĸֽڽ)
- δ߳Դָ
- //ִ´ͷȷָ߳صIJ;øͷÿ̶߳ͷصĩβ
- HttpURLConnection.setRequestProperty("Range","bytes="+start+"-"+end);
- ̶߳ϵأ
- ʼʱжǷµ
- ǣͷʼ
- ǣҵϴɶ٣
- عм¼ÿ̵߳ؽȣͬʱضپдٵأÿļд֮ݿиؽ
- ֮ɾݿؼ¼
- 8)ͨеURḶ
- URL
- URL(Uniform Resource Locator)ͳһԴλָԴָ롣ԴǼļĿ¼
- ҲǸӵĶãݿIJѯ
- URLɣ
- Э˿ںԴ·ɡHttp://localhost:8080/BookShop/index.jsp
- URLӦã
- ʹURLԴ
- ʹURLConnectionύ
- ͨURL.openConnection()URLConnection
- URLConnectionIJͨ
- GETPOST
- ʹHttpURLConnectionԴ
- (3)HandlerϢݻƺAndroidµϢͻƣ
- 1)HandlerϢݻ:
- Handler
- Handlerǽˢ»
- HandlerAndroidӦö̼߳ͨ⣬̺֮߳߳ͨ
- AndroidϵͳActivity̷߳ʸActivityĽ͵̬߳ıýֵ
- ̴߳View,ȡ;߳ݣViewHandlerϢݻƾͿԽ⡣
- Handlerã
- aHandlerһ߳УHandlerþʵ첽
- bHandlerڲͬ߳УHandlerþʵ첽ʵ̼߳ͨš
- HandlerLooperĹϵ
- aHandlerҪͺʹϢǷϢϢôݵأ
- LooperˣÿHandlerڲװһLooperڴHandlerʱָLooper
- ϵͳͻĬϽǰ̵߳LooperHandlerϣ
- LooperάһϢУHander͵Ϣ洢ϢУ
- LooperϵıϢУȡϢhandleMessage
- Looperĸ̣߳hadleMessageͻǸִ߳С
- bLooperã
- Looper̵߳ϢкϢѭ
- **̵߳Looper
- ߳ʹHandlerʱָLooperΪ߳̿ʱѾLooper.loop()ʼѯˡ
- ͨHandler.getLooper()ɻȡǰ̵߳Looper
- ߳̿ͨLooper̷߳Ϣ
- **̵߳Looper
- ߳ʹHandlerʱͨLooperprepare洢LooperõLooper.loop()ѯ
- һ߳̿Դ(ȻҲԲ)һϢкһϢѭ(Looper)ض̵߳Ϣַֻܷ̣߳
- ܽп̡߳ͨѶǴĹ߳ĬûϢѭϢеģø߳̾ϢкϢѭ
- Ҫ߳ȵLooper.prepare()ϢУȻLooper.loop()Ϣѭ
- עAndroidг˽ViewڴView߳ġ
- Handlerʹã
- HandlerʹҪĸʹã
- HandlerLooperMessageThread
- HandlerAsyncTask
- aͬ㣺
- AsyncTaskHandler̺֮ͨ߳߳ͨŸ
- bͬ㣺
- HandlerȽ鷳AsyncTaskʹӷ㣬AsyncTask̿ɿ;
- ڶ̨ʱʹHandlerṹʹöAsyncTaskʱ쳣
- 2)AndroidµϢͻ:
- ϢͻƸ
- ǿͷӦʱ϶Ҫȡ˵ݣҪϢͻʵ֡
- ڻȡϲʱµϢַʽ
- һǿͻʹPull()ķʽͻÿһʱȥ˻ȡϢǷиµϢоͻȡ
- ڶǷʹPush()ķʽ˸ˣͰѸµPushͻ
- עȻPullPushʽʵֻȡ˸µݵĹܣԵPushʽPullʡû͵
- Ϣͽ
- ****ѭPull:
- ӦóԵӲѯǷϢ
- ȱݣҪѯƵʣ̫ܵijЩϢӳ٣̫죬͵
- ****SMS Push:
- ͨSMSϢҽϢ˽ͼ
- ȱݣɱԱȽϸߣҵѵĶϢ
- ****־Push:
- ȱݣֻʵһɿķҷdzֻĵ
- Ϣͷ
- ****C2DM(Cloud to Device Messaging):
- C2DMGoogleṩϢͷһġĻƣ֪ͨƶӦóֱͨ
- ԱڴӷȡӦóºûݡ
- C2DMϢŶӵĿ豸ϵӦóַЩϢ
- C2DM⣺
- C2DMAndroid2.2ϵͳϣϵ1.62.1ϵͳ
- C2DMҪGoogleٷṩC2DMڹڵ绷ãҪܺõʹã
- ǵApp ServerҲڹ⣬²ÿ߶ܹʵֵ
- ****MQTTЭʵAndroidͣ
- MQTTһϢ/Э飬ʵֻֻͻ˵Ϣͷ
- wmqtt.jar IBMṩMQTTЭʵ
- ****RSMBʵͣ
- Really Small Message Broker (RSMB) һMQTTͬIBMṩ
- ****XMPPЭʵAndroidͣ
- GoogleٷC2DMײҲDzXMPPЭеķװ
- XMPP(չͨѶͱʾЭ)ǻڿչ(XML)Э飬ڼʱϢ(IM)Լ̽⡣
- Эûϵκ˷ͼʱϢ
- androidpnһXMPPЭjavaԴAndroid push notificationʵ
- ע
- XMPPЭʵAndroid͵ƾǼDzҪC2DMϵͳ汾ҲᵣijһGoogleá
- XMPPЭǻԽһĶЭչʵָΪƵĹܡĿǰֻܷϢ
- ˵һ㹻ˣΪDzָͨ͵õе
- 3)̼߳ͨ
- ٽ̺߳Լ̵߳ĸ
- ̣ڽеijÿһִжһִ˳˳һִ·߽һƵԪ
- ̣߳ڲһִ·һƵԪ
- עߵ
- һһ߳
- ִйӵжڴ浥Ԫ̹߳һڴ浥Ԫ
- ̣߳
- һж̣߳Ϊ߳
- ڶ̵߳ƺͱˣ
- ƣ˶ಿͬʱе⣬Ч
- ˣ̫߳ᵼЧʵĽͣΪ̵ִ߳CPUл
- ʵ̵ֶ߳ķ
- ʵֶ̳߳̿ͨThreadʵRunnableӿ
- a̳Thread
- һ̳Thread
- дThreadеpublic void run()̵߳װrun
- ֱӴThread߳
- start()߳(̵߳run)
- bʵRunnableӿڣ
- һ࣬ʵRunnableӿڣ
- ǽӿڵpublic void run()ķ̵߳װrunУ
- Runnableӿڵ
- RunnablӿڵΪݸThreadĹ캯Thread
- ԭ̵߳װRunnableӿrunС
- Ҫ̶߳ʱͱȷҪе
- start()̡߳
- עַ
- (1)ʵRunnableӿڱ˵̳еľ
- (2)̳Thread̴߳Threadrun
- ʵRunnableӿ̴߳ڽӿڵrunУ
- ڶ߳ʱʹʵRunnableӿڣΪж̶߳ʹַʽʵ
- ̵߳ļ״̬
- ½newһThreadǴһ̣߳һ̶߳ûпʱ
- ֻΪ̶߳ڴռͳʼݡ
- ½ĶstartͿ̣߳߳̾͵˾״̬
- ״̶ִ̬߳ʸûCPUִȨ
- У̶߳ȡCPUԴ
- ״̶ִ̬߳ʸҲִȨ
- йе߳ijЩԭ(wait,sleep)ͷִʸִȨ
- ȻǿԻص״ֱֻ̬ӻص״̬Ȼص״̬
- ̶߳õrun()ֱӵstop()̶̶߳߳ڴб
- ݶ̰߳ȫ⣺
- aԭ:
- Ķڲ̵߳Ĺʱ(ƱеƱǹԴ)̵߳Ե
- һִ߳жʱִһֻûִ꣬һ߳ᵽcpuִȨִУ
- ʱ͵¹ݷƱдӡƱʹƱ
- b:Զݵͬһִ߳й̲߳Բ
- Javaж߳ͬ
- aͬã
- ̵ͬ߳İȫģڶ߳УͬܿƶԹݵķʡ
- ûͬһ߳һʱһ߳ʹû߸ͬһݣ³ִĽ
- bͬǰ
- 뱣֤߳
- Ƕ߳ʹͬһڲ̹߳
- 뱣ֻ֤ͬһ߳
- cͬĺôͱ
- ôͬ˶̵߳İȫ
- ˣ̶߳ҪжȽԴ
- dֱͬʽ
- ͬ:
- ָҪȡĸͬ,ʹsynchronizedĴͬҪ,
- ǵȫ⣬һ㻹ʹͬһ˵Чʽϸߡ
- ע⣺
- **Ȼͬʹκζڽж߳ͨʹͬʱ
- 뱣֤ͬĶΨһᱨ
- **ͬthisҲҪ֤ͬĶ͵waitnotifynotifyAllĶ
- ͬһҲǶthisĶ
- ʽ
- synchronized()
- {
- ͬĴ;
- }
- ͬ
- ָͬ÷ʱҪȡthisͬڷʹsynchronizedؼ֣
- ʹthisΪҲʹ˵ǰΪס˷ڴ˵ЧԽϵ͡
- ע:̬ͬǸ÷ڵֽļ.classļ
- ʽ
- δ synchronized ֵ (б)
- {
- ͬĴ;
- }
-
- ̶߳ͬѭʱͻᷢ
- ͬǶͬȴͬ
- ΪʲôҪ̼߳ͨţ
- ִ̲߳еʱ, Ҫ̵ָ߳ȴ߳, ôҪ̼߳ͨš
- ߵ⣬һһ,ʱҪѵĽ̵ȴ,һɺҪѸѵ߳,
- ͬʱԼڵȴѵʱѵ̱߳ѣIJƷֽȴ̻߳ѣ
- ȻʹԼ̴߳ڵȴͨţԴﵽһһĿ
- ̼߳ôͨ
- ͬ, ʹwait()õǰ̵߳ȴ, ֱ̻߳Ϊֹ.
- ʹnotify()Իһȴ̣߳notifyAllеȴ߳.
- ̼߳ͨsleepʵ֣˯ʱѰա
- Android̼߳ͨӦð
- aHandler
- bIntent
- ע̼ͨŰ
- 㲥ߡṩߵ
- (4)AndroidµXMLJSON
- 1)XMLĽɣ
- XMLĸ
- XMLʽ֣DOMSAXPull
- Android SDKѾPullκjarļAndroidϵͳƼʹPullXML
- PullзʽSAXƣṩ¼ж
- ΪʲôҪXML
- XMLǰXMLļǩԡıװjavabeanУXMLĹؼõXMLļԪصԺı
- ڽXMLIJ裺
- aýXmlPullParser parser = Xml.newPullParser();
- bԼ룬ָĸXMLļ
- //ȥgetClassLoader()ļǰӡ/
- InputStream in = PersonServiceTest.class.getClassLoader().getResourceAsStream("persons.xml");
- parser.setInput(in, "UTF-8");
- cͨXmlPullParserij˷XMLļ
- XmlPullParser¼ͳSTART_DOCUMENTEND_DOCUMENT START_TAG END_TAG TEXT
-
- getEventType():ȡ¼
- next()½
- getName()ȡǩ
- getAttributeValue(int index)ȡǩԣ0ʼ
- getText()ȡı
- nextText()ȡһı
- ΪʲôҪXML
- javabeanдXMLļXMLļĹؼΰjavabeanXMLļԪرǩ
- ʹXmlSerializerXMLļIJ裺
- aȡл
- XmlSerializer serializer = Xml.newSerializer();
- bлͱ룬ָɵĸXMLļ
- FileOutputStream fos = new FileOutputStream("/mnt/sdcard/persons.xml");
- serializer.setOutput(out,UTF-8);
- cͨлĸַXMLļĸԪرǩ
- startDocumentʼXMLĵ
- startTagʼǩ
- attributeñǩ
- textñǩı
- endTagǩ
- endDocumentXMLĵ
- 2)JSON
- JSONļ൱һ
- JSONļ൱ڱ洢JSONJSONArrayȡÿJSONObjectݣװjavabean
- JSONȱ㣺
- ŵ㣺
- ΪݴʽXMLƣDZXML
- JSONJavaScriptԭʽJSONҪضݵײϢ
- ȱ㣺
- Ͻ
- ɶԲ
- evalڷ
- (5)JNIã
- 1)JNI
- ʲôJNI?
- JNIJava Native InterfaceдJavaؽӿ
- JNIһЭ飬ͨJavaC/C++Э,JavaC/C++֮
- ͨJNIЭ飬JavaԵⲿC/C++еĶõĺ;ⲿC/C++ҲԵJavaзװõͷ
- 2)ΪʲôJNI
- ʵʿеCJavaͨJNIͿԵCõӶչJava
- Androidϵͳwifi-hostpotCJavaͨJNIõ
- ЧʣڸЧʵѧ㡢ϷʵʱȾƵƵıϣCдģJavaͨJNICдõĸЧʵĴ
- ۴븴ãJavaʵ2000ҲչģCʮͳˣCкܶdz÷dzĺķװ,
- Cйļѹ(7-zip Cд Чʷdz)ʶJavaҪдˣֱþͺ
- עΪʲôCдĴЧʸߣ
- CдĴ벻ҪͨJava룬ϵͳֱӾʶֱӾá
- 3)JNI:
- C/C++
- ָ룺
- ָǵַַָ
- ַ
- ڴ浥Ԫı
- ָ
- ŵַı
- ָҪ:
- aֱӷӲ
- bٴ
- cһϵֵ
- dʾӵݽṹ
- e㴦ַ
- f
- JNỊ
- aһAndroid
- bJavaһطjavahͷļ
- cڸAndroidдjniĿ¼,ͷļ,ͷļʵc룬οNDKеjni.hļ
- еĽṹJNIEnv*jobjectҪCеķ봫
- djniĿ¼ддAndroid.mkļ
- eNdkɶ̬⣬ִֻеĶļ(.soļ)
- fJavaload ̬.native:System.loadLibrary("Hello");//HelloΪjniĿ¼C/C++.cļ
- NDK(native develop kits):
- aΪʲôҪNDKߣ
- ڰУΪײ㶼CCҪײܶCЧʱjava죬javaҪCд롣
- javaֱӵCд룬ǵCĶļCװCзḻĺ
- JavaҪCĿִеĶļ辭裺
- 룺
- CԴɲִеĶļ
- öļwindowsϵͳ.objļ
- Linuxϵͳ.oļ
- ӣ
- õĶļݵǰIJϵͳϵͳӳɿִеĶļӹм˱ĺ
- öļwindowsϵͳ.exeļ
- linuxϵͳ.soļ
- b룺
- GoogleṩCдNDKߣùߵndk-buildʵڵ(windowsϵͳx86CPU)
- ֻ(linuxϵͳarmCPU)ִеĶļ˹̾ǽ̡
- NDKҪlinuxϵͳ£cygwinwindowsϵͳģlinuxϵͳһߣʰװNDK֮ǰ谲װcygwin
- (6)SQLiteMySqlݿCRUDSharedPreferencesݳ־û
- 1)SQLite:
- SQLite
- Androidƽ̨ǶһϵݿSQLiteݿⲻͬSQLite洢ʱ
- SQLiteֻԴݿ⣬ÿһݿһXMLļÿһXMLļһŻű
- ڴSQLiteݿⲽ裺
- a̳SQLiteOpenHelper
- SQLiteOpenHelperݿһߣдonCreate()ݿupGrade()ݿⷽ
- ڻȡݿʱЩԶִ,ʹֻԴSQLiteݿ봴һSQLiteOpenHelper࣬
- ʵonCreate(SQLiteDatabase), onUpgrade(SQLiteDatabase, int, int)
- ݿⲻݿ汾Dz£ݿ汾ά䱣һѵ״̬
- bȡݿSQLiteDatabase
- SQLiteOpenHelper. getWritableDatabase()ȡдݿ⣬дʱɻȡݿ
- SQLiteOpenHelper. getReadableDatabase()ȡݿ
- cִݿɾIJ
- ִɾIJؽ
- SQLiteDatabase.execSQL(String sql,Object[] params);
- ִвѯCursor
- SQLiteDatabase.rawQuery(String sql,String[] params);
- ִCRUD
- SQLiteDatabase.insert();
- SQLiteDatabase.update();
- SQLiteDatabase.delete();
- SQLiteDatabase.query();
- dرԴ(ѡÿλȡݿʱݿײԶֶر)
- SQLiteDatabase.close();
- Cursor.close();
- 2)MySql:
- MySql:
- ṹѯ,Structured Query Languageд
- JDBC飺
- aJDBCjavaݿӣJava DataBase Connectivityд
- bԱװ˲ͬݿ(MySQLOracle)Ҫװͬݿ
- javaӦóӸݿⲢԸݿݽвԿԱ˵Ǻ鷳
- ǺSUNṩһײݿĹ淶ù淶JDBC
- ͬݿ⳧ʵ˸ù淶()ԱֻҪոù淶
- cJDBC淶JDKе
- JDBC̲裺
- aע
- ʽһDriverManager.registDriver(new com.mysql.jdbc.Driver())
- עDriverڵİcom.mysql.jdbc.*java.sql.*
- ַʽʹãԭ£
- ****ݿ,DriverManagerjava.sql.*е
- Orcalݿ⣬øij
- ****ᵼݿע2ΣDriverManagerһصʱ
- עһ,new com.mysql.jdbc.Driver()עһ
- (鿴Դ)
- ʽClass.forName("com.mysql.jdbc.Driver");
- ô˷ʽηʽaзʽһֵ
- bݿӣjava.sql.ConnectionеݿĽӵĻϽв
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day12","root", "xiaruri");
- עurlĹ̶ʽдҪס"jdbc:mysql://localhost:3306/day12"
- jdbc:Э mysql:Э localhost:3306:Ͷ˿ day12:ݿ
- root:MySQLû xiaruri:û
- ʵʿѴȥַȡдļͨȡļʽ
- ȡĴȥݿʱijֻļ
- cȡSQL
- Statement stmt = conn.createStatement();
- dִSQL
- String sql = "select id,name,password,email,birthday from users";
- eнᱻװһResultSet
- ResultSet rs = stmt.executeQuery(sql);
- f
- while(rs.next()){
- //rs.getObject(1):ÿ¼1ʼJDBCʱʹ
- System.out.println(rs.getObject("id")+"\t"+rs.getObject("name")+"\t"+
- rs.getObject("password")+"\t"+rs.getObject("email")+
- "\t"+rs.getObject("birthday"));
- }
- hرʹõԴ
- rs.close();
- stmt.close();
- conn.close();
- ܿԴԴܣ
- aֱӷӲ
- bDBCP
- DBCPApache֯µĿԴӳʵ֣ʹDBCPԴӦóӦϵͳjarļ
- Commons-dbcp.jarӳصʵ
- Commons-pool.jarӳʵֵ
- O-R Mappingӳ乤
- Hibernate CMP JPA(Java Persistent API)
- Ibatis(ΪMyBatis)
- Commons DbUtils(ֻǶJDBCװ)
- Spring JDBC Template
- DbUtils飺
- QueryRunner
- MyBatis飺
- MyBatisǰiBatisһݳ־ò
- MyBatis֧ͨSQLѯ洢̺ӳ־ò
- ˼еJDBCͲֹԼļMyBatisʹüXMLעúԭʼӳ
- ӿںJavaPOJOs(Plain Old Java ObjectsͨJava)ӳݿеļ¼
- cC3P0
- 3)SharedPreferences
- SharedPreferences൱һɳ־ûMap
- ͨput洢־ûݣҪcommitЧ
- ͨgetȡ־û
- (7)ϵͳMediaPlayerڡͼƵƵý忪
- MediaPlayerղƵƵļĶͨMeidaPlayer
- עƵƵCдģMediaPlayerڲͨJNIϵͳC
- aMediaPlayerڵļ״̬
- idleһMediaPlayerոnewǵreset()idle״̬
- initializedʼ״ִ̬setDataSource()initialized״̬
- prepared״ִ̬ͬprepare()첽prepareAsync()prepared״̬
- עprepare()ʽԲƵжprepareAsync()prepareAsync()лص
- startedʼ״ִ̬start()seekTo()started״̬
- pausedͣ״ִ̬pause()paused״̬
- stoppedֹͣ״ִ̬stop()stopped״̬
- playbackComp״̬
- endrelease()end״̬
- errorſƲܻʧܣ粻ֵ֧Ƶ/ƵʽȱٸɨƵ/Ƶֱ̫ߣʱԭ
- һMediaPlayer뵽Error״̬
- MediaPlayerִʽ
- ****MediaPlayer mp = new MediaPlayer(); //ַprepare()prepareAsync()start()
- ****MediaPlayer.create(Context context,int resId); //ַϵͳneibuѾִprepare()ˣʿֱstart()
- bMediaPlayerļ¼
- setOnCompletionListener(MediaPlayer.OnCompletionListener listener) ý岥Ž
- setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) ýĻ
- setOnErrorListener(MediaPlayer.OnErrorListener listener) Ϣ
- setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener) Ƶߴ
- setScreenOnWhilePlaying(boolean screenOn) ǷʹSurfaceHolderʾ
- cMediaPlayer
- ****MediaPlayerͨServiceϲƵļ
- ****MediaPlayerͨSurfaceViewϲƵļ
- ӦõԴļ
- ӦõԭʼԴļ
- ⲿ洢ϵԴļ
- Դļ
- dMediaPlayerȱ
- Դռϸߣӳʱϳ
- ֶ֧Ƶͬʱ
- eʹSoundPoolЧ
- SoundPoolʹЧصĸ̴ٵЧSoundPoolҪڲ̴ܼٵЧ
- SoundPoolMediaPlayerȵCPUԴռͺͷӦӳ£SoundPool֧ƷʡűʵȲ
- fʹVideoViewMediaControllerƵ
- VideoViewĸ
- VideoViewʾͲƵ
- VideoViewװMediaPlayerͬʱ̳SurfaceView
- VideoViewԲƵƵļ֧ͨrmvbʽƵ
- ʹVideoViewƵIJ裺
- VideoView
- VideoViewsetVideoPath(String path)setVideoURI(Uri uri)ָƵ
- VideoViewstart()stop()pause()ƵIJ
- gʹMediaPlayerSurfaceViewƵ
- MediaRecorder
- ֻһ㶼ṩ˷ӲAndroidϵͳͿøӲ¼ƵƵ
- ۶ý峣ʶ
- aʲôǶý
- ýǼƵĽϣʵý壻ͼڵ͵
- bõƵʽ
- AndroidϵͳĬϣmp43gp
- øʽts3gpp3g23gpp2avimkvflvdivxf4vrmrmvbrvwmvasfmovmpgv8rammpeg
- swfm2vasxraramndivxxvid
- cƵʽ
- Androidϵͳmp3ogg
- øʽwmamidm4axmfaacmpamidiar
- dͼƬʽPNGGIFBMPjpg
- eandroidĶýӦã
- Ƶ
- Ƶ
-
- ͼƬ
- Ƶͨ
- MediaScannerSDcardʱϵͳɨͼƬƵƵýļ
- fMediaPlayerηװ룺
- MediaPlayerһ̬飬þ̬ɵCԱдĽ롣
- gڸƵվõĽܣ
- ſᡢѺաppsӰ56õffmpeg
- pptvѾʹp2p
- Ե㼼peer-to-peer P2PֳƶԵȻ缼һ¼вߵļʹ
- ǰۼڽٵļ̨ϡP2PͨͨAd Hocӽڵ㡣ڶ;
- ֵѾõ˹㷺ʹáP2PҲʹVoIPʵʱýҵͨС
- hŹ̳ƣ
- ʾûŴ
- ²
- ʹõ
- ʵܲŵĿܣ
-
- ȻAndroidѾVideoViewMediaPlayerֿ֧Ƶϵͳֵ֧ĸʽܵȸ涼ʮ
- ǿÿԴĿVLCffmpegVitamioԼAndroidܲ
- aVLCܣ
- VLCһԴĿffmpegܵԶ岥LibVLCVLCĺIJ֣൱MediaPlayer
- VLCһҪIJ֣ԲŸ͵ýļýļҿԴýɸָʽýļ
- VLCһֿƽ̨ý岥ýΪvideolanĿͻˣһַdzĶý岥
- ŸָƵĸʽļ(MPEG-1MPEG-2MPEG- 4DivXWMVmp3OGGVorbisAC3AACȵ)ýЭ
- ɫĹǿԱر߹ۿDivxýļԲŲȫAVIļֽ֧ĸġ
- ȱ㣺C/C++룬Java룬̫Ӵ
- bffmpegܣ
- ŵ㣺ܣά
- FFmpegһ¼ơת/Ƶ빦ΪһĿԴ
- FFMPEGΪеķعˣ롢롢úͽ⸴á
- ʹöýӦóױдһģCдģٵIJܹ
- õĸʽȻҲָʽ
- FFmpeg֧MPEGDivXMPEG4AC3DVFLV40ֱ룬֧AVIMPEGOGGMatroskaASF90ֽ
- FFmpegĿ¼ҪlibavcodeclibavformatlibavutilĿ¼libavcodecڴŸencode/decodeģ
- libavformatڴmuxer/demuxerģ飬libavutilڴڴȸģ
- cvitamioܣ
- vitamioҲǻffmpegԴ
- VPlayervitamioһƷvitamioVPlayerͬһŶӿģVPlayerܲŵvitamioҲܲ
- vitamioijɹ
- ڣVPlayerèӰ321Ӱ
- ⣺TvltalianeDizi TV
- vitamioֵ֧Э飺
- m3u8
- MMS
- RTSP (RTP, SDP)
- HTTPʽ(progressive streaming)
- HTTP Live Streaming (M3U8), Android 2.1+
- vitamioɣ
- vitamio.jar
- ARMv-7-NEON.apk
- ĸ
- ARMv-7-NEON.apk
- VFP.apk
- ARMv6.apk
- ARMv5.apk
- עvitamioֻCPUͺŰװӦĽֻװһ
- vitamioܵģΪֻϵAndroidϵͳ̸ֻĹvitamio֧еִֵֻֻ֧
- 룺
- Ӳ룺ϵͳӿʵֵIJ
- 룺ϵͳӿʵֵIJ
- עϵͳӲ롣ӲƵãϵͳIJ϶ȵIJá
- dý壺
- VLSһרĸ⣬ҲһЩVLCvideolanΪhttprtprtsp
- ý
- νýָʽķʽInternetŵýʽ
- ýֽʽý壬ָ̼һƵͷѽĿݰ͵ϡ
- ûͨѹ豸ЩݽнѹĿͻǰʾ
- ýķʽдƵƵͶýļʽ
- ýļʽֲ֧ʽ估ŵýʽ
- ʽ䷽ʽǽƵƵȶýļѹʽֳһѹ
- ɷûʵʱ͡ڲʽ䷽ʽϵͳУûʽȵļ
- ȫϺܿеݣֻҪӻʮʱû
- ӦIJѹƵƵʽýļвţʣIJֽأֱϡ
- ʵƵĸţ
- 塢ؿ졢϶졢ûй
- (8)JavaScriptAJAXͨJQueryӦ첽ݾֲˢ
- 1)JavaScript
- Aptana:
- a
- AptanaһdzǿġԴġרעJavaScriptAjaxIDE(Integrated Drive ElectronicsдӼ)
- bAptanaܣ
- JavaScriptHTMLCSSԵĴʾ
- OutLinerͼ
- ʾ
- JavaScript
- ֧еAJAXܵĴʾ
- JavaScript֪ʶ
- aWindow:
- ɣ
- documentĵ
- linksӶ
- forms
- imagesͼƬ
- frameܶ
- locationλö
- historyʷ
- DOM:
- Document Object Modeĵģ
- Node
- ڵCRUD
- 2)Ajax
- (1)ʲôAJAX
- Asynchronous JavaScript And XMLд
- ͨŶˢµǰҳļAJAX
- (2)ַʽ
- ͨB/Sģʽ(ͬ)
- ύ->ȴ->Ϸ ڼͻܸκ
- AJAX(첽)
- 첽: ͨ¼->ʱȻ飩->
- (3)ͬ첽ĸ
- ָͬͷݺȽշӦԺŷһݰͨѶʽ
- 첽ָͷݺȽշӦŷ¸ݰͨѶʽ
- (4)AJAXӦã
- GoogleͼеվڶAJAXֲˢµļ
- (5)ˢµļ
- Flash
- Java Applet
- ۿ
- صiframe
- XMLHttpRequest
- öǶJavaScriptһչʹҳͨšǴ AjaxӦõѡʵͨAjaxXMLHttpRequestĴ
- (6)AJAXԭ
- AjaxĺJavaScriptXmlHttpRequest
- öInternet Explorer 5״룬һ֧첽ļ
- ֮XmlHttpRequestʹʹJavaScriptӦû
- AJAX첽̡AJAXû֮һмý飬Ӷ罻еĴȴȴȱ㡣
- (7)AJAXļ
- AJAXһµļǶּĽϣJavascriptXHTMLCSSDOMXMLXMLHttpRequest
- (8)AJAXȱݣ
- ֧֣ĿǰIE5.0ϡMozilla1.0NetScape7ϰ汾֧AJAX
- ڶý֧ûFLASHJava Appletá
- ֻPADܺܺõ֧AJAX
- AJAXҳݵʱûˢҳ棬ˣҳĺ˹ʧЧģû㲻ҳϵǾɵĻǸ¹
- 3)JQuery
- JQueryԭ
- Ϊ˼JavaScriptĿ, һЩJavsScriptˡ
- ǰе JavaScript :
- jQuery, MooTools, Prototype, Dojo, YUI
- JQueryʲô
- ajQueryǼprototype֮һJavascriptܡּǡWRITE LESS,DO MORE,дٵĴ,顣
- bjs(ѹֻ21k)jsģCSS3ݸ(IE 6.0+,FF 1.5+,Safari 2.0+,Opera 9.0+)
- cjQueryһٵģjavaScript⣬ʹûܸشHTML documentseventsʵֶЧҷΪվṩAJAX
- djQueryܹʹûhtmlҳִhtmlݷ룬Ҳ˵htmlһjsˣֻ趨id
- ʲôJQuery
- jQuery ͨjQueryװDOMĶ
- ȻjQueryǰװDOMģjQueryʹDOMκηͬDOMҲʹjQueryķ.ʹûᱨ
- (9)AsyncTaskAsyncQueryHandler
- 1)AsyncTask:
- AsyncTask
- AsyncTaskAndroid 1.5ṩһ첽ߣһװõĺ̨ࡣ
- AsyncTaskʹԭ
- aAsyncTaskʵ߳д
- bexecuteִ߳
- cҪֶĵonPreExecutedoInBackgroundonPostExecuteonProgressUpdate
- dεý쳣
- AsyncTaskHandlerͬ㣺
- aͬ㣺
- AsyncTaskHandler̺֮ͨ߳߳ͨŸ
- bͬ㣺
- HandlerȽ鷳AsyncTaskʹӷ㣬AsyncTask̿ɿء
- ڶ̨ʱʹHandlerṹʹöAsyncTaskʱ쳣
- 2)AsyncQueryHandler
- AsyncQueryHandler
- aAsyncQueryHandler̳Handler
- AsyncQueryHandlerã
- ContentProviderṩݽɾIJ顣
- AsyncQueryHandlerĹƣ
- עAsyncQueryHandlerڲҪHandlerLooperMessageHandlerThreadWorkerHandlerWorkerArgsʹ첽
- aAsyncQueryHandlerʱϵͳAsyncQueryHandler췽AsyncQueryHandler췽
- ϵͳ²
- һHandlerThreadͬʱʼLooperHandler
- bAsyncQueryHandlerstartQuerystartInsertstartUpdatestartDeleteʱ
- ͻִӦɾIJ鷽AsyncQueryHandlerɾIJ鷽ͨHandlerʼMessage
- ȻٳʼһWorkerArgsϢװWorkerArgsУ
- ͨHandlersengMessage첽Ϣͳȥ
- cWorkerHandlerյϢhandleMessageڸ÷첽IJͽжϣȻִ֮ӦĴ
- dصָ첽ִɵĻصûصϵͳǿʵ֣ҪûԼԼҵȥд
- AsyncQueryHandlerʹע
- ʱANR쳣ҪŻ
- (10)aidl
- 1)ʲôaidl
- aidlAndroidӿڶԣAndroid Interface Definition LanguageдGoogleṩһ淶
- 2)aidlã
- (Ȳֿʽٿʼش)
- ߺͷͬһӦãʱͨԶ̰÷ķͱͨaidl
- 3)ʹaidlIJ裺
- ڷж÷
- DzȥnewһҲͲõһãòãҲͲͨ÷еķ
- ôͨʲôʽܵ÷ķأǿͨһмʵֵ÷ķм˾ǽӿڡ
- ͨaidlɽӦеĽӿں͵ӦеĽӿڱͬһӿ
- ͺñҪ͵ͨľ
- ڶһӿڣڽӿ
- ͨķķ÷onBindִonBind᷵һIBinderӿڶ
- BinderIBinderӿڵʵ࣬ǿԶһڲMyBinder̳BinderͬʱʵֲжõĽӿڣʵֽӿδʵֵķ
- ʱMyBinder൱һмˣͨм˵ķǾͿԼӵĵ÷еķ
- ܽӦõıĿ¼еĽӿļΪaidlͬʱӿеȨηȥ(ʱӢgenĿ¼Ӧ.javaļ)
- ÷ӦõıĿ¼ӿļĺΪaidlͬʱӿеȨηȥ(ʱӢgenĿ¼Ӧ.javaļ)
- ͱ֤ӦͬͬĽӿͬһӿڣͨм˽ӿԶ̵÷ķ
- ݽԶڲMyBinderΪ̳Stub
- Զ̰÷ĴServiceConnectiononServiceConnectedصIBinderӿڣ
- ͨStub.asInterface(IBinder)ǿתԶм˽ӿ(ֻǿתΪͷԶĽӿͲܵ÷еķ)
- (11)WebServiceü
- WebServiceüã
- ṩķ
- ʹWebService:
- a½http://www.webxml.com.cnվȷҪʵWebService鿴ṩʹAPI
- ȡWebService跢XMLļͽյXMLļ˽ʹ˵
- bϷ˷ָҪָʽXMLļ
- cϷ˷صXMLļ
- WebServiceǷϵAPIͨXMLãWebServiceؽҲXML
- WebServiceûƣֻҪԷXMLݺͽXMLݼ
- (12)ģʽ㷨
- (1)ģʽ
- עʲôģʽ
- ij֮Чķһ˼룬ǹɵܽ
- 1)ģʽ
- ٸ
- ֤һڴֻΨһһ
- ʵֵģʽIJ裺
- a캯˽л캯˽лɱ
- bڱдһ˽еĸ
- cṩһʷʽΪ˷ʵ
- ۵ģʽַʽ
- aʽ
- һؾʹ
- class Student
- {
- private Student(){}
-
- private static final Student s = new Student();
-
- public static Student getInstance()
- {
- return s;
- }
- }
- bʽ
- ʹʱŴö
- class Student
- {
- private Student(){}
-
- private static final Student s = null;
-
- public static Student getInstance()
- {
- if(s==null)
- {
- //߳1ͽˣ߳2ͽˡ
- s = new Student();
- }
- return s;
- }
- }
- cʽͱʽ
- ****ʽһؽڴʹ˶ʽؽڴʱûдڣҪʹøöʱnew
- ****ʽӳټأ߳ͬʱʽʱп̰ܳ߳ȫ
- Ϊʽ̰߳ȫ⣬̰߳ȫԼͬ
- Ǽ֮ͬÿһζҪȽЧʾͱˣͨ˫ж߳Чʡ
- עöʽΪʽȫʽ̵߳ʱ
- ܵģʽӦã
- Ҫ֤ijڴҽһʵʱõģʽjavaRuntimeࡢClassDzõĵģʽ
- 2)ģʽ
- úͺô
- ã
- ṩĽӿ
- ô
- aشϸ
- bҪ¶ʱֱļľУ
- ڹģʽķࣺ
- aģʽ
- ڲϵвƷ
- bģʽ
- Թ
- cģʽ
- ֳΪ䣬Ʒ壬ڲµIJƷ
- ۹ģʽӦã
- XMLļļֽDOMSAXPULLڴʱõĹģʽ
- ȱ㣺
- ȱǵƷʱҲҪӦġ
- 3)ģģʽ
- ٸ
- һ㷨ĹǼܣһЩִнȥɡ
- ڶ幦ʱܵһȷģһDzȷģȷIJʹòȷIJ֣
- ɽȷIJֱ¶ȥɸȥɡ
- ģģʽӦã
- aServletõģģʽ
- bAndroidеBaseActivityÿActivityҪִfindviewsetview¼ʹ¼Ȳ
- ǿԽЩͬIJȡγһģ塣
- cģģʽһЩԴӦúܶ
- 4)ģʽ
- ٶ壺
- ΪṩһִԿƶķ
- ڴģʽӦó
- aȨ
- bֱӷʶֱн
- ۴ģʽã
- Ҫ裬æֻˣȻᳪ裬ͨм˿Ե衣
- 5)ģʽ
- ٶ壺
- ģʽװ㷨ġ
- ģʽ㷨壬ֱװ֮Ի滻ģʽ㷨ı仯Ӱ쵽ʹ㷨Ŀͻ
- ڸ
- ģʽΪͻฺֿάֺͲѯΪ࣬㷨ھIJṩ
- 㷨ͻ㷨ĶӰ쵽Ϳͻˡ
- ۲ģʽӦó
- ģʽװ㷨ġ
- ֻҪڲͬʱӦòͬҵͿԿòģʽֱ仯Ŀԡ
- 6)װģʽ
- ٸ
- װģʽԶԿͻķʽչĹܣǼ̳йϵһṩȼ̳иԡ
- ̬һӹܣЩܿٶ̬ijһЩܵ϶ķdzĹܡ
- 7)ģʽ
- ٸ
- һĽӿתɿͻϣһӿڡģʽʹԭڽӿڲݶһЩһ
- Ӧó
- ͬƣǾвͬĽӿʱͿԿģʽ
- 8)۲ģʽ
- ٸ
- ۲ģʽһһԶϵö۲߶ͬʱij
- ״̬仯ʱ֪ͨеĹ۲ߣʹܹԼԼ
- Ըݲһʵʵͻˡ
- ڸ:
- ν֪֪˰ս
- 9)ģʽ
- ٸ
- ⲿһϵͳͨűͨһͳһСģʽṩһ߲εĽӿڣʹϵͳʹá
- ÿһϵͳֻһ࣬ҴֻһʵҲ˵һģʽϵͳжࡣ
- 10)ԭ
- ٵһְԭ
- a
- Ӧҽһԭı
- SRPSingle Responsibility Principleд
- bһְĺô
- ĸԽ
- ɶԸ
- ά
- Σս
- 滻ԭ
- a
- ûĵطʹĶ
- ͨĽֻҪֵܳĵطͿԳ֣ҵκεĴ쳣
- ǷͲˣֵĵطδؾӦ
- b滻ԭ˼
- ȫʵָķ
- Լĸ
- ǻʵָķʱԱŴ
- ǻʵָķʱԱС
- ԭ
- a
- Dependence Inversion Principle
- ÿ˵ƵıǣԱдҪдʱǵĶԳ̶ϸڱ
- еϵֹڳ߽ӿڣǾƣ֮ǹ̻ˡ
- ܽӿڸԭ(Interface Segregation Principle)
- a
- һֶ壺
- ͻ˲ӦõĽӿ
- ڶֶ壺
- ϵӦýСĽӿ
- ͨĽǽӿھϸͬʱӿеķ١
- bӿڸIJ˼
- ӿҪС
- ӿҪھۣ
- ھ۾߽ӿڡࡢģĴٶĽ
- Ʒ
- ӿȵ
- һӿֻһģҵ
- ݵط(Low Of Demeter)
- a
- Ҳ֪ʶԭ
- ͨĽһԼҪϻߵõӦ֪٣ڲôӡôľ嶼ûϵ
- ڲ飬Ҿ֪ṩôpublicҾ͵
- bطIJ˼
- ֻѽ
- ڳԱе౻ΪԱ
- ѼҲоģ
- طҪ"С"һ㣬Ҫ̫publicͷǾ̬public
- ʹprivate,package-privateprotectedȷȨ
- ԼľԼ:
- һڱУϵҲԱӰ죬ͷڱ
- ʹSerializable
- ԭ(Open Close Principle)
- a
- ʵӦöչţĹرգ京˵һʵӦͨչʵֱ仯ͨеĴʵֱ仯
- ʵ壺
- ĿƷаһֵģ
- ӿڻ
-
- bΪʲôҪÿԭ
- ԭԭ
- ԭdzҪ
- ԭԲԵӰ
- ԭ߸
- ԭ߿ά
- Ҫ
- cʹÿԭ
- Լ
- ģΪ
- ƶĿ³
- װ仯
- (13)html5PhoneGAPܣ
-
-
-
- (14)ص
- ٻصĸ:
- صЩԼдģDzԼãҪʱõĺϢӦ
- ɶʱöķΪȥҪٵá
- (15)UMLԣ
- UMLã
- ˲ͬģ֮IJ
- ṩһͻ ܹơʵֺά֮乲ͬ
- Ŀʵɹ;
- UMLࣺ
- ̬ͼ
- ͼ(֮Ĺϵʵֺ(ַΪۺϺ))
- ͼ
- ͼ
- Ϊͼ
- ͼ
- ״̬ͼ
- ͼ
- ͼ(֮Ĺϵչ)
- ͼ
- ˳ͼ
- Эͼ
- ʵͼ
- ͼ
- ͼ
- UMLĽģߣ
- Rose:
- Visio:
- Power Designer:
- OOԭ
- ԭ
- ϴԭ
- ԭ
- ӿڷԭ
- (16)
- 1)
- ̶Եģǿǹܣǿǽܷװǿ߱ܵĶ
- 2)˼صô
- A:Ƿ˼ϰߵһ˼룻
- B:ӵˣ
- C:Աִָ߱ߣ
- ע
- ҪﵽijֽҪijܣҾѰܰҴﵽýĹܵĶö߱˸ù
- ôõöҲͿʹøöĹܡҪϴ·Ҿϴ»ôϴҲܡ
- 3)
- װضԺʵϸڣṩʷʽ
- ̳: дͬԺΪʱЩݳȡһУôٶ
- ЩԺΪֻҪ̳Ǹ༴ɡ
- ̬: һڳͬʱ̴Ķ״̬߽ӿڵָ
- 4)ƵҪ飺
- ˭ӵݣ˭ͶṩЩݵķ
- 磺
- ںڰϻԲ
- ԲҪ֪ԲĵλúԲİ뾶ԲĵλúԲİ뾶ֻԲԼԻԲķԲķ
- г˾ɲ
- ɲķ˾ĻdzأͬɲĶôɲֻгģֻǷɲźŸɲķdz
- ⣺
- ʯͷĥһʯʯԽľģľĿӣ
- ʯͷĥʯĸķأʯͷڲķĻôʯͷĥʯʯͷԼûˣ
- ʯͷĥʯʯͷڲķʯͷʯӦһʯͷӹķʯͷĥʯ
- ʯľģʯӦһľĵķ
- ľĿӣӦһľļӹüӹһľȻӹӵķ
- һӵһƶһˣ
- Ӧƶһķ
- Ӧṩ¸ĸķ֪ͨСƶķ
- (18)AndroidĴ
- 1)
- 2)Service
- ٷֿʽ
- astartService
- ص㣺
- һͻں̨
- Ŀ߸ûʲôϵ
- bbindService
- ص㣺
- ߹ˣҲŹҡͬͬ
- עͨbindServiceķһҪunbindServicedestroyᱨ쳣
- 3)
- 4)
- (19)Ż
- 1)Żԭ:
- ʱ任ʱ䣺
- õԵһЩͨЩûҪʱӶʡʱ
- վݵķȡAJAX
- ʱ任ռ䣺
- 翽ļʱnewһֽ鵱byte[] buffer = new byte[1024]
- Ϊʲôֻnewһ1024ֽڵأnewһֽ鲻һ¾ͰļôôΪʱʡڴռ
- ۿռ任ʱ䣺
- WindowsϵͳԴļĹļʱӲ̿ռ䰲װһeverythingļر
- ܿؼռ䣺
- ڴ
- (20)ֻλͼ
- 1)Androidֻλַʽ
- ٻվλ
- ֻĻվֻͨźŵǿλֻ
- ֶλʽľȷȸֻվԶԼֻվ̶ܼйϵ
- Ϊ20-2000ײȡ
- wifiλ(Ҳ綨λ)
- ֻʱᶯ̬ȡһipַӪ̻ipʵλһһһӦϵͨipַҲԶλֻ
- Google˾Ĺȸݺᡣ
- ΪֻȡipӪ̸ֻλö̬ipַʽֻλľȷȱȽϲȷΪ200+
- GPSλ
- ֻԴһȽϱ˵ķרҵA-GPSģ飬ͨѵĹⲨķʽǽͨš
- ΪͨⲨķʽԾҪͷտ
- ϱȽרҵGPS豸źһЩŴ棬ֻλҲͱȽϲƺ;ȷ
- ȷȸGPSģľйأͨΪ2-10ס
- 2)Google Map
- ٻȡGoogle Map APIKey
- ΪӦóеGoogle MapȻȡGoogle Map APIKey
- ڰװGoogle Map API
- Android SDKĬϲ֧Google MapΪ˵õ֧Google MapSDKΪAndroid SDKӦIJAVD
- ۴֧Google Map API豸
- ΪAndroid SDKװGoogle Map APIҪһ֧Google Map API豸
- Google Map API
- aMapView
- ΪAndroidƽ̨ϵGoogle MapGoogle MapṩһMapView
- MapView÷ͨImageViewһֱڽ沼ļжȻڳпƸɡ
- bMapController
- ͨMapView.getController()ɻȡMapController
- MapControllerɶMapViewпƣƵͼλָλûߵͼŴС
- cOverlay
- ͨMapView.getOverlay()ɻȡOverlay
- OverlayǸGoogle MapϵĸͼƬӦÿԿGoogle MapOverlay
- dGeoPoint
- GeoPointʾGoogle Mapϵָ
- GeoPointǶԾȺγȵķװ
- ʹGoogle Map APIλIJ裺
- aȡMapViewӦMapController
- bݾȡγֵGeoPoint
- cMapViewؼMapControlleranimateTo(GeoPoint point)λָλ
- ע⣺
- ڲļMapViewҪͨ.ķʽ
- ڲļжMapViewҪandroid:apiKeyֵΪ뵽Key
- GPS
- GPSGoogle MapʹãԷdzĿGPSӦ
- aͨContext.getSystemService(Context.LOCATION_SERVICE)ȡLocationManager
- bͨLocationManagerÿһʱȡGPSλϢ
- cLocationManagerÿһʱȡGPSλϢͨMapViewͼλָλ
- ߸ݵַλ
- Google MapͨȺγжλͨûܼסijλõľȺγȣ
- Զͨû˵ݵַλмֵĵͼӦ
- ΪˣҪ
- aַ
- ַַתΪγ
- bַ
- ѾγתΪַַ
- AndroidΪַṩGeocoder࣬ùṩеַͷַ
- aList getFromLocation(double latitude, double longtitude, int maxResults)
- ִеַѾγֵתΪַַ
- bList getFromLocationName(String locationName, int maxResults)
- ִзַַַתΪγֵ
- 3)ϵͳ
- ھGPSȡľȺγȶǣǹҲбǣûá
- ͨǻȡľγǹʱľγ;
- ʱľγйͼʾλDzȷ;
- ΪùʱľγйͼϻȡȷλãҪѹʱľγתйĻ
- ܻȡȷλ
- (21)JDK1.5ԣ
- (22)ƣ
- 1)ֻ˵ͨ
- WLAN(wi-fi) ߾
- Wi-fi߾õһwi-fiipһݰUDP
- ǷΧ100
- ֻAPN(Access Point Name)
- aվ
- ǷΧ1-1.5
- bWapʽ
- ûеģַʽйеģеԡ
- WapipͶ˿ڣ
- ip10.0.0.172
- ˿ڣ80
- WapͨŻƣ
- ֻ˵ԴȾWapWapٽתԴ
- Wapã
- мṩֵҵ
- cNetʽ
- NetͨŻƣ
- ֻԴֱӵ·Դ·Ҫͨκмӿ
- 2)ֻ˺ͷͨŵķʽ
- Socket
- 磺㶹(USBWIFI)칤ߵ
- USBӣ
- ֻͨUSBPCʱȡֻ豸PIDVIDϢȻֻ
- ûװԶ㰲װѰװٰװ
- װֻͨSocketָһ˿ڶȡֻϢ
- wi-fiӣ
- PCӦûеipͨUDPһݰ
- ʵʱϸʱҲõSocketͨţ
- ͨSocketдһӣÿһʱݰ
- ݰΪʱͨΪ30
- ƱסĽӦõȶʵʱ
- HttpUrlConnectioon
- Ϊһ
- HttpClient
- HttpClientһԴ
- ã
- ͷн(Wap)ʱĵ
- 籱Ϻ(Wap)вģͨWapͨţڱӦãõϺȥû
- 10磬ܲųɹ34Ρ
- 3)дֻӹ֮ǰ
- жֻǰͣ
- жWiFi뻹APN
- APNҪرҪAPNϢ(ȡֻǰڻ״̬APNipͶ˿)
- (23)ԣ
- monkeyԣ
- AndroidԴIJԹ
- testing
- ṩܶԹ
- ۰ٶȲģ
- (24)ڲͬĻֻϵ䣻
- 1)Ļԭ
- ٿʱλdipdpλ
- ڶ岼ʱԲֻԲֻ֡
- ۵ĻСݹʱScrollViewؼļа
- ܵ9ͼƬ
- AndroidManifest.xmlļԪԪ
-
-
- (25)MVCģʽ
- (26)Ź
- A.̳BroadcastReceiver
- B.嵥
- nameֵΪ:android.provider.Telephony.SMS_RECEIVED
- Ȩpermission-->android.permission.RECEIVE_SMS
- C.onReceive(context,intent)лȡ
- Bundle bundle = intent.getExtras();
- /*
- * Set set = bundle.keySet(); for(String str : set)
- * System.out.println(str); õbundleеֶ--->pdus
- */
- Object[] objs = (Object[]) bundle.get("pdus");//һObject[]
- for (Object obj : objs) {
- //ÿһobjһbyte[]
- SmsMessage sms = SmsMessage.createFromPdu((byte[]) obj);
- ":"+sms.getMessageBody()
- ":"+sms.getOriginatingAddress()
- "ĺ:"+sms.getServiceCenterAddress()
- Date date = new Date(sms.getTimestampMillis());
- "ʱ:"+new SimpleDateFormat("yyyyMMdd HHʱmmss").format(date)
- }
- D.ݲͬ,Žй,δܸ,Ϣװݺ鷳,ֻabortBroadcast();
-1ԶؼĿ
- (1)SplashActivity:
- 1)Splashã
- ʵʿSplashһչֲƷlogoƷ֪
- SplashĵڶǿԸݲͬںʱ䣬չֲͬĽ棬˽ڰ桢ȣû
- (˳һûڳñȽϻһκһվκһ˵Ҫû飬
- СĹ˾UIʦĹ˾UEʦ)
- SplashĵǿɳijʼݿijʼļõĿͶȡȲ
- SplashԽм硢·SDCardǷԼ־Ȳ
- 2)
- ոSplashĻ˶͵ʱĶ֡
- ڽһصʱöҪע˴ͨؼ.startAnimationķʽΪʱ֡ͼƬԴûɣ
- ͨؼ.postķʽһ̣߳߳ͨ.startķ
- (2)HomeActivity
- 1)
- (android:ellipsize="marquee")
- aЧӦó
- ڿռȽҪչʾϢȽ϶ʱͿԿDzЧչʾ
- bЧʵ֣
- ͨԶؼ̳TextViewʵֵЧ
- ʵЧǰǸÿؼȡ㣬ĬеTextViewǻȡ
- Ҫڼ̳TextViewԶؼдisFocusedҷtrueĿռͿԻȡ㣬
- ҲͿڽһصʱʵЧ
- ڽ沼֣
- HomeؼչʾͨGridViewʵ֡ǿʾõһؼListViewʵGridViewListView
- ̳ͬһAbsListViewǵ÷࣬ͨÿؼʵݵʾ
- ۵ײ˵
- ײ˵ǰǵڵſֻ˵ʵЧҾֲ˵ȽţԾԼʵ
- ʵҲȽϼͨԲֵķʽʵ֣ҪǶʵֺ͵¼Ĵ
- һת¼һЩжϺͿռʾؿ
- ܵGridViewѡĶ
- ͨoverridePendingTransitionʵֽлʱĶЧ
- ĶŶ(Scale)ijѡʱɵĽСѡλãµĽٴӸѡλ÷ŴĻС
- (3)ImageView
- 1)Ŀ֪ʶ
- ImageViewģҪչʾͼƬһЩؼ
- ViewPager
- aViewPager
- ͨViewPagerʵֵġ
- ViewPagerһǩandroid_support-v4.jarУʹõʱҪͨ.ķʽ롣
- ͨViewPagerPagerAdapterдPagerAdapterinstantiateItemʵҪʵͼƬdestroyItemȥͼƬ
- ViewPagerؼGalleryһһλͼƬViewPagerһֻܻһͼƬΪʲôViewPagerֻܻһͼƬأ
- ΪViewPagerʾʱֻͼƬǰʾͼƬǰʾͼƬǰһͼƬͺһͼƬ
- bʵViewPagerͼƬԶ
- ÿ2ӣViewPagerؼͼƬԶлһͼƬлһͼƬʱлصһͼƬ
- ͨʱTimerִ̳߳ScheduledExecutorServiceʵViewPgerؼͼƬԶл
- ǣTimerһЩbugTimerԵȵ֧ǻھʱ䣬ʱģɴϵͳʱӵĸıе;
- ScheduledThreadExecutorֻ֧ʱ䡣Timerʱÿִһ
- ȥĵǰϵͳʱӣʱͻԵǰִеӰ졣
- ScheduledExecutorServiceĵĻϵͳʱûӰġ
- JDK1.5ԺTimerˣжScheduledExecutorService
- cʵViewPagerֺ͵ͼƬĻ仯
- ViePagerؼͼƬԶлֶлʱеϢ͵״̬֮ı䡣
- ͨViewPagerͼƬı¼ʵ֡
- OnPageChangeListenerViewPagerʾͼƬıʱonPageSelectedǿڸ÷ʵ֡
- ʵֹҪһ¼һViewPagerʾͼƬλposition
- ScrollView
- aScrollViewĸ
- ĵѡRadioGroupʵֵġصʱҪʾͼƬ̬ĴӦĿRadioButton
- ͼƬʾʱͨԶؼ̳ViewGroupʵֵġ
- ͨдViewGrouponLayoutviewViewGroupеIJʾ
- onLayoutʵViewGroupViewС
- Ҫ֪ViewGroupViewʱϵͳԶô˷
- дViewGrouponTouchEvent()¼ʶGestureDetector
- ʶʶĸƣ¡ٻȡ
- ͨдGestureDetectoronScroll()ʵֻдonFling()ʵֿٻʱлͼƬ
- ɿָʱжϵǰͼƬĻе㣬ͨView.scrollBy(dx, dy)
- Scroller.startScroll(startX, startY, dx, dy)ͼƬƶĻʾ
- invalidate()½
- ٻɿָʱжϻٶȺͼٶȷٽǰʾͼƬлһͼƬ
- invalidate()½
- ڼ̳ViewGroupԶؼṩһViewGroupʾͼƬĸı䡣
- ʵͼƬıʱRadioGroupӦRadioButton״̬ѡС
- Gallery
- aGallery
- ͼƬĻ+ӰЧʵˣҪAPIȽ϶࣬ҪCameraתTransformation;Matrix
- ʵͼƬıʾҪBitmapCanvasPaintAPIʵֵӰͼƬɡ
- ҪҲһ㡣
- ҪʾͼƬĻã
- Զؼ̳Gallery
- ڸü̳GalleryԶؼидgetChildStaticTransformation÷GalleryеͼƬʾ״̬ıʱã
- ڸ÷ǿԸͼƬʾλüͼƬGaleryʾתλã
- ͬʱü̳GalleryԶؼӦûһͼƬGalleryʾͼƬĵλòͬGallery
- ͼƬʾĴСǶȡȵϢķ
- ˣҪʾͼƬ
- Զ̳BaseAdapter
- ü̳BaseAdapterԶؼṩһɵӰͼƬķ
- ڸӰͼƬķУԴͼƬ͵ӰͼƬļЧЧȥͼƬݵȲ
- Ⱥ͵ӰͼƬúԶOK
- WaterFall
- aͼƬٲ
- ͼƬٲҪͼƬԴҲԶؼʮԭ֮һ
- ЩͼƬԴΪȽϴԴʲassetsĿ¼µġΪʲôҪʲĿ¼¶ǴresĿ¼أ
- ΪresµĿ¼µԴᱻԸ룬ԴãԴļȽϴʱͱȽ鷳
- assetsĿ¼µԴԭⲻĿ.apkļС
- (3)Dialog
- 1)Dialog
- DialogҲһӦ÷dz㷺ĿؼеӦöõؼ
- AndroidУ֪ͨûķʽ֣һ˾֪ͨһ״̬֪ͨһ־õĶԻ֪ͨ
- Իַ֪ͨΪѡԻѡԻбԻȶԻȡ
- ַͨAlertDialogڲBuilderʵֵģȽϼֻҪѡַһЩ͵ַռʾء
- û¼ģµQQ½ʵֵġͨұߵͼ굯ΪһListViewPopupWindow
- PopupWindowôҪΪDialogԵʣΪDialog棬PopupWindowĸ߶Ⱦͱˡ
- ѵ½ŪһActivityˣΪʾһ£ʵʿвŪôôôPopupWindow
- (4)ProgressBar
- 1)ProgressBar
- Զˮƽ
- ΪϵͳĬϵĽͦѿģĽԶϵͳˮƽ
- ͨ鿴Android SDKԴĿ¼resµvaluesļеstyles.xmlļļAndroidϵͳеĿؼԤʽ
- ڸļҵˮƽʽĶ壬Ų鿴ϵͳprogress_horizontal.xmlļ
- ֱӿprogress_horizontal.xmlģͿʵԶˮƽʽˡ
- ڲļɨ趯
- ɨ趯һתٵģЧԭҪɶЧģ
- ΪĬϵIJȿ
- ȥʵٵЧҲȽףǿˮƽûɨһĿתʮȻʮʵٵЧ
- ڲļɨ裺
- ڲɨ裬ʵҲȽϼ
- ɱԭ
- ɱԭDZȶļ롣
- νɱʵһļΪʲôļأΪһӦóҲһļ
- ʲôDzأҪôȥˣνˮܸۣһ
- һںõķ棬һڻķ棬һ
- νɨ裬ǸļȥȶԲݿ⡣
- 2)SeekBar
- ʾͿĿؼͨԶؼ̳ViewʵֵġҲֱSeekBarʵֱ֣SeekBarʵ
- ü̳ViewԶؼͨдViewonDrawԼͨͼƬһűʾɫĿһűʾĻɫĿ
- onDrawݵǰֱʾɫֺͲʾĻɫֻ
- ü̳ViewԶؼṩһӿںıʵıʱıؼĽ
- (5)ListView
- 1)ListView
- ListViewʾݡ˵ǿУӦõݴֶͨListViewʾ
- 罻ӦúѵʾӦϢʾýӦöýļʾͨListViewʾ
- ʾ
- ListView?
- ҪListViewһAdapterҪʾݽAdapterȥ
- ListViewgetViewÿһʾһĿһɵĿƳΪŻListView
- getView()þĿconvertView
- ListViewgetViewÿִһfindViewByIdʱӦֵ״ṹٱ״ṹҵָid
- òֵ״ṹܸʱÿζidȽ鷳ΪŻǿṩһViewHolder࣬
- ¼епؼеĿؼidֻһΣʱֱViewHolderȡ
- ListViewʾʱҪзػҳʾ
- 2)ˢ:
- ˢ¿ؼͨԶؼ̳ListViewʵֵģͨListView.addHeaderViewͷˢµӵListView
- ļʱͨ.ķʽԶؼ
- ͷˢˢ¼ͷָˢϢĸͨ¼ʵ֣
- ListViewʾĵһĿλΪ0ָĻY᷽ƶʱˢ״̬ˢ״̬
- ָĻƶYλƴˢһʱˢ״̬ˢ±Ϊɿˢ״̬
- ɿָʱˢ״̬ɿˢ±ˢ
- ˢɺˢ״̬ͱĬϵ״̬
- 3)ҳ
-
-2ܶŷ
- (1)Ŀ
- ܶŷĿйƶĿڶƻһϵͳĿ
- Ҫ¸ϵͳһװҪװйƶһЩϢԺܶ涼Ҫ
- ֻϵͳAndroidԭϵͳPhone2.5汾ԺڶŵһӦáѶϵͳ½˷װ
- (2)ģ飺
- 1)Ựбʾ
- ʹAndroidṩ첽ѯAsyncQueryHandlerѯֻţ鿴ϵͳԴTelephonyProvider
- 2)ļ
- ԶŽзΪռ䡢䡢ѷͺͲݸ䣬ҶԶŽڷָʾ
- 3)Ⱥ飺
- ṩûݶԶ
- 4)
- 5)
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/\351\235\242\350\257\225\351\242\230\346\211\223\345\215\260.doc" "b/Android\345\237\272\347\241\200/\351\235\242\350\257\225\351\242\230\346\211\223\345\215\260.doc"
deleted file mode 100644
index e54aee1c..00000000
Binary files "a/Android\345\237\272\347\241\200/\351\235\242\350\257\225\351\242\230\346\211\223\345\215\260.doc" and /dev/null differ
diff --git "a/Android\345\212\240\345\274\272/Android\345\272\224\347\224\250\345\217\221\345\270\203.md" "b/AppPublish/Android\345\272\224\347\224\250\345\217\221\345\270\203.md"
similarity index 100%
rename from "Android\345\212\240\345\274\272/Android\345\272\224\347\224\250\345\217\221\345\270\203.md"
rename to "AppPublish/Android\345\272\224\347\224\250\345\217\221\345\270\203.md"
diff --git "a/AppPublish/Zipalign\344\274\230\345\214\226.md" "b/AppPublish/Zipalign\344\274\230\345\214\226.md"
new file mode 100644
index 00000000..c69dedfa
--- /dev/null
+++ "b/AppPublish/Zipalign\344\274\230\345\214\226.md"
@@ -0,0 +1,49 @@
+Zipalign优化
+===
+
+`Zipalign`优化工具是`SDK`中自带的优化工具,在`android-sdk-windows\build-tools\23.0.1`,在我们上传`Google Pay`的时候都会遇到您上传的`Apk`没有经过`Zipalign`处理
+的失败提示,就是说如果你的`apk`没有使用`zipalign`优化,那`google play`是拒绝给你上架的,从这里能看出`zipalign`优化是多么滴重要。
+
+```
+zipalign is an archive alignment tool that provides important optimization to Android application (.apk) files.
+The purpose is to ensure that all uncompressed data starts with a particular alignment relative to the start of the file.
+Specifically, it causes all uncompressed data within the .apk, such as images or raw files, to be aligned on 4-byte boundaries.
+This allows all portions to be accessed directly with mmap() even if they contain binary data with alignment restrictions.
+The benefit is a reduction in the amount of RAM consumed when running the application.
+```
+
+```
+Caution: zipalign must only be performed after the .apk file has been signed with your private key.
+If you perform zipalign before signing, then the signing procedure will undo the alignment.
+Also, do not make alterations to the aligned package.
+Alterations to the archive, such as renaming or deleting entries,
+will potentially disrupt the alignment of the modified entry and all later entries.
+And any files added to an "aligned" archive will not be aligned.
+```
+
+大意就是它提供了一个灰常重要滴功能来确保所有未压缩的数据都从文件的开始位置以指定的4字节对齐方式排列,例如图片或者
+`raw`文件。当然好处也是大大的,就是能够减少内存的资源消耗。最后他还特意提醒了你一下就是一定在对`apk`签完名之后再用`zipalign`
+优化,如果你在之前用,那无效。
+
+废多看用法:
+
+- 首先我要检查下我的`apk`到底用没用过`zipalign`优化呢?
+ `zipalign -c -v 4 test.apk`
+ 这个4是神马呢?就是4个字节的队列方式
+ 命令一顿执行,然后打出来了`Verification failed`,我不想再解释了。
+
+- 如何使用?
+ `zipalign -f -v 4 test.apk zip.apk`
+ 就是把当前的`test.apk`使用`zipalign`优化,优化完成后的是`zip.apk`
+
+Flag:
+
+- -f : overwrite existing outfile.zip
+- -v : verbose output
+- -c : confirm the alignment of the given file
+
+
+---
+
+- 邮箱 :charon.chui@gmail.com
+- Good Luck!
diff --git "a/AppPublish/\344\275\277\347\224\250Jenkins\345\256\236\347\216\260\350\207\252\345\212\250\345\214\226\346\211\223\345\214\205.md" "b/AppPublish/\344\275\277\347\224\250Jenkins\345\256\236\347\216\260\350\207\252\345\212\250\345\214\226\346\211\223\345\214\205.md"
new file mode 100644
index 00000000..437ac037
--- /dev/null
+++ "b/AppPublish/\344\275\277\347\224\250Jenkins\345\256\236\347\216\260\350\207\252\345\212\250\345\214\226\346\211\223\345\214\205.md"
@@ -0,0 +1,135 @@
+使用Jenkins实现自动化打包
+===
+
+[Jenkins](https://jenkins.io/)个开源的持续集成工具,不仅可以用来进行`Android`打包,也可以用来进行`iOS`打包、`NodeJs`打包、`Java`服务打包等。
+
+> The leading open source automation server, Jenkins provides hundreds of plugins to support building, deploying and automating any project.
+
+`Jenkins`是使用`Java`开发的,官方提供一个`war`包,并且自带`servlet`容器,可以独立运行也可以放在`Tomcat`中运行。当然它也提供了`mac`等客户端,可以直接下载。
+因为一般我们都是将其部署到服务器上,所以这里就用下载`jenkins.war`放到`Tomcat`的方式来讲解。
+
+
+安装Tomcat
+---
+
+去[Tomcat](https://tomcat.apache.org/)官网下载最新的安装包,安装完成后启动`tomcat`.
+
+
+
+
+安装启动都很简答,就是下载后解压,然后打开`terminal`进入解压后的目录下的`bin`目录,然后执行`startup`命令:
+
+
+
+可以看到上面我执行`./startup.sh`时提示权限问题了,这是因为用户没有权限导致无法运行,需要要`chmod`修改`bin`目录下`.sh`的权限。
+修改完权限后启动就可以了,看到提示启动成功后,我们可以在浏览器输入`http://localhost:8080`,如果能显示出来可爱的小喵咪,那就说明启动成功了。
+
+
+
+有关`tomcat`更多的信息就不介绍了,一般在`javaweb`的学习过程中都会学到。
+
+部署Jenkins到Tomcat
+---
+
+去[Jenkins官网](https://jenkins.io/)进行下载,然后选择意向版本的`.war`包
+
+
+
+把下载后的`war`包放在本地`tomcat`目录下的`webapps`目录下。
+
+
+
+然后在浏览器中访问`http://localhost:8080/jenkins/`,如果看到以下界面,代表已经成功部署了.
+
+
+
+启动完成后会提示输入一个密码,上面有路径,我们直接进去打开拷贝就可以了。
+
+
+
+按照上面的路径,进入拷贝.
+
+
+
+然后会出现安装选择页面,我们选择默认的配置就可以。
+
+
+然后就会出现以下界面,我们等待安装就可以了,这个安装过程会灰常慢。 我们也可以看到他会安装`ant、gradle、git、svn、email`等插件。
+
+
+等安装完成后会看到用户名设置界面。
+
+
+好了,大功告成,开始使用后的页面如下:
+
+
+那就开始创建一个项目的项目:
+
+
+创建后就会进入到项目设置页面:
+
+
+然后我们去设置源码管理,配置好分支和项目地址:
+
+
+下面点击证书后面的`add`进行添加,然后选择用用户名和密码的登录方式,输入用户名和密码:
+
+
+然后继续进行设置构建部分,因为`android`打包需要使用`Gradle`所以,我们选择使用`Gradle`然后进行配置`Gradle`:
+
+
+然后设置`Gradle`版本:
+
+
+这里你会发现没有`Gradle`版本,这是因为我们没有去配置`Gradle`导致的,因为`android`打包需要`Gradle`和`JDK`所以我们要先去配置下他俩,
+进入到`jenkins`首页选择系统管理-全局工具配置:
+
+
+里面的`jdk`和`gradle`都可以选择在线安装,如果`jdk`使用在线安装的话需要输入`oracle`账号的的用户名和密码。
+配置弯沉恭候,再回到刚才创建的`JenkisDemo`项目的配置页面继续进行构建配置:
+
+
+然后就可以选择我们刚才新添加的`gradle`版本了:
+
+
+然后再`Tasks`里面输入对应的`Task`命令就可以了。
+
+在里面构建后操作中选择增加构建后操作步骤,可以选择构建完后自动发邮件等。
+
+
+到这里就配置完了,下面直接执行项目里面的立即构建就可以自动打包了。
+
+
+但是报错了,我们点本次构建列表中点入,再点击控制台输出可以查看详细的错误信息,提示说需要配置`SDK`,前面只配置了`jdk`忘了配置`sdk`了
+
+
+打开系统管理-系统设置然后在全局变量-环境变量中增加`Android_home`配置:
+
+
+好了,这样就可以了。
+
+但是我们再打包的时候不仅仅是想这样打一个简单的版本,而是想配置一下参数,来满足一些版本号,渠道等的需求。
+我们可以来到项目的设置页面,选择参数化构建过程-添加参数-选择选项参数等进行添加:
+
+
+可以配置`APP_VERSION`、`BUILD_TIME`、`PRODUCT_FLAVORS`、`BUILD_TYPE`等
+
+
+
+注意这里配置完成后,还要去在`gradle task`中去使用才可以(在命令后面加上配置的参数):
+
+
+好了,配置完成后再返回到项目首页你就会发现之前的立即构建变成了`Build with Parameters`,点击它就可以直接构建了。
+
+
+打包完成后可以自动放到服务器目录中,通过`tomcat`提供链接对外下载,也可以发邮件、生成二维码等。这里就不仔细介绍了。
+`jenkins`可以让我们更自由的进行配置,操作,也可以通过`shell`脚本等进行更加深度的定制,提高了开发中打包的效率。
+
+而且`Jenkins`还提供了很多静态代码分析检查的插件,可以直接去集成使用[Static Code Analysis Plug-ins](Static Code Analysis Plug-ins)
+
+
+
+---
+
+- 邮箱 :charon.chui@gmail.com
+- Good Luck!
diff --git "a/Architect/1.\346\236\266\346\236\204\347\256\200\344\273\213.md" "b/Architect/1.\346\236\266\346\236\204\347\256\200\344\273\213.md"
new file mode 100644
index 00000000..6fa7327a
--- /dev/null
+++ "b/Architect/1.\346\236\266\346\236\204\347\256\200\344\273\213.md"
@@ -0,0 +1,108 @@
+1.系统架构
+===
+
+#### 什么是系统架构
+
+关于系统架构,维基百科给出了一个非常好的定义。
+A system architecture is the conceptual model that defines the structure, behavior, and more views of a system.[
+(系统架构是概念模型,定义了系统的结构、行为和更多的视图)
+
+* 系统架构是一个概念模型。
+* 系统架构定义了系统的结构、行为以及更多的视图。
+关于这个定义,这里给出了另外一种解读,供大家参考。
+* 静。首先,从静止的角度,描述系统如何组成,以及系统的功能在这些组成部分之间是如何划分的。这就是系统的“结构”。一般要描述的是:系统包含哪些子系统,每个子系统有什么功能。在做这些描述时,应感觉自己是一名导游,带着游客在系统的子系统间参观。
+* 动。然后,从动态的角度,描述各子系统之间是如何联动的,它们是如何相互配合完成系统预定的任务或流程的。这就是系统的“行为”。在做这个描述时,应感觉自己是一名电影导演,将系统的各种运行情况通过一个个短片展现出来。
+* 细。最后,在以上两种描述的基础上,从不通的角度,更详细的刻画出系统的细节和全貌。这就是“更多的视图”。
+
+
+
+
+好代码的特性:
+1. 鲁棒(Solid and Robust)
+2. 高效(Fast)
+3. 简洁(Maintainable and Simple)
+4. 简短(Small)
+5. 可测试(Testable)
+6. 共享(Re-Usable)
+7. 可移植(Portable)
+8. 可观测(Observvable)/可监控(Monitorable)
+9. 可运维(Operational): 可运维重点关注成本、效率和稳定性三个方面
+10. 可扩展(Scalable and Extensible)
+
+
+工程能力的定义:
+使用系统化的方法,在保证质量的前提下,更高效率的为客户/用户持续交付有价值的软件或服务的能力。
+
+在《软件开发的201个原则》一书中,将“质量第一”列为全书的第一个原则,可见其重要性。
+Edward Yourdon建议,当你被要求加快测试、忽视剩余的少量Bug、在设计或需求达成一致前就开始编码时,要直接说“不”。
+开发前期的设计文档、技术评审3天以上100%。代码规范,缺乏认真的代码评审。
+降低质量要求,事实上不会降低研发成本,反而会增加整体的研发成本。在研发阶段通过降低质量所“节省”的研发成本,会在软件维护阶段加倍偿还。
+
+在研发前期(需求分析和系统设计)多投入资源,相对于把资源都投入在研发后期(编码、测试等),其收益更大。
+
+
+### 架构三要素
+
+#### 构件
+
+构件在软件领域是指可复用的模块,它可以是被封装的对象类、类树、一些功能模块、软件框架(framework)、软件架构(或体系结构Architectural)、文档、分析件、设计模式(Pattern)。但是,操作集合、过程、函数即使可以复用也不能成为一个构件。
+
+##### 构件的属性:
+1. 有用性(Usefulness):构件必须提供有用的功能。
+2. 可用性(Usability):构件必须易于理解和使用,可以正常运行。
+3. 质量(Quality):构件及其变形必须能正确工作,质量好坏与可用性相互补充。
+4. 适应性(Adaptability):构件应该易于通过参数化等方式再不同环境中进行配置,比较高端一点的复用性,接收外界各种入参,产生不同的结果,健壮性比较高。
+5. 可移植性(Portability):构件应能在不同的硬件运行平台和软件环境中工作,可移植性比较好,跨平台。
+
+
+#### 模式(Pattern)
+
+其实就是解决某一类问题的方法论,是生产经验和生活经验中经过抽象和升华提炼出来的核心知识体系。 模式就是一个完整的流程闭环,能够解决一些问题的通用方法(比如资本运作、玩家不同的需求等),软件中的模式大多源于生活,是人类智慧的结晶。
+
+#### 规划
+
+规划是系统架构中最重要的组成部分,是个人或者组织制定的比较全面长远的发展计划,是对未来整体性、长期性、基本性问题的思考和考量。设计未来整套行动的方案。很早就有规划这个概念了,例如:国家的十一五规划等。当然软件开发也和生活紧密联系,一个大型的系统也需要良好的规划,规划可以说是基石,是系统架构的前提。
+
+
+系统架构虽然是软件系统的结构,行为,属性的高级抽象,但其根本就是在需求分析的基础行为下,制定技术框架,对需求的技术实现。
+
+
+### 系统设计的原则和方法:
+
+* 单一目的
+* 对外关系清晰
+* 重视资源约束
+* 根据需求做决策
+* 基于模型思考
+
+
+#### 单一职责原则
+
+
+
+#### 开放-封闭原则
+无论模块是多么的‘封闭’,都会存在一些无法对之封闭的变化。既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化
+
+开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而,对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要
+
+
+#### 依赖倒转原则
+
+
+
+#### 迪米特法则
+迪米特法则首先强调的前提是在类的结构设计上,每一个类都应当尽量降低成员的访问权限,也就是说,一个类包装好自己的private状态,不需要让别的类知道的字段或行为就不要公开
+
+我们在程序设计时,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。也就是说,信息的隐藏促进了软件的复用。”
+
+
+
+
+
+
+
+---
+- 邮箱 :charon.chui@gmail.com
+- Good Luck!
+
+
diff --git "a/Architect/2.UML\347\256\200\344\273\213.md" "b/Architect/2.UML\347\256\200\344\273\213.md"
new file mode 100644
index 00000000..2bcf58de
--- /dev/null
+++ "b/Architect/2.UML\347\256\200\344\273\213.md"
@@ -0,0 +1,26 @@
+2.UML简介
+
+推荐使用[Visual Paradigm](https://www.visual-paradigm.com/cn/),如果是非商业用途可以下载社区版,免费使用
+
+
+
+
+
+
+类图分三层,第一层显示类的名称,如果是抽象类,则就用斜体显示。第二层是类的特性,通常就是字段和属性。第三层是类的操作,通常是方法或行为。注意前面的符号,‘+’表示public,‘-’表示private,‘#’表示protected。”
+
+继承关系用空心三角形+实线来表示。
+接口用空心三角形+虚线来表示。
+关联关系用实线箭头来表示。
+聚合表示一种弱的‘拥有’关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分。聚合关系用空心的菱形+实线箭头来表示。
+合成(Composition,也有翻译成‘组合’的)是一种强的‘拥有’关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样.合成关系用实心的菱形+实线箭头来表示
+依赖关系(Dependency),用虚线箭头来表示。
+
+
+
+
+## 类图
+
+## 时序图
+
+
diff --git "a/Android\345\237\272\347\241\200/Android\345\205\245\351\227\250\344\273\213\347\273\215.md" "b/BasicKnowledge/Android\345\205\245\351\227\250\344\273\213\347\273\215.md"
similarity index 64%
rename from "Android\345\237\272\347\241\200/Android\345\205\245\351\227\250\344\273\213\347\273\215.md"
rename to "BasicKnowledge/Android\345\205\245\351\227\250\344\273\213\347\273\215.md"
index d2b16ca6..ab179d5d 100644
--- "a/Android\345\237\272\347\241\200/Android\345\205\245\351\227\250\344\273\213\347\273\215.md"
+++ "b/BasicKnowledge/Android\345\205\245\351\227\250\344\273\213\347\273\215.md"
@@ -2,16 +2,16 @@ Android入门介绍
===
1. 3G、4G
- - 第三代移动通信技术(3rd - Generation),速率一般在几百Kbps,较之前的2G和2.5G在数据传输速度上有很大提升。
- - 第四代移动通信技术(4th - Generation),速度可达到100Mbps以上,几乎可以满足人们的所有传输数据的需求。
+ - 第三代移动通信技术`(3rd - Generation)`,速率一般在几百`Kbps`,较之前的`2G`和`2.5G`在数据传输速度上有很大提升。
+ - 第四代移动通信技术`(4th - Generation)`,速度可达到100`Mbps`以上,几乎可以满足人们的所有传输数据的需求。
- 目前主流的3G技术标准有三种:
- - WCDMA:全球80%以上的3G网络都是采用此种制式。中国联通运营。186
- - CDMA2000:目前日韩及北美使用较多。中国电信运营。 189
- - TD-SCDMA:中国自主知识产权的3G通信技术。中国移动运营。 188
+ 目前主流的`3G`技术标准有三种:
+ - `WCDMA`:全球80%以上的`3G`网络都是采用此种制式。中国联通运营。186
+ - `CDMA2000`:目前日韩及北美使用较多。中国电信运营。 189
+ - `TD-SCDMA`:中国自主知识产权的3G通信技术。中国移动运营。 188
- 目前主流的4G技术为LTE,但还没有被广泛应用:
- GSM → GPRS → EDGE → WCDMA → HSDPA → HSDPA+ → LTE
+ 目前主流的`4G`技术为`LTE`,但还没有被广泛应用:
+ `GSM` → `GPRS` → `EDGE` → `WCDMA` → `HSDPA` → `HSDPA+` → `LTE`
2. Android是什么
1. 手机设备的软件栈内存,包括
@@ -27,7 +27,7 @@ Android入门介绍
- 硬件驱动
3. Android体系结构
- - Applications:桌面应用、打电话应用、浏览器等应用程序
+ - Applications:桌面、电话、浏览器等应用程序
- Applications Framework:ActivityManager、 WindowManager、ContentProvider、ResourceManager等
- Libraries: SQLite库、SurfaceManager、WebKit、OppenGL等。
- Android运行时
@@ -50,7 +50,9 @@ Android入门介绍
- intel
- AMD
2. ARM
- - 摩托罗拉
+ - 联发科
+ - 高通
+ - 海思
- 三星
6. Android项目目录结构
@@ -63,7 +65,7 @@ Android入门介绍
- anim:定义动画的XML
- raw:原生文件
4. assets:资源路径,不会在R文件注册
- 5. project.properties:供Eclipse使用,读取该项目使用Android版本号。早期版本名为default.properties
+ 5. project.properties:供Eclipse使用,读取该项目使用Android版本号,早期版本名为default.properties
6. AndroidManifest.xml:清单文件,在软件安装的时候被读取
Android中的四大组件(Activity、ContentProvider、BroadcastReceiver、Service)都需要在该文件中注册程序所需的权限也需要在此文件中声明,例如:电话、短信、互联网、访问SD卡
7. bin:二进制文件,包括class、资源文件、dex、apk等
@@ -79,24 +81,28 @@ Android入门介绍
7. 按照main.xml文件初始化界面
简单的来说软件的安装都是两个过程
- - 拷贝apk中得一些文件到系统的某个目录,1./data/app/目录下, 2.创建一个文件夹 /data/data/com.test.helloworld/来保存数据
- - 在系统的注册表里面配置一些信息. data/system/packages.xml
+ - 拷贝apk中的一些文件到系统的某个目录
+ 1. `/data/app/`目录下
+ 2. 创建一个文件夹 `/data/data/com.test.helloworld/`来保存数据
+ - 在系统的packages.xml文件(类似于Windows的注册表)中里面配置应用权限等一些信息. `/data/system/packages.xml`
8. Android安全学
- Android安全学中的一个重要的设计点是在默认情况下应用程序没有权限执行对其它应用程序、操作系统或用户有害的操作。这些操作包括读/写用户的隐私数据(例如联系方式或e-mail),读/写其它应用程序的文件,执行网络访问,保持设备活动,等等。 所以牵扯到付费或者可能与用户隐私相关的操作都要申请权限.
+ Android安全学中的一个重要的设计点是在默认情况下应用程序没有权限执行对其它应用程序、操作系统或用户有害的操作。
+ 这些操作包括读/写用户的隐私数据(例如联系人或e-mail),读/写其它应用程序的文件,执行网络访问,保持设备活动,等等。
+ 所有牵扯到付费或者可能与用户隐私相关的操作都要申请权限。
9. 测试分类
- 单元测试(Unit test) -> 功能测试( Function test) ->集成测试(Intergation test)
+ 单元测试(Unit test) -> 功能测试( Function test) -> 集成测试(Intergation test)
10. Android单元测试
- AndroidManifest.xml中进行配置,导入android的junit环境
- - 编写测试类继承Android的测试父类,AndroidTestCase这个类( AndroidTestCase是为了去模拟一个手机的运行环境, 这个类中有一个getContext方法能获取到当前测试类的应用上下文对象,所以这个方法必须要等到测试框架初始化完成后才可以去调用)
- - 测试的方法名要求以小写的test开头,如不以test开头只能单独点这个方法运行,整体全部运行时没有这个方法,所有的测试方法都要抛出异常,要把异常抛给测试框架不能自己去捕获。
+ - 编写测试类继承Android的测试父类,AndroidTestCase这个类( AndroidTestCase是为了去模拟一个手机的运行环境,这个类中有一个getContext方法能获取到当前测试类的应用上下文对象,所以这个方法必须要等到测试框架初始化完成后才可以去调用)
+ - 测试的方法名要求以小写的test开头,如不以test开头只能单独点这个方法运行,整体全部运行时没有这个方法,所有的测试方法都要抛出异常,要把异常抛给测试框架不能自己去捕获
- 注意:测试得代码也是只能在手机上跑,它是在手机上测试完之后又将信息发送到了eclipse中
+ 注意:测试的代码也是只能在手机上跑,它是在手机上测试完之后又将信息发送到了eclipse中
---
- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
+- Good Luck!
diff --git "a/BasicKnowledge/Android\345\212\250\347\224\273.md" "b/BasicKnowledge/Android\345\212\250\347\224\273.md"
new file mode 100644
index 00000000..2705a05e
--- /dev/null
+++ "b/BasicKnowledge/Android\345\212\250\347\224\273.md"
@@ -0,0 +1,386 @@
+Android动画
+===
+
+1. AlphaAnimation
+
+ ```java
+ RelativeLayout rl_splash = (RelativeLayout) findViewById(R.id.rl_splash);
+ //播放动画效果
+ AlphaAnimation animation = new AlphaAnimation(1.0f, 0.0f);
+ //设置Alpha动画的持续时间
+ animation.setDuration(2000);
+ //播放Alpha动画
+ rl_splash.setAnimation(animation);
+ ```
+
+2. RotateAnimation
+
+ ```java
+ //相对于自身的哪个位置旋转,这里是相对于自身的右下角
+ RotateAnimation ra = new RotateAnimation(0, 360, //从哪旋转,旋转多少度
+ Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
+ 1.0f);
+ ra.setDuration(800);
+ ra.setRepeatCount(Animation.INFINITE);
+ ra.setRepeatMode(Animation.RESTART);
+ iv_scan.startAnimation(ra);
+ ```
+3. ScaleAnimation(缩放动画)
+
+ ```java
+ ScaleAnimation(float fromX, float toX, float fromY, float toY)
+ Constructor to use when building a ScaleAnimation from code
+ ```
+
+4. TranslateAnimation(位移动画)
+
+ ```java
+ TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue)
+ Constructor to use when building a TranslateAnimation from code
+ ```
+
+5. AnimationSet (多组动画)
+
+ ```java
+ ScaleAnimation sa = new ScaleAnimation(0.2f, 1.0f, 0.4f,1.0f);//缩放的动画效果,1.0f就代表窗体的总宽或者高
+ sa.setDuration(400);
+ TranslateAnimation ta = new TranslateAnimation(//位移动的动画效果
+ Animation.RELATIVE_TO_SELF, 0,//指定这个位置是相对于谁
+ Animation.RELATIVE_TO_SELF, 0.1f,
+ Animation.RELATIVE_TO_SELF, 0,
+ Animation.RELATIVE_TO_SELF, 0);
+ ta.setDuration(300);
+ AnimationSet set = new AnimationSet(false);//如果想播放多种动画的组合,这里就要用到了AnimationSet
+ set.addAnimation(sa);
+ set.addAnimation(ta);
+ contentView.startAnimation(set); // 播放一组动画.
+ ```
+
+6. Frame动画
+ 在`SDK`中提到,不要在`onCreate`中调用`start`方法开始播放`Frame`动画,因为`AnimationDrawable`还没有完全跟`Window`相关联,如果想要界面显示时就开始播放帧动画的话,可以在`onWindowFocusChanged()`中调用`start()`。
+
+ - 在`drawable`目录下新建一个`xml`文件,内容如下:
+
+ ```xml
+
+ //onshot是指定是否循环播放
+ //播放这个图片持续的时间
+
+
+ ```
+ - 播放Frame动画
+
+ ```java
+ AnimationDrawable rocketAnimation;
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ ImageView rocketImage = (ImageView) findViewById(R.id.iv);
+ rocketImage.setBackgroundResource(R.drawable.animlist); //将上边建的Frame动画的xml文件通过背景资源设置给图片
+ rocketAnimation = (AnimationDrawable) rocketImage.getBackground(); //获取到图片的背景资源
+ }
+ public void start(View view) {
+ if (!rocketAnimation.isRunning()) {
+ rocketAnimation.start(); //播放
+ }
+ }
+ ```
+
+7. 保持动画播放完成后的状态`animation.setFillAfter(true);`
+
+ ```java
+ Interpolator //定义了动画的变化速度,可以实现匀速、正加速、负加速、无规则变加速度
+ AccelerateDecelerateInterpolator//先加速后减速。
+ AccelerateInterpolator//逐渐加速。
+ LinearInterpolator//平稳不变的
+ DecelerateInterpolator//逐渐减速
+ CycleInterpolator//曲线运动特效,要传递float型的参数。
+ animation.setInterpolator(new LinearInterpolator());//指定动画的运行效果
+ ```
+
+上面所讲的动画都是`Android 3.0`之前的动画,也就是我们最先熟悉的`Frame`动画和`Tween`动画。
+
+从`3.0`开始又引入了一个新的动画叫做`Property`动画。并且针对这三种动画的动画模式分为:
+
+- `Property Animation` : 属性动画,从`Android 3.0`开始引进,更改的是对象的实际属性,而且属性动画不止可以应用于`View`还可以应用于任何对象。
+- `View Animation` : 指之前的`Tween`动画,`alpha scale translate rotate`等。为什么叫做`View Animation`呢?因为它只能应用于`View`对象,而且只支持一部分属性,如支持缩放旋转而不支持背景颜色的变化。对于`View Animation`而言,它只改变了`View`对象绘制的位置,而没有改变`View`对象本身的属性,比如,有一个200*200大小的`Button`,你用`Tween`动画给放大到500*500但是它的有效点击区域还是200*200。
+- `Drawable Animation` : 指之前的`Frame`动画。因为它是通过一帧帧的图片来播放的。
+
+下面我们开始仔细讲解一下`Property Animation`
+---
+
+官方文档中是这样这样介绍属性动画的:
+
+```
+The property animation system is a robust framework that allows you to animate almost anything. You can define an animation to change any object property over time, regardless of whether it draws to the screen or not. A property animation changes a property's (a field in an object) value over a specified length of time. To animate something, you specify the object property that you want to animate, such as an object's position on the screen, how long you want to animate it for, and what values you want to animate between.
+```
+一个强大的框架。
+
+在`Property Animation`中,可以对动画应用以下属性:
+
+- `Duration`: 指定动画持续时间,默认时间是`300ms`
+- `TimeInterpolation`: 一些效果,如加速、加速等。
+- `Repeat count and behavior `: 重复次数已经
+- `Animation Set`: 动画合集。用来同时或者顺序播放多个动画。
+- `Frame Refresh Delay`: 多长时间刷新一次,默认是`10ms`。
+
+### `ValueAnimator`
+
+
+`ValueAnimator`包含`Property Animation`动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用`Property Animation`有两个步聚:
+
+- 计算属性值
+- 根据属性值执行相应的动作,如改变对象的某一属性。
+
+`ValuAnimiator`只完成了第一步工作,如果要完成第二步,需要实现`ValueAnimator.onUpdateListener`接口,这个接口只有一个函数`onAnimationUpdate()`,在这个函数中会传入`ValueAnimator`对象做为参数,通过这个`ValueAnimator`对象的`getAnimatedValue()`函数可以得到当前的属性值。
+
+### `ObjectAnimator`
+
+继承自`ValueAnimator`,要指定一个对象及该对象的一个属性,当属性值计算完成时自动设置为该对象的相应属性,即完成了`Property Animation`的全部两步操作。实际应用中一般都会用`ObjectAnimator`来改变某一对象的某一属性,但用`ObjectAnimator`有一定的限制,要想使用`ObjectAnimator`,应该满足以下条件:
+
+- 对象应该有一个`setter`函数:`set`(驼峰命名法)
+- 如上面的例子中,像`ofFloat`之类的工场方法,第一个参数为对象名,第二个为属性名,后面的参数为可变参数,如果`values…`参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的`getter`方法:`get`
+- 如果有`getter`方法,其应返回值类型应与相应的`setter`方法的参数类型一致。
+- `object`的`setXxx`对属性`xxx`所做的改变必须能够通过某种方法反映出来,比如会带来`ui`的改变啥的(如果这条不满足,动画无效果),例如我对`TextView`或者`Button`使用`width`的`ObjectAnimator`动画,就会发现无效,虽然他们都有`setWidth`和`getWidth`方法,但是`setWidth`方法的内部实现是改变`TextView`的最大宽度和最小宽度的,和`TextView`的宽度不是一个东西。所以动画就会无效。确切的说`TextView`的宽度对应的是`xml`中`android:layout_width`属性,而`TextView`还有另外一个属性:`android:width`,而`android:width` 属性对应的就是`TextView`中的`setWidth`方法。
+
+如果上述条件不满足,则不能用`ObjectAnimator`,应用`ValueAnimator`代替。
+也就是说`ObjectAnimator`内部的工作机制是通过寻找特定属性的`get`和`set`方法,然后通过方法不断地对值进行改变,从而实现动画效果的。
+
+### `AnimationSet`
+
+
+`AnimationSet`提供了一个把多个动画组合成一个组合的机制,并可设置组中动画的时序关系,如同时播放,顺序播放等。
+
+以下例子同时应用5个动画:
+
+- Plays bounceAnim.
+- Plays squashAnim1, squashAnim2, stretchAnim1, and stretchAnim2 at the same time.
+- Plays bounceBackAnim.
+- Plays fadeAnim.
+
+```java
+AnimatorSet bouncer = new AnimatorSet();
+bouncer.play(bounceAnim).before(squashAnim1);
+bouncer.play(squashAnim1).with(squashAnim2);
+bouncer.play(squashAnim1).with(stretchAnim1);
+bouncer.play(squashAnim1).with(stretchAnim2);
+bouncer.play(bounceBackAnim).after(stretchAnim2);
+ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
+fadeAnim.setDuration(250);
+AnimatorSet animatorSet = new AnimatorSet();
+animatorSet.play(bouncer).before(fadeAnim);
+animatorSet.start();
+```
+
+### `TypeEvalutors`
+
+
+根据属性的开始、结束值与`TimeInterpolation`计算出的比例值来计算当前时间对应的属性值,`Android`提供了一下几种`evalutor`:
+
+- `IntEvalutor`:`int`类型的属性值
+- `FloatEvaluator`:
+- `ArgbEvaluator`: 属性的值类型为十六进制颜色值;
+- `TypeEvaluator`: 一个接口,可以通过实现该接口自定义Evaluator。
+自定义`TypeEvaluator`也很简单,只需要实现一个方法,如`FloatEvalutor`的定义:
+```java
+public class FloatEvaluator implements TypeEvaluator {
+ public Object evaluate(float fraction, Object startValue, Object endValue) {
+ float startFloat = ((Number) startValue).floatValue();
+ return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
+ }
+}
+```
+`evaluate()`方法当中传入了三个参数,第一个参数`fraction`非常重要,这个参数用于表示动画的完成度的,我们应该根据它来计算当前动画的值应该是多少,第二第三个参数分别表示动画的初始值和结束值。那么上述代码的逻辑就比较清晰了,用结束值减去初始值,算出它们之间的差值,然后乘以`fraction`这个系数,再加上初始值,那么就得到当前动画的值了。
+
+
+### `TimeInterplator`
+Time interplator定义了属性值变化的方式,如线性均匀改变,开始慢然后逐渐快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,这两个是一样的,在3.0之前只有Interplator,3.0之后实现代码转移至了TimeInterplator。Interplator继承自TimeInterplator,内部没有任何其他代码。
+
+- AccelerateInterpolator 加速,开始时慢中间加速
+- DecelerateInterpolator 减速,开始时快然后减速
+- AccelerateDecelerateInterolator 先加速后减速,开始结束时慢,中间加速
+- AnticipateInterpolator 反向 ,先向相反方向改变一段再加速播放
+- AnticipateOvershootInterpolator 反向加回弹,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
+- BounceInterpolator 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
+- CycleIinterpolator 循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
+- LinearInterpolator 线性,线性均匀改变
+- OvershottInterpolator 回弹,最后超出目的值然后缓慢改变到目的值
+- TimeInterpolator 一个接口,允许你自定义interpolator,以上几个都是实现了这个接口
+
+
+### `PropertyValuesHolder`
+
+如果要实现一个对象不同属性的动画效果,除了`Set`,我们还可以利用`PropertyValuesHolder`和`ViewPropertyAnimator`对象来实现,具体做法如下:
+```
+PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
+PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
+ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
+```
+
+### `ViewPropertyAnimator`
+```
+ * This class is not constructed by the caller, but rather by the View whose properties
+ * it will animate. Calls to {@link android.view.View#animate()} will return a reference
+ * to the appropriate ViewPropertyAnimator object for that View.
+```
+如果需要对一个View的多个属性进行动画可以用ViewPropertyAnimator类,该类对多属性动画进行了优化,会合并一些invalidate()来减少刷新视图,该类在3.1中引入。
+
+`view.animate()`方法会返回`ViewPropertyAnimator`类。
+```java
+myView.animate().x(50f).y(100f);
+```
+的效果与上面的`PropertyValuesHolder`例子中的效果完全一致。
+但是你有没有发现我们自始至终没有调用过`start()`方法,这是因为新的接口中使用了隐式启动动画的功能,只要我们将动画定义完成之后,动画就会自动启动。并且这个机制对于组合动画也同样有效,只要我们不断地添加新的方法,那么动画就不会立刻执行,等到所有在`ViewPropertyAnimator`上设置的方法都执行完毕后,动画就会自动启动。当然如果不想使用这一默认机制的话,我们也可以显式地调用`start()`方法来启动动画。
+
+
+
+### `XML`中定义
+
+在`res/animator`中定义对应的动画`xml`
+- 对应代码中的ValueAnimator
+- 对应代码中的ObjectAnimator
+- 对应代码中的AnimatorSet
+例如:
+
+```xml
+
+
+
+```
+这里说明一下`valueFrom`和`valueTo`:是动画开始和结束值,如果我们缩放,则它们对应的是倍数,如果我们平移则对应的就是距离了。
+
+接下来就是调用了
+```java
+scaleXAnimator = (ObjectAnimator)AnimatorInflater.loadAnimator(this, R.animator.scalex);
+scaleXAnimator.setTarget(btnScaleX);
+scaleXAnimator.start();
+```
+
+那如果我们要播放多个动画怎么办?
+```xml
+
+
+
+
+
+
+
+```
+```java
+animatorScaleSet = (AnimatorSet)AnimatorInflater.loadAnimator(this, R.animator.scale);
+animatorScaleSet.setTarget(btnScale);
+animatorScaleSet.start();
+
+```
+
+`Android L`又增加了一种动画样式,叫做`Reveal Animation`。
+首先来看一下效果:
+
+
+
+可以直接通过`ViewAnimationUtils.createCircularReveal()`方法来创建。
+
+```java
+/**
+ * Returns an Animator which can animate a clipping circle.
+ *
+ * Any shadow cast by the View will respect the circular clip from this animator.
+ *
+ * Only a single non-rectangular clip can be applied on a View at any time.
+ * Views clipped by a circular reveal animation take priority over
+ * {@link View#setClipToOutline(boolean) View Outline clipping}.
+ *
+ * Note that the animation returned here is a one-shot animation. It cannot
+ * be re-used, and once started it cannot be paused or resumed. It is also
+ * an asynchronous animation that automatically runs off of the UI thread.
+ * As a result {@link AnimatorListener#onAnimationEnd(Animator)}
+ * will occur after the animation has ended, but it may be delayed depending
+ * on thread responsiveness.
+ *
+ * @param view The View will be clipped to the animating circle.
+ * @param centerX The x coordinate of the center of the animating circle, relative to
+ * view.
+ * @param centerY The y coordinate of the center of the animating circle, relative to
+ * view.
+ * @param startRadius The starting radius of the animating circle.
+ * @param endRadius The ending radius of the animating circle.
+ */
+public static Animator createCircularReveal(View view,
+ int centerX, int centerY, float startRadius, float endRadius) {
+ return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
+}
+```
+
+代码如下:
+
+```java
+void enterReveal() {
+ final View myView = findViewById(R.id.my_view);
+
+ int cx = myView.getMeasuredWidth() / 2;
+ int cy = myView.getMeasuredHeight() / 2;
+
+ int finalRadius = Math.max(myView.getWidth(), myView.getHeight()) / 2;
+
+ Animator anim =
+ ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
+
+ anim.start();
+}
+
+void exitReveal() {
+ final View myView = findViewById(R.id.my_view);
+
+ int cx = myView.getMeasuredWidth() / 2;
+ int cy = myView.getMeasuredHeight() / 2;
+
+ int initialRadius = myView.getWidth() / 2;
+
+ Animator anim =
+ ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);
+
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ myView.setVisibility(View.INVISIBLE);
+ }
+ });
+
+ anim.start();
+}
+
+```
+
+有关如何提高动画性能请看:[通过Hardware Layer提高动画性能](https://github.com/CharonChui/AndroidNote/blob/master/Android%E5%8A%A0%E5%BC%BA/%E9%80%9A%E8%BF%87Hardware%20Layer%E6%8F%90%E9%AB%98%E5%8A%A8%E7%94%BB%E6%80%A7%E8%83%BD.md)
+
+---
+
+- 邮箱 :charon.chui@gmail.com
+- Good Luck!
diff --git "a/BasicKnowledge/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213ContentProvider.md" "b/BasicKnowledge/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213ContentProvider.md"
new file mode 100644
index 00000000..26adc9e2
--- /dev/null
+++ "b/BasicKnowledge/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213ContentProvider.md"
@@ -0,0 +1,312 @@
+Android四大组件之ContentProvider
+===
+
+ContentProvider
+---
+
+安卓应用程序默认是无法获取到其他程序的数据,这是安卓安全学的基石(沙盒原理)。但是经常我们需要给其他应用分享数据,内容提供者就是一个这种可以分享数据给其他应用的接口。
+可以简单的理解为,内容提供者就是一个可以在不同应用程序间共享数据的组件,相当于一个中间人,一个程序把数据暴露给这个中间人,另一个则通过这个中间人获取相应的数据.
+
+下面的这张图片能更直观的显示:
+
+
+
+- `ContentProvider`中的`getContext`和`AndroidTestCast`中的`getContext`方法一样,都是一个模拟的上下文,必须在该类初始化之后才会调用`setContext`方法将`context`设置成自己的成员变量中记录,
+ 所以对于获取`getContext`的时候只能放在方法内,不能放到成员位置,因为在成员上时是null,而在方法内调用时该类就会已经初始化完了
+
+- `ContentProvider`中的`query()`后不能关闭数据库,因为其他的应用在调用该`query`方法时需要继续使用该返回值`Cursor`,所以不能关闭数据库,因为数据库关闭之后`Cursor`就不能用了,
+ `Cursor`中保存的数据其实是数据库的一个引用,如果数据库关了`Cursor`就不能找到里面的数据了,`Cursor.close()`只是释放`Cursor`用到的资源。说到这里就多数一句
+ `According to Dianne Hackborn (Android framework engineer) there is no need to close the database in a content provider.`以为内容提供者是因为进程启动时便加载,之后就一直存在,当进程销毁
+ 释放资源时会去关闭数据库。
+
+- 如果数据是`SQLiteDatabase`,表中必须有一个`_id`的列,用来表示每条记录的唯一性。
+
+1. 继承`ContentProvider`,并实现相应的方法。
+ ```java
+ public class NoteProvider extends ContentProvider {
+ private static final int NOTES = 1;
+ private static final int NOTE_ID = 2;
+
+ public static final String AUTHORITY = "com.charon.demo.provider.noteprovider";
+ public static final String TABLE_NAME = "note";
+ // 定义一个名为`CONTENT_URI`必须为其指定一个唯一的字符串值,最好的方案是以类的全名称
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
+
+ // 声明一个路径的检查者,参数为Uri不匹配时的返回值
+ // 虽然是中间人,但也不能谁要数据我们都给,所以要检查下,只有符合我们要求的人,我们才会给他数据。
+ private static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+ private NoteSQLiteOpenHelper mSQLiteOpenHelper;
+ private SQLiteDatabase mSQLiteDatabase;
+
+ static {
+ // 建立匹配规则,例如发现路径为ccom.charon.demo.provider.noteprovider/note/1表示要操作note表中id为1的记录
+ sUriMatcher.addURI(AUTHORITY, TABLE_NAME, NOTES);
+ sUriMatcher.addURI(AUTHORITY, TABLE_NAME + "/#", NOTE_ID);
+ }
+
+ /**
+ * Implement this to initialize your content provider on startup.
+ * This method is called for all registered content providers on the
+ * application main thread at application launch time. It must not perform
+ * lengthy operations, or application startup will be delayed.
+ *
+ * You should defer nontrivial initialization (such as opening,
+ * upgrading, and scanning databases) until the content provider is used
+ * (via {@link #query}, {@link #insert}, etc). Deferred initialization
+ * keeps application startup fast, avoids unnecessary work if the provider
+ * turns out not to be needed, and stops database errors (such as a full
+ * disk) from halting application launch.
+ *
+ * If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper}
+ * is a helpful utility class that makes it easy to manage databases,
+ * and will automatically defer opening until first use. If you do use
+ * SQLiteOpenHelper, make sure to avoid calling
+ * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or
+ * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase}
+ * from this method. (Instead, override
+ * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the
+ * database when it is first opened.)
+ *
+ * @return true if the provider was successfully loaded, false otherwise
+ */
+ @Override
+ public boolean onCreate() {
+ mSQLiteOpenHelper = new NoteSQLiteOpenHelper(getContext());
+ return true;
+ }
+
+ /**
+ * 内容提供者暴露的查询的方法.
+ */
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ mSQLiteDatabase = mSQLiteOpenHelper.getReadableDatabase();
+ Cursor cursor;
+ // 1.重要的事情 ,检查 uri的路径.
+ switch (sUriMatcher.match(uri)) {
+ case NOTES:
+ break;
+ case NOTE_ID:
+ String id = uri.getLastPathSegment();
+ if (TextUtils.isEmpty(selection)) {
+ selection = selection + "_id = " + id;
+ } else {
+ selection = selection + " and " + "_id = " + id;
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("UnKnown Uri" + uri);
+ break;
+ }
+ cursor = mSQLiteDatabase.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
+ if (cursor != null) {
+ cursor.setNotificationUri(getContext().getContentResolver(), uri);
+ }
+ return cursor;
+ }
+
+ /**
+ * Implement this to handle requests for the MIME type of the data at the
+ * given URI. The returned MIME type should start with
+ * vnd.android.cursor.item for a single record,
+ * or vnd.android.cursor.dir/ for multiple items.
+ * This method can be called from multiple threads, as described in
+ * Processes
+ * and Threads.
+ *
+ * Note that there are no permissions needed for an application to
+ * access this information; if your content provider requires read and/or
+ * write permissions, or is not exported, all applications can still call
+ * this method regardless of their access permissions. This allows them
+ * to retrieve the MIME type for a URI when dispatching intents.
+ *
+ * @param uri the URI to query.
+ * @return a MIME type string, or {@code null} if there is no type.
+ */
+ @Override
+ public String getType(Uri uri) {
+ // 注释说的很清楚了,下面是常用的格式
+ // 单个记录的IMEI类型 vnd.android.cursor.item/vnd..
+ // 多个记录的IMEI类型 vnd.android.cursor.dir/vnd..
+ switch (sUriMatcher.match(uri)) {
+ case NOTE_ID:
+ // 如果uri为 content://com.charon.demo.noteprovider/note/1
+ return "vnd.android.cursor.item/vnd.charon.note";
+ case NOTES:
+ return "vnd.android.cursor.dir/vnd.charon.note";
+ default:
+ return null;
+ }
+
+ // 这个MIME类型的作用是要匹配AndroidManifest.xml文件标签下标签的子标签的属性android:mimeType。
+ // 如果不一致,则会导致对应的Activity无法启动。
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ mSQLiteDatabase = mSQLiteOpenHelper.getWritableDatabase();
+ switch (sUriMatcher.match(uri)) {
+ case NOTES:
+ break;
+
+ case NOTE_ID:
+ break;
+
+ default:
+ throw new IllegalArgumentException("UnKnown Uri" + uri);
+ break;
+ }
+
+ long rowId = mSQLiteDatabase.insert(TABLE_NAME, null, values);
+ if (rowId > 0) {
+ Uri noteUri = ContentUris.withAppendedId(CONTENT_URI, rowId);
+ getContext().getContentResolver().notifyChange(noteUri, null);
+ return noteUri;
+ }
+
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ mSQLiteDatabase = mSQLiteOpenHelper.getWritableDatabase();
+ switch (sUriMatcher.match(uri)) {
+ case NOTES:
+ break;
+
+ case NOTE_ID:
+ String id = uri.getLastPathSegment();
+ if (TextUtils.isEmpty(selection)) {
+ selection = selection + "_id = " + id;
+ } else {
+ selection = selection + " and " + "_id = " + id;
+ }
+ break;
+
+ default:
+ throw new IllegalArgumentException("UnKnown Uri" + uri);
+ break;
+ }
+ int count = mSQLiteDatabase.delete(TABLE_NAME, selection, selectionArgs);
+ getContext().getContentResolver().notifyChange(uri, null);
+ return count;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ switch (sUriMatcher.match(uri)) {
+ case NOTES:
+
+ break;
+
+ case NOTE_ID:
+
+ break;
+
+ default:
+ throw new IllegalArgumentException("UnKnown Uri" + uri);
+ break;
+ }
+
+ mSQLiteDatabase = mSQLiteOpenHelper.getWritableDatabase();
+ int update = mSQLiteDatabase.update(TABLE_NAME, values, selection, selectionArgs);
+ return update;
+ }
+ ```
+
+2. 在清单文件中进行注册,并且指定其authorities
+ ```xml
+
+ ```
+
+3. 使用内容提供者获取数据,使用`ContentResolver`去操作`ContentProvider`, `ContentResolver`用于管理`ContentProvider`实例,
+ 并且可实现找到指定的`ContentProvider`并获取里面的数据
+ ```java
+ public void query(View view){
+ //得到内容提供者的解析器 中间人
+ ContentResolver resolver = getContentResolver();
+ Cursor cursor = resolver.query(NoteProvider.CONTENT_URI, null, null, null, null);
+ while(cursor.moveToNext()){
+ String name = cursor.getString(cursor.getColumnIndex("name"));
+ int id = cursor.getInt(cursor.getColumnIndex("id"));
+ float money = cursor.getFloat(cursor.getColumnIndex("money"));
+ System.out.println("id="+id+",name="+name+",money="+money);
+ }
+ cursor.close();
+ }
+ public void insert(View view){
+ ContentResolver resolver = getContentResolver();
+ ContentValues values = new ContentValues();
+ values.put("name", "买洗头膏");
+ values.put("money", 22.58f);
+ resolver.insert(NoteProvider.CONTENT_URI, values);
+ }
+ public void update(View view){
+ ContentResolver resolver = getContentResolver();
+ ContentValues values = new ContentValues();
+ values.put("name", "买洗头膏");
+ values.put("money", 42.58f);
+ resolver.update(NoteProvider.CONTENT_URI, values, "name=?", new String[]{"买洗头膏"});
+ }
+ public void delete(View view){
+ ContentResolver resolver = getContentResolver();
+ resolver.delete(NoteProvider.CONTENT_URI, "name=?", new String[]{"买洗头膏"});
+ }
+ ```
+
+内容观察者
+---
+
+内容观察者的原理:
+`How a content provider actually stores its data under the covers is up to its designer. But all content providers implement a common interface for
+querying the provider and returning results — as well as for adding, altering, and deleting data.
+It's an interface that clients use indirectly, most generally through ContentResolver objects.
+You get a ContentResolver by calling getContentResolver() from within the implementation of an Activity or other application component:
+You can then use the ContentResolver's methods to interact with whatever content providers you're interested in.`
+
+1. 一方使用内容观察者去观察变化
+ ```java
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ ContentResolver resolver = getContentResolver();
+ resolver.registerContentObserver(NoteProvider.CONTENT_URI, true, new NoteObserver(new Handler()));
+
+ }
+
+ private class NoteObserver extends ContentObserver {
+
+ public NoteObserver(Handler handler) {
+ super(handler);
+
+ }
+ //当观察到数据发生变化的时候 会执行onchange方法.
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ Log.i(TAG,"发现有新的短信产生了...");
+ //1.利用内容提供者 中间人 获取用户的短信数据.
+ ContentResolver resolver = getContentResolver();
+ // .. 重新查询
+ cursor = ...;
+ cursor.close();
+ }
+ }
+ ```
+
+2. 一方在发生变化的时候去发送改变的消息
+ 对于一些系统的内容提供者内部都实现了该步骤,如果是自己写程序想要暴露就必须要加上该代码。
+
+ ```java
+ getContext().getContentResolver().notifyChange(uri, null);
+ ```
+
+---
+
+- 邮箱 :charon.chui@gmail.com
+- Good Luck!
\ No newline at end of file
diff --git "a/BasicKnowledge/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213Service.md" "b/BasicKnowledge/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213Service.md"
new file mode 100644
index 00000000..dcf3cb47
--- /dev/null
+++ "b/BasicKnowledge/Android\345\233\233\345\244\247\347\273\204\344\273\266\344\271\213Service.md"
@@ -0,0 +1,216 @@
+Android四大组件之Service
+===
+
+服务的两种开启方式:
+---
+
+1. `startService()`:开启服务.
+ 开启服务后 服务就会长期的后台运行,即使调用者退出了.服务仍然在后台继续运行.服务和调用者没有什么关系, 调用者是不可以访问服务里面的方法.
+2. `bindService()`:绑定服务.
+ 服务开启后,生命周期与调用者相关联.调用者挂了,服务也会跟着挂掉.不求同时生,但求同时死.调用者和服务绑定在一起,调用者可以间接的调用到服务里面的方法.
+
+AIDL
+---
+
+本地服务:服务代码在本应用中
+远程服务:服务在另外一个应用里面(另外一个进程里面)
+`aidl`: `android interface defination language`
+`IPC implementation` : `inter process communication`
+
+服务混合调用的生命周期
+---
+
+开启服务后再去绑定服务然后再去停止服务,这时服务是无法停止了.必须先解绑服务然后再停止服务,在实际开发中会经常采用这种模式,
+开启服务(保证服务长期后台运行) --> 绑定服务(调用服务的方法) --> 解绑服务(服务继续在后台运行) --> 停止服务(服务停止),服务只会被开启一次,
+如果已经开启后再去执行开启操作是没有效果的。
+
+绑定服务调用方法的原理
+---
+
+1. 定义一个接口,里面定义一个方法
+ ```java
+ public interface IService {
+ public void callMethodInService();//通过该类中提供一个方法,让自定
+ 义的类实现这个接口
+ }
+ ```
+
+2. 在服务中自定义一个IBinder的实现类,让这个类继承Binder(Binder是IBinder的默认适配器),由于这个自定义类是私有的,为了其他类中能拿到该类,
+ 我们要定义一个接口,提供一个方法,让IBinder类去实现该接口,并在相应方法中调用自己要供别人调用的方法。
+ ```java
+ public class TestService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ System.out.println("onbind");
+ return new MyBinder();
+ }
+
+ private class MyBinder extends Binder implements IService{
+ public void callMethodInService(){
+ //实现该方法,去调用服务中的方法
+ methodInService();
+ }
+ }
+ //服务中的方法
+ public void methodInService(){
+ Toast.makeText(this, "我是服务里面的春哥,巴拉布拉!", 0).show();
+ }
+ }
+ ```
+
+3. 服务的调用类中将`onServiceConnected`方法中的第二个参数强转成接口
+ ```java
+ public class DemoActivity extends Activity {
+ private Intent intent;
+ private Myconn conn;
+ private IService iService;
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ intent = new Intent(this,TestService.class);
+ setContentView(R.layout.main);
+ }
+ public void start(View view) {
+ startService(intent);
+ }
+ public void stop(View view) {
+ stopService(intent);
+ }
+ public void bind(View view) {
+ conn = new Myconn();
+ //1.绑定服务 传递一个conn对象.这个conn就是一个回调接口
+ bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ }
+ public void unbind(View view) {
+ unbindService(conn);
+ }
+ //调用服务中的方法
+ public void call(View view){
+ iService.callMethodInService();
+ }
+ private class Myconn implements ServiceConnection{
+ //当服务被成功绑定的时候调用的方法.
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {//第二个参数就是服务中的onBind方法的返回值
+ iService = (IService) service;
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ }
+ }
+ ```
+
+远程服务aidl
+---
+
+上面介绍了绑定服务调用服务中方法的原理,对于远程服务的绑定也是这样,
+但是这个远程服务是在另外一个程序中的,在另外一个程序中定 义的这个接口,
+在另外一个程序中是拿不到的,就算是我们在自己的应用 中也定义一个一模一样
+的接口,但是由于两个程序的报名不同,这两个接口也是不一样的,为了解决这个
+问题,谷歌的工程师给提供了aidl,我们将定义的这个接口的`.java`改成 `.aidl`,
+然后将这个接口中的`权限修饰符`都**去掉**,在另一个程序中拷贝这个aidl文
+件,然后放到同一个包名中,由于`Android`中通过包名来区分应用程序,这两个
+`aidl`的包名一样,系统会认为两个程序中的接口是同一个,这样就能够在另一
+个程序中将参数强转成这个接口,在使用`aidl`文件拷贝到自己的工程之后会自动
+生成一个接口类,这个接口类中有 一个内部类`Stub`该类继承了`Binder`并实现了
+这个接口,所以我们在自定义 `IBinder的实现类`时只需让自定义的类继承`Stub类`
+即可.
+
+1. 远程服务中定义一个接口,改成`aidl`
+ ```java
+ package com.seal.test.service;
+
+ interface IService {
+ void callMethodInService();
+ }
+ ```
+
+2. 远程服务中定义一个`Ibinder的实现类`,让这个实现类继承上面接口的`Stub类`,
+并在`onBind`方法中返回这个自定义类对象
+ ```java
+ public class RemoteService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ System.out.println("远程服务被绑定");
+ return new MyBinder();
+ }
+ private class MyBinder extends IService.Stub{
+ @Override
+ public void callMethodInService() {
+ methodInService();
+ }
+ }
+ public void methodInService(){
+ System.out.println("我是远程服务里面的方法");
+ }
+ }
+ ```
+
+3. 在其他程序中想要绑定这个服务并且调用这个服务中的方法的时候首先要拷贝
+这个`aidl`文件到自己的工程,然后再`ServiceConnection`的实现类中将这个参数使
+用`asInterface`方法转成接口,通过这样来得到接口,从而调用接口中的方法
+ ```java
+ public class CallRemoteActivity extends Activity {
+ private Intent service;
+ private IService iService;
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ service = new Intent();
+ service.setAction("com.itheima.xxxx");
+ }
+ public void bind(View veiw){
+ bindService(service, new MyConn(), BIND_AUTO_CREATE);
+ }
+ public void call(View view){
+ try {
+ iService.callMethodInService();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ private class MyConn implements ServiceConnection{
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ iService = IService.Stub.asInterface(service);
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // TODO Auto-generated method stub
+ }
+ }
+ }
+ ```
+
+最后说一下`IntentService`:
+
+`IntentService`是`Service`的子类,用来处理异步请求。客户端可以通过`startService(Intent)`方法将请求的`Intent`传递请求给`IntentService`,
+`IntentService`会将该`Intent`加入到队列中,然后对每一个`Intent`开启一个`worker thread`来进行处理,执行完所有的工作之后自动停止`Service`。
+每一个请求都会在一个单独的`worker thread`中处理,不会阻塞应用程序的主线程。`IntentService` 实际上是`Looper`、`Handler`、`Service` 的集合体,
+他不仅有服务的功能,还有处理和循环消息的功能.
+
+- Service:
+ 1. A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified,
+ it runs in the same process as the application it is part of.
+ 2. A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
+所以在`Service`中进行耗时的操作时必须要新开一个线程。
+
+至于为什么要使用`Service`而不是`Thread`,这个主要的区别就是生命周期不同,`Service`是Android系统的一个组件,Android系统会尽量保持`Service`的长期后台运行,
+即使内存不足杀死了该服务(很少会出现内存不足杀死服务的情况)也会在内存可用的时候去复活该服务,而`Thread`随后都会被杀死
+- IntentService
+ 1. IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand.
+ Clients send requests throughstartService(Intent) calls;
+ the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
+ 2. This "work queue processor" pattern is commonly used to offload tasks from an application's main thread.
+ The IntentService class exists to simplify this pattern and take care of the mechanics.
+ To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread,
+ and stop the service as appropriate.
+ 3. All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop),
+ but only one request will be processed at a time.
+
+---
+
+- 邮箱 :charon.chui@gmail.com
+- Good Luck!
diff --git "a/BasicKnowledge/Android\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md" "b/BasicKnowledge/Android\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md"
new file mode 100644
index 00000000..319f5ef8
--- /dev/null
+++ "b/BasicKnowledge/Android\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md"
@@ -0,0 +1,622 @@
+Android基础面试题
+===
+
+没有删这套题,虽然都是网上找的,在刚开始找工作的时候这套题帮了我很多,那时候`Android`刚起步,很多家都是这一套面试题,我都是直接去了不看题哗哗一顿就写完了,哈哈
+现在估计没有公司会用这种笔试题了。还是留下来吧,回忆一下。
+
+1. 下列哪些语句关于内存回收的说明是正确的? (b)
+ A、 程序员必须创建一个线程来释放内存
+ B、 内存回收程序负责释放无用内存
+ C、 内存回收程序允许程序员直接释放内存
+ D、 内存回收程序可以在指定的时间释放内存对象
+2. 下面异常是属于Runtime Exception 的是(abcd)(多选)
+ A、ArithmeticException
+ B、IllegalArgumentException
+ C、NullPointerException
+ D、BufferUnderflowException
+3. Math.round(11.5)等于多少(). Math.round(-11.5)等于多少(c)
+ A、11 ,-11 B、11 ,-12 C、12 ,-11 D、12 ,-12
+4. 下列程序段的输出结果是:(b)
+ ```java
+ void complicatedexpression_r(){
+ int x=20, y=30;
+ boolean b;
+ b=x>50&&y>60||x>50&&y<-60||x<-50&&y>60||x<-50&&y<-60;
+ System.out.println(b);
+ }
+ ```
+ A、true B、false C、1 D、011.activity
+5. 对一些资源以及状态的操作保存,最好是保存在生命周期的哪个函数中进行(d)
+ A、onPause() B、onCreate() C、 onResume() D、onStart()
+6. Intent传递数据时,下列的数据类型哪些可以被传递(abcd)(多选)
+ A、Serializable B、charsequence C、Parcelable D、Bundle
+7. android 中下列属于Intent的作用的是(c)
+ A、实现应用程序间的数据共享
+ B、是一段长的生命周期,没有用户界面的程序,可以保持应用在后台运行,而不会因为切换页面而消失
+ C、可以实现界面间的切换,可以包含动作和动作数据,连接四大组件的纽带
+ D、处理一个应用程序整体性的工作
+8. 下列属于SAX解析xml文件的优点的是(b)
+ A、将整个文档树在内存中,便于操作,支持删除,修改,重新排列等多种功能
+ B、不用事先调入整个文档,占用资源少
+ C、整个文档调入内存,浪费时间和空间
+ D、不是长久驻留在内存,数据不是持久的,事件过后,若没有保存数据,数据就会消失
+9. 下面的对自定style的方式正确的是(a)
+ A、
+ ```xml
+
+
+
+ ```
+ B、
+ ```xml
+
+ ```
+ C、
+ ```xml
+
+ - fill_parent
+
+ ```
+ D、
+ ```xml
+
+
+
+ ```
+10. 在android中使用Menu时可能需要重写的方法有(ac)。(多选)
+ A、onCreateOptionsMenu()
+ B、onCreateMenu()
+ C、onOptionsItemSelected()
+ D、onItemSelected()
+11. 在SQL Server Management Studio 中运行下列T-SQL语句,其输出值(c)
+ `SELECT @@IDENTITY`
+ A、 可能为0.1
+ B、 可能为3
+ C、 不可能为-100
+ D、 肯定为0
+12. 在SQL Server 2005中运行如下T-SQL语句,假定SALES表中有多行数据,执行查询之后的结果是(d)。
+ ```
+ BEGIN TRANSACTION A
+ Update SALES Set qty=30 WHERE qty<30
+ BEGIN TRANSACTION B
+ Update SALES Set qty=40 WHERE qty<40
+ Update SALES Set qty=50 WHERE qty<50
+ Update SALES Set qty=60 WHERE qty<60
+ COMMIT TRANSACTION B
+ COMMIT TRANSACTION A
+ ```
+ A、SALES表中qty列最小值大于等于30
+ B、SALES表中qty列最小值大于等于40
+ C、SALES表中qty列的数据全部为50
+ D、SALES表中qty列最小值大于等于60
+13. 在android中使用SQLiteOpenHelper这个辅助类时,可以生成一个数据库,并可以对数据库版本进行管理的方法可以是(ab)
+ A、getWriteableDatabase()
+ B、getReadableDatabase()
+ C、getDatabase()
+ D、getAbleDatabase()
+14. android 关于service生命周期的onCreate()和onStart()说法正确的是(ad)(多选题)
+ A、当第一次启动的时候先后调用onCreate()和onStart()方法
+ B、当第一次启动的时候只会调用onCreate()方法
+ C、如果service已经启动,将先后调用onCreate()和onStart()方法
+ D、如果service已经启动,只会执行onStart()方法,不在执行onCreate()方法
+15. 下面是属于GLSurFaceView特性的是(abc)(多选)
+ A、管理一个surface,这个surface就是一块特殊的内存,能直接排版到android的视图view上。
+ B、管理一个EGL display,它能让opengl把内容渲染到上述的surface上。
+ C、让渲染器在独立的线程里运作,和UI线程分离。
+ D、可以直接从内存或者DMA等硬件接口取得图像数据
+16. 下面在AndroidManifest.xml文件中注册BroadcastReceiver方式正确的(a)
+ A、
+ ```xml
+
+
+
+
+
+
+ ```
+ B、
+ ```xml
+
+
+ android:name="android.provider.action.NewBroad"/>
+
+
+ ```
+ C、
+ ```xml
+
+
+
+
+ ```
+ D、
+ ```xml
+
+
+
+ android:name="android.provider.action.NewBroad"/>
+
+
+
+ ```
+17. 关于ContenValues类说法正确的是(a)
+ A、他和Hashtable比较类似,也是负责存储一些名值对,但是他存储的名值对当中的名是String类型,而值都是基本类型
+ B、他和Hashtable比较类似,也是负责存储一些名值对,但是他存储的名值对当中的名是任意类型,而值都是基本类型
+ C、他和Hashtable比较类似,也是负责存储一些名值对,但是他存储的名值对当中的名,可以为空,而值都是String类型
+ D、他和Hashtable比较类似,也是负责存储一些名值对,但是他存储的名值对当中的名是String类型,而值也是String类型
+18. 我们都知道Hanlder是线程与Activity通信的桥梁,如果线程处理不当,你的机器就会变得越慢,那么线程销毁的方法是(a)
+ A、onDestroy()
+ B、onClear()
+ C、onFinish()
+ D、onStop()
+19. 下面退出Activity错误的方法是(c)
+ A、finish()
+ B、抛异常强制退出
+ C、System.exit()
+ D、onStop()
+20. 下面属于android的动画分类的有(ab)(多项)
+ A、Tween B、Frame C、Draw D、Animation
+21. 下面关于Android dvm的进程和Linux的进程,应用程序的进程说法正确的是(d)
+ A、DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,不一定拥有一个独立 的Dalvik虚拟机实例.而每一个DVM都是在Linux 中的一个进程,
+ 所以说可以认为是同一个概念.
+ B、DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,不一定拥有一个独立的Dalvik虚拟机实例.而每一个DVM不一定都是在Linux 中的一个进程,
+ 所以说不是一个概念.
+ C、DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例.而每一个DVM不一定都是在Linux 中的一个进程,
+ 所以说不是一个概念.
+ D、DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的 Dalvik虚拟机实例.而每一个DVM都是在Linux 中的一个进程,
+ 所以说可以认为是同一个概念.
+22. Android项目工程下面的assets目录的作用是什么(b)
+ A、放置应用到的图片资源。
+ B、主要放置多媒体等数据文件
+ C、放置字符串,颜色,数组等常量数据
+ D、放置一些与UI相应的布局文件,都是xml文件
+23. 关于res/raw目录说法正确的是(a)
+ A、这里的文件是原封不动的存储到设备上不会转换为二进制的格式
+ B、这里的文件是原封不动的存储到设备上会转换为二进制的格式
+ C、这里的文件最终以二进制的格式存储到指定的包中
+ D、这里的文件最终不会以二进制的格式存储到指定的包中
+24. 下列对android NDK的理解正确的是(abcd)
+ A、NDK是一系列工具的集合
+ B、NDK 提供了一份稳定、功能有限的 API 头文件声明。
+ C、使 “Java+C” 的开发方式终于转正,成为官方支持的开发方式
+ D、NDK 将是 Android 平台支持 C 开发的开端
+
+25. android中常用的四个布局是framlayout,linenarlayout,relativelayout和tablelayout。
+26. android 的四大组件是activiey,service,broadcast和contentprovide。
+27. java.io包中的objectinputstream和objectoutputstream类主要用于对对象(Object)的读写。
+28. android 中service的实现方法是:startservice和bindservice。
+29. activity一般会重载7个方法用来维护其生命周期,除了onCreate(),onStart(),onDestory() 外还有onrestart,onresume,onpause,onstop。
+30. android的数据存储的方式sharedpreference,文件,SQlite,contentprovider,网络。
+31. 当启动一个Activity并且新的Activity执行完后需要返回到启动它的Activity来执行 的回调函数是startActivityResult()。
+32. 请使用命令行的方式创建一个名字为myAvd,sdk版本为2.2,sd卡是在d盘的根目录下,名字为scard.img, 并指定屏幕大小HVGA.____________________________________。
+33. 程序运行的结果是:_____good and gbc__________。
+ ```java
+ public class Example{
+ String str=new String("good");
+ char[]ch={'a','b','c'};
+ public static void main(String args[]){
+ Example ex=new Example();
+ ex.change(ex.str,ex.ch);
+ System.out.print(ex.str+" and ");
+ Sytem.out.print(ex.ch);
+ }
+ public void change(String str,char ch[]){
+ str="test ok";
+ ch[0]='g';
+ }
+ }
+ ```
+34. 在android中,请简述jni的调用过程。(8分)
+ 1)安装和下载Cygwin,下载 Android NDK
+ 2)在ndk项目中JNI接口的设计
+ 3)使用C/C++实现本地方法
+ 4)JNI生成动态链接库.so文件
+ 5)将动态链接库复制到java工程,在java工程中调用,运行java工程即可
+35. 简述Android应用程序结构是哪些?(7分)
+ Android应用程序结构是:
+ Linux Kernel(Linux内核)、Libraries(系统运行库或者是c/c++核心库)、Application
+ Framework(开发框架包)、Applications (核心应用程序)
+36. 请继承SQLiteOpenHelper实现:(10分)
+ 1).创建一个版本为1的“diaryOpenHelper.db”的数据库
+ 2).同时创建一个 “diary” 表(包含一个_id主键并自增长,topic字符型100长度, content字符型1000长度)
+ 3).在数据库版本变化时请删除diary表,并重新创建出diary表。
+ ```java
+ public class DBHelper extends SQLiteOpenHelper {
+
+ public final static String DATABASENAME = "diaryOpenHelper.db";
+ public final static int DATABASEVERSION = 1;
+
+ //创建数据库
+ public DBHelper(Context context,String name,CursorFactory factory,int version)
+ {
+ super(context, name, factory, version);
+ }
+ //创建表等机构性文件
+ public void onCreate(SQLiteDatabase db)
+ {
+ String sql ="create table diary"+
+ "("+
+ "_id integer primary key autoincrement,"+
+ "topic varchar(100),"+
+ "content varchar(1000)"+
+ ")";
+ db.execSQL(sql);
+ }
+ //若数据库版本有更新,则调用此方法
+ public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion)
+ {
+
+ String sql = "drop table if exists diary";
+ db.execSQL(sql);
+ this.onCreate(db);
+ }
+ }
+ ```
+37. 页面上现有ProgressBar控件progressBar,请用书写线程以10秒的的时间完成其进度显示工作。(10分)
+ ```java
+ public class ProgressBarStu extends Activity {
+
+ private ProgressBar progressBar = null;
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.progressbar);
+ //从这到下是关键
+ progressBar = (ProgressBar)findViewById(R.id.progressBar);
+
+ Thread thread = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ int progressBarMax = progressBar.getMax();
+ try {
+ while(progressBarMax!=progressBar.getProgress())
+ {
+
+ int stepProgress = progressBarMax/10;
+ int currentprogress = progressBar.getProgress();
+ progressBar.setProgress(currentprogress+stepProgress);
+ Thread.sleep(1000);
+ }
+
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+ });
+
+ thread.start();
+ //关键结束
+ }
+ }
+ ```
+38. 如何退出Activity?如何安全退出已调用多个Activity的Application?
+ 对于单一Activity的应用来说,退出很简单,直接finish()即可。
+ 当然,也可以用killProcess()和System.exit()这样的方法。
+ 但是,对于多Activity的应用来说,在打开多个Activity后,如果想在最后打开的Activity直接退出,上边的方法都是没有用的,因为上边的方法都是结束一个Activity而已。
+ 当然,网上也有人说可以。
+ 就好像有人问,在应用里如何捕获Home键,有人就会说用keyCode比较KEYCODE_HOME即可,而事实上如果不修改framework,根本不可能做到这一点一样。
+ 所以,最好还是自己亲自试一下。
+ 那么,有没有办法直接退出整个应用呢?
+ 在2.1之前,可以使用ActivityManager的restartPackage方法。
+ 它可以直接结束整个应用。在使用时需要权限android.permission.RESTART_PACKAGES。
+ 注意不要被它的名字迷惑。
+ 可是,在2.2,这个方法失效了。
+ 在2.2添加了一个新的方法,killBackgroundProcesses(),需要权限 android.permission.KILL_BACKGROUND_PROCESSES。
+ 可惜的是,它和2.2的restartPackage一样,根本起不到应有的效果。
+ 另外还有一个方法,就是系统自带的应用程序管理里,强制结束程序的方法,forceStopPackage()。
+ 它需要权限android.permission.FORCE_STOP_PACKAGES。
+ 并且需要添加android:sharedUserId="android.uid.system"属性
+ 同样可惜的是,该方法是非公开的,他只能运行在系统进程,第三方程序无法调用。
+ 因为需要在Android.mk中添加LOCAL_CERTIFICATE := platform。
+ 而Android.mk是用于在Android源码下编译程序用的。
+ 从以上可以看出,在2.2,没有办法直接结束一个应用,而只能用自己的办法间接办到。
+ 现提供几个方法,供参考:
+ - 抛异常强制退出:
+ 该方法通过抛异常,使程序Force Close。
+ 验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
+ - 记录打开的Activity:
+ 每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
+ - 发送特定广播:
+ 在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
+ - 递归退出
+ 在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
+ 除了第一个,都是想办法把每一个Activity都结束掉,间接达到目的。
+ 但是这样做同样不完美。
+ 你会发现,如果自己的应用程序对每一个Activity都设置了nosensor,在两个Activity结束的间隙,sensor可能有效了。
+ 但至少,我们的目的达到了,而且没有影响用户使用。
+ 为了编程方便,最好定义一个Activity基类,处理这些共通问题。
+39. 请介绍下Android中常用的五种布局。
+ FrameLayout(框架布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局)
+40. 请介绍下Android的数据存储方式。
+ - SharedPreferences方式
+ - 文件存储方式
+ - SQLite数据库方式
+ - 内容提供器(Content provider)方式
+ - 网络存储方式
+41. 请介绍下ContentProvider是如何实现数据共享的。
+ 创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。
+42. 如何启用Service,如何停用Service。
+ Android中的service类似于windows中的service,service一般没有用户操作界面,它运行于系统中不容易被用户发觉,
+ 可以使用它开发如监控之类的程序。
+ 一。步骤
+ 第一步:继承Service类
+ public class SMSService extends Service { }
+ 第二步:在AndroidManifest.xml文件中的节点里对服务进行配置:
+
+ 二。Context.startService()和Context.bindService
+ 服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可
+ 以启动Service,但是它们的使用场合有所不同。
+ 1.使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
+ 使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。
+ 2.采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
+ 接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并
+ 不会导致多次创建服务,但会导致多次调用onStart()方法。
+ 采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用
+ onDestroy()方法。
+
+ 3.采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
+ 接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,
+ 。接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会
+ 导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务
+ 解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。
+ 三。Service的生命周期
+ 1. Service常用生命周期回调方法如下:
+ onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,
+ 服务也只被创建一次。 onDestroy()该方法在服务被终止时调用。
+ 2. Context.startService()启动Service有关的生命周期方法
+ onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。
+ 多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。
+ 3. Context.bindService()启动Service有关的生命周期方法
+ onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,
+ 当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
+ onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。
+
+ 备注:
+ 1. 采用startService()启动服务
+ Intent intent = new Intent(DemoActivity.this, DemoService.class);
+ startService(intent);
+ 2. Context.bindService()启动
+ Intent intent = new Intent(DemoActivity.this, DemoService.class);
+ bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ //unbindService(conn);//解除绑定
+43. 注册广播有几种方式,这些方式有何优缺点?请谈谈Android引入广播机制的用意。
+ Android广播机制(两种注册方法)
+ 在android下,要想接受广播信息,那么这个广播接收器就得我们自己来实现了,我们可以继承BroadcastReceiver,就可以有一个广播接受器了。
+ 有个接受器还不够,我们还得重写BroadcastReceiver里面的onReceiver方法,当来广播的时候我们要干什么,这就要我们自己来实现,
+ 不过我们可以搞一个信息防火墙。具体的代码:
+ ```java
+ public class SmsBroadCastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Bundle bundle = intent.getExtras();
+ Object[] object = (Object[])bundle.get("pdus");
+ SmsMessage sms[]=new SmsMessage[object.length];
+ for(int i=0;i
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ```
+ 两种注册类型的区别是:
+ - 第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
+ - 第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
+44. 请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。
+ Handler简介:
+ 一个Handler允许你发送和处理Message和Runable对象,这些对象和一个线程的MessageQueue相关联。每一个线程实例和一个单独的线程以及该线程的MessageQueue相关联。
+ 当你创建一个新的Handler时,它就和创建它的线程绑定在一起了。这里,线程我们也可以理解为线程的MessageQueue。从这一点上来看,
+ Handler把Message和Runable对象传递给MessageQueue,而且在这些对象离开MessageQueue时,Handler负责执行他们。
+ Handler有两个主要的用途:(1)确定在将来的某个时间点执行一个或者一些Message和Runnable对象。(2)在其他线程(不是Handler绑定线程)中排入一些要执行的动作。
+ Scheduling Message,即(1),可以通过以下方法完成:
+ post(Runnable):Runnable在handler绑定的线程上执行,也就是说不创建新线程。
+ postAtTime(Runnable,long):
+ postDelayed(Runnable,long):
+ sendEmptyMessage(int):
+ sendMessage(Message):
+ sendMessageAtTime(Message,long):
+ sendMessageDelayed(Message,long):
+ post这个动作让你把Runnable对象排入MessageQueue,MessageQueue受到这些消息的时候执行他们,当然以一定的排序。sendMessage这个动作允许你把Message对象排成队列,
+ 这些Message对象包含一些信息,Handler的hanlerMessage(Message)会处理这些Message.当然,handlerMessage(Message)必须由Handler的子类来重写。这是编程人员需要作的事。
+ 当posting或者sending到一个Hanler时,你可以有三种行为:当MessageQueue准备好就处理,定义一个延迟时间,定义一个精确的时间去处理。
+ 后两者允许你实现timeout,tick,和基于时间的行为。
+ 当你的应用创建一个新的进程时,主线程(也就是UI线程)自带一个MessageQueue,这个MessageQueue管理顶层的应用对象(像activities,broadcast receivers等)和
+ 主线程创建的窗体。你可以创建自己的线程,并通过一个Handler和主线程进行通信。这和之前一样,通过post和sendmessage来完成,差别在于在哪一个线程中执行这么方法。
+ 在恰当的时候,给定的Runnable和Message将在Handler的MessageQueue中被Scheduled。
+ Message简介:
+ Message类就是定义了一个信息,这个信息中包含一个描述符和任意的数据对象,这个信息被用来传递给Handler.Message对象提供额外的两个int域和一个Object域,
+ 这可以让你在大多数情况下不用作分配的动作。尽管Message的构造函数是public的,但是获取Message实例的最好方法是调用Message.obtain(),
+ 或者Handler.obtainMessage()方法,这些方法会从回收对象池中获取一个。
+ MessageQueue简介:
+ 这是一个包含message列表的底层类。Looper负责分发这些message。Messages并不是直接加到一个MessageQueue中,而是通过MessageQueue.IdleHandler关联到Looper。
+ 你可以通过Looper.myQueue()从当前线程中获取MessageQueue。
+ Looper简介:
+ Looper类被用来执行一个线程中的message循环。默认情况,没有一个消息循环关联到线程。在线程中调用prepare()创建一个Looper,然后用loop()来处理messages,直到循环终止。
+ 大多数和message loop的交互是通过Handler。
+ 下面是一个典型的带有Looper的线程实现。
+ ```java
+ class LooperThread extends Thread {
+ public Handler mHandler;
+
+ public void run() {
+ Looper.prepare();
+
+ mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ // process incoming messages here
+ }
+ };
+
+ Looper.loop();
+ }
+ }
+ ```
+45. AIDL的全称是什么?如何工作?能处理哪些类型的数据?
+ AIDL的英文全称是Android Interface Define Language
+ 当A进程要去调用B进程中的service时,并实现通信,我们通常都是通过AIDL来操作的
+ A工程:
+ 首先我们在net.blogjava.mobile.aidlservice包中创建一个RemoteService.aidl文件,在里面我们自定义一个接口,含有方法get。ADT插件会在gen目录下自动生成一个RemoteService.java文件,该类中含有一个名为RemoteService.stub的内部类,该内部类中含有aidl文件接口的get方法。
+ 说明一:aidl文件的位置不固定,可以任意
+ 然后定义自己的MyService类,在MyService类中自定义一个内部类去继承RemoteService.stub这个内部类,实现get方法。在onBind方法中返回这个内部类的对象,系统会自动将这个对象封装成IBinder对象,传递给他的调用者。
+ 其次需要在AndroidManifest.xml文件中配置MyService类,代码如下:
+
+
+
+
+
+
+
+ 为什么要指定调用AIDL服务的ID,就是要告诉外界MyService这个类能够被别的进程访问,只要别的进程知道这个ID,正是有了这个ID,B工程才能找到A工程实现通信。
+ 说明:AIDL并不需要权限
+ B工程:
+ 首先我们要将A工程中生成的RemoteService.java文件拷贝到B工程中,在bindService方法中绑定aidl服务
+ 绑定AIDL服务就是将RemoteService的ID作为intent的action参数。
+ 说明:如果我们单独将RemoteService.aidl文件放在一个包里,那个在我们将gen目录下的该包拷贝到B工程中。如果我们将RemoteService.aidl文件和我们的其他类存放在一起,那么我们在B工程中就要建立相应的包,以保证RmoteService.java文件的报名正确,我们不能修改RemoteService.java文件
+ bindService(new Inten("net.blogjava.mobile.aidlservice.RemoteService"), serviceConnection, Context.BIND_AUTO_CREATE);
+ ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法中的service参数就是A工程中MyService类中继承了RemoteService.stub类的内部类的对象。
+46. 请解释下Android程序运行时权限与文件系统权限的区别。
+ 运行时权限Dalvik( android授权)
+ 文件系统 linux 内核授权
+47. 系统上安装了多种浏览器,能否指定某浏览器访问指定页面?请说明原由。
+ 通过直接发送Uri把参数带过去,或者通过manifest里的intentfilter里的data属性
+48. 你如何评价Android系统?优缺点。
+ 答:Android平台手机 5大优势:
+ - 开放性
+ 在优势方面,Android平台首先就是其开发性,开发的平台允许任何移动终端厂商加入到Android联盟中来。显著的开放性可以使其拥有更多的开发者,
+ 随着用户和应用的日益丰富,一个崭新的平台也将很快走向成熟。开放性对于Android的发展而言,有利于积累人气,这里的人气包括消费者和厂商,
+ 而对于消费者来讲,随大的受益正是丰富的软件资源。开放的平台也会带来更大竞争,如此一来,消费者将可以用更低的价位购得心仪的手机。
+ - 挣脱运营商的束缚
+ 在过去很长的一段时间,特别是在欧美地区,手机应用往往受到运营商制约,使用什么功能接入什么网络,几乎都受到运营商的控制。从去年iPhone 上市 ,
+ 用户可以更加方便地连接网络,运营商的制约减少。随着EDGE、HSDPA这些2G至3G移动网络的逐步过渡和提升,手机随意接入网络已不是运营商口中的笑谈,
+ 当你可以通过手机IM软件方便地进行即时聊天时,再回想不久前天价的彩信和图铃下载业务,是不是像噩梦一样?互联网巨头Google推动的Android终端天生就有网络特色,
+ 将让用户离互联网更近。
+ - 丰富的硬件选择
+ 这一点还是与Android平台的开放性相关,由于Android的开放性,众多的厂商会推出千奇百怪,功能特色各具的多种产品。功能上的差异和特色,
+ 却不会影响到数据同步、甚至软件的兼容,好比你从诺基亚 Symbian风格手机 一下改用苹果 iPhone ,同时还可将Symbian中优秀的软件带到iPhone上使用、
+ 联系人等资料更是可以方便地转移,是不是非常方便呢?
+ - 不受任何限制的开发商
+ Android平台提供给第三方开发商一个十分宽泛、自由的环境,不会受到各种条条框框的阻扰,可想而知,会有多少新颖别致的软件会诞生。但也有其两面性,血腥、暴力、情色方面的程序和游戏如可控制正是留给Android难题之一。
+ - 无缝结合的Google应用
+ 如今叱诧互联网的Google已经走过10年度历史,从搜索巨人到全面的互联网渗透,Google服务如地图、邮件、搜索等已经成为连接用户和互联网的重要纽带,
+ 而Android平台手机将无缝结合这些优秀的Google服务。
+
+ 再说Android的5大不足:
+ - 安全和隐私
+ 由于手机 与互联网的紧密联系,个人隐私很难得到保守。除了上网过程中经意或不经意留下的个人足迹,Google这个巨人也时时站在你的身后,
+ 洞穿一切,因此,互联网的深入将会带来新一轮的隐私危机。
+ - 首先开卖Android手机的不是最大运营商
+ 众所周知,T-Mobile在23日,于美国纽约发布 了Android首款手机G1。但是在北美市场,最大的两家运营商乃AT&T和Verizon,
+ 而目前所知取得Android手机销售权的仅有 T-Mobile和Sprint,其中T-Mobile的3G网络相对于其他三家也要逊色不少,因此,用户可以买账购买G1,
+ 能否体验到最佳的3G网络服务则要另当别论了!
+ - 运营商仍然能够影响到Android手机
+ 在国内市场,不少用户对购得移动定制机不满,感觉所购的手机被人涂画了广告一般。这样的情况在国外市场同样出现。
+ Android手机的另一发售运营商Sprint就将在其机型中内置其手机商店程序。
+ - 同类机型用户减少
+ 在不少手机论坛都会有针对某一型号的子论坛,对一款手机的使用心得交流,并分享软件资源。而对于Android平台手机,由于厂商丰富,
+ 产品类型多样,这样使用同一款机型的用户越来越少,缺少统一机型的程序强化。举个稍显不当的例子,现在山寨机泛滥,品种各异,
+ 就很少有专门针对某个型号山寨机的讨论和群组,除了哪些功能异常抢眼、颇受追捧的机型以外。
+ - 过分依赖开发商缺少标准配置
+ 在使用PC端的Windows Xp系统的时候,都会内置微软Windows Media Player这样一个浏览器程序,用户可以选择更多样的播放器,
+ 如Realplay或暴风影音等。但入手开始使用默认的程序同样可以应付多样的需要。在 Android平台中,由于其开放性,软件更多依赖第三方厂商,
+ 比如Android系统的SDK中就没有内置音乐 播放器,全部依赖第三方开发,缺少了产品的统一性。
+49. 什么是ANR 如何避免它?
+ 答:ANR:Application Not Responding,五秒
+ 在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。当出现下列情况时,Android就会显示ANR对话框了:
+ 对输入事件(如按键、触摸屏事件)的响应超过5秒
+ 意向接受器(intentReceiver)超过10秒钟仍未执行完毕
+ Android应用程序完全运行在一个独立的线程中(例如main)。这就意味着,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。
+ 因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intent broadcast)。
+ 因此,任何运行在主线程中的方法,都要尽可能的只做少量的工作。特别是活动生命周期中的重要方法如onCreate()和 onResume()等更应如此。
+ 潜在的比较耗时的操作,如访问网络和数据库;或者是开销很大的计算,比如改变位图的大小,需要在一个单独的子线程中完成(或者是使用异步请求,如数据库操作)。
+ 但这并不意味着你的主线程需要进入阻塞状态已等待子线程结束 -- 也不需要调用Therad.wait()或者Thread.sleep()方法。
+ 取而代之的是,主线程为子线程提供一个句柄(Handler),让子线程在即将结束的时候调用它(xing:可以参看Snake的例子,这种方法与以前我们所接触的有所不同)。
+ 使用这种方法涉及你的应用程序,能够保证你的程序对输入保持良好的响应,从而避免因为输入事件超过5秒钟不被处理而产生的ANR。
+ 这种实践需要应用到所有显示用户界面的线程,因为他们都面临着同样的超时问题。
+50. 什么情况会导致Force Close ?如何避免?能否捕获导致其的异常?
+ 答:一般像空指针啊,可以看起logcat,然后对应到程序中 来解决错误
+
+51. 如何将SQLite数据库(dictionary.db文件)与apk文件一起发布?
+ 解答:可以将dictionary.db文件复制到Eclipse Android工程中的res aw目录中。所有在res aw目录中的文件不会被压缩,这样可以直接提取该目录中的文件。
+ 可以将dictionary.db文件复制到res aw目录中
+52. 如何将打开res aw目录中的数据库文件?
+ 解答:在Android中不能直接打开res aw目录中的数据库文件,而需要在程序第一次启动时将该文件复制到手机内存或SD卡的某个目录中,然后再打开该数据库文件。复制的基本方法是使用getResources().openRawResource方法获得res aw目录中资源的 InputStream对象,然后将该InputStream对象中的数据写入其他的目录中相应文件中。
+ 在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法来打开任意目录中的SQLite数据库文件。
+53. Android引入广播机制的用意?
+ - 从MVC的角度考虑(应用程序内)
+ 其实回答这个问题的时候还可以这样问,android为什么要有那4大组件,现在的移动开发模型基本上也是照搬的web那一套MVC架构,只不过是改了点嫁妆而已。
+ android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构,它们之间有时候是一种相互依存的关系,有时候又是一种补充关系,
+ 引入广播机制可以方便几大组件的信息和数据交互。
+ - 程序间互通消息(例如在自己的应用程序内监听系统来电)
+ - 效率上(参考UDP的广播协议在局域网的方便性)
+ - 设计模式上(反转控制的一种应用,类似监听者模式)
+54. Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念
+ DVM指dalivk的虚拟机。每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例。而每一个DVM都是在Linux 中的一个进程,
+ 所以说可以认为是同一个概念。
+55. 说说mvc模式的原理,它在android中的运用
+ MVC(Model_view_contraller)”模型_视图_控制器”。 MVC应用程序总是由这三个部分组成。Event(事件)导致Controller改变Model或View,或者同时改变两者。
+ 只要 Controller改变了Models的数据或者属性,所有依赖的View都会自动更新。类似的,只要Contro
+56. DDMS和TraceView的区别?
+ DDMS是一个程序执行查看器,在里面可以看见线程和堆栈等信息,TraceView是程序性能分析器 。
+57. java中如何引用本地语言
+ 可以用JNI(java native interface java 本地接口)接口 。
+58. 谈谈Android的IPC(进程间通信)机制
+ IPC是内部进程通信的简称, 是共享"命名管道"的资源。Android中的IPC机制是为了让Activity和Service之间可以随时的进行交互,故在Android中该机制,
+ 只适用于Activity和Service之间的通信,类似于远程方法调用,类似于C/S模式的访问。通过定义AIDL接口文件来定义IPC接口。Servier端实现IPC接口,
+ Client端调用IPC接口本地代理。
+
+---
+
+- 邮箱 :charon.chui@gmail.com
+- Good Luck!
+
diff --git "a/BasicKnowledge/Android\347\274\226\347\240\201\350\247\204\350\214\203.md" "b/BasicKnowledge/Android\347\274\226\347\240\201\350\247\204\350\214\203.md"
new file mode 100644
index 00000000..d6131150
--- /dev/null
+++ "b/BasicKnowledge/Android\347\274\226\347\240\201\350\247\204\350\214\203.md"
@@ -0,0 +1,329 @@
+Android编码规范
+===
+
+介绍
+---
+
+1. 为什么需要编码规范
+ 编码规范对于程序员而言尤为重要,有以下几个原因:
+ - 一个软件的生命周期中,80%的花费在于维护
+ - 几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护
+ - 编码规范可以改善软件的可读性,可以让程序员尽快而彻底地理解新的代码
+
+源文件规范
+---
+
+1. 文件名
+ 源文件名必须和它包含的顶层类名保持一致,包括大小写,并以.java作为后缀名。
+
+2. 文件编码
+ 所有源文件编码必须是`UTF-8`
+
+
+
+命名
+---
+
+1. 包名
+ 命名规则:一个唯一包名的前缀总是全部小写的`ASCII`字母并且是一个**顶级域名**,通常是`com,edu,gov,mil,net,org`。
+ 包名的后续部分根据不同机构各自内部的命名规范而不尽相同。这类命名规范可能以特定目录名的组成来区分部门 `(department)`,
+ 项目`(project)`,机器`(machine)`,或注册名`(login names)`.
+ 例如: `com.domain.xx`
+
+ 包命名必须以`com.domain`开始,后面跟有项目名称(或者缩写),再后面为模块名或层级名称。
+ 如:`com.domain.项目缩写.模块名` `com.domain.xx.bookmark`
+ 如:`com.domain.项目缩写.层级名` `com.domain.xx.activity`
+
+2. 类和接口命名
+ 命名规则:类名是个一名词,采用大小写混合的方式,每个单词的首字母大写。尽量使你的类名简洁而富于描述。使用完整单词,
+ 避免缩写词(除非该缩写词被更广泛使用,像 URL,HTML)
+
+ 接口一般要使用`able`,`ible`,`er`等后缀
+
+ 类名必须使用**驼峰规则**,即首字母必须大写,如果为词组,则每个单词的首字母也必须要大写,类名必须使用名词,或名词词组。
+ 要求类名简单,不允许出现无意义的单词。
+
+3. 方法的命名
+ 命名规则:方法名是一个动词,采用大小写混合的方式,第一个单词的首字母小写,其后单词的首字母大写。
+ 例如: `public void run(); public String getBookName();`
+
+ 类中常用方法的命名:
+ - 类的获取方法(一般具有返回值)一般要求在被访问的字段名前加上`get`.
+ 如`getFirstName()`,`getLastName()`.
+ 一般来说,`get`前缀方法返回的是单个值,`find`前缀的方法返回的是列表值.
+
+ - 类的设置方法(一般返回类型为`void`):被访问字段名的前面加上前缀 `set`.
+ 如`setFirstName()`,`setLastName()`.
+
+ - 类的布尔型的判断方法一般要求方法名使用单词`is`或`has`做前缀.
+ 如`isPersistent()`,`isString()`.或者使用具有逻辑意义的单词,例如`equal`或`equals`.
+
+ - 类的普通方法一般采用完整的英文描述说明成员方法功能,第一个单词尽可能采用动词,首字母小写.
+ 如`openFile()`, `addCount()`.
+ - 构造方法应该用递增的方式写,(参数多的写在后面).
+ - `toString()`方法:一般情况下,每个类都应该定义`toString()`.
+
+4. 变量命名
+ 命名规则:第一个单词的首字母小写,其后单词的首字母大写。变量名不应以下划线或美元符号开头,尽管这在语法上是允许的。变量名应简短且富于描述。
+ 变量名的选用应该易于记忆,即,能够指出其用途。尽量避免单个字符的变量名,除非是一次性的临时变量。临时变量通常被取名为 `i,j,k,m,n`它们一般用于整型;
+ `c,d,e` 它们一般用于字符型。
+ 在`Android`中成员变量
+ 非`public`非`static`的变量可以使用`m`开头
+ 非常量的`static`变量可以使用`s`开头
+
+
+ 变量命名也必须使用**驼峰规则**,但是首字母必须小写,变量名尽可能的使用名词或名词词组。同样要求简单易懂,不允许出现无意义的单词。
+ 例如:`private String mBookName; `
+
+5. 常量命名
+ 命名规则:类常量的声明,应该全部大写,单词间用下划线隔开。
+ 例如:`private static final int MIN_WIDTH = 4;`
+
+6. 异常命名
+ 自定义异常的命名必须以`Exception`为结尾。已明确标示为一个异常。
+
+7. layout命名
+ `layout.xml`的命名必须以全部单词小写,单词间以下划线分割,并且使用名词或名词词组,即使用 模块名_功能名称_所属页面类型 来命名。
+ 如:`video_controller_player_activity` 视频模块下的-控制栏-属于播放器的-Activity页
+
+8. id命名
+ ·layout`中所使用的`id`必须以全部单词小写,单词间以下划线分割,并且使用名词或名词词组,并且要求能够通过`id`直接理解当前组件要实现的功能。
+ 如:某`TextView @+id/tv_book_name_show`
+ 如:某`EditText @+id/`et_book_name_edit`
+
+9. 资源命名
+ `layout`中所使用的所有资源(如`drawable`,`style`等),命名必须以全部单词小写,单词间以下划线分割,并且尽可能的使用名词或名词组,
+ 即使用 模块名_用途 来命名。如果为公共资源,如分割线等,则直接用用途来命名
+ 如:`menu_icon_navigate.png`
+ 如:某分割线:`line.png` 或 `separator.png`
+
+注释
+---
+
+`Java`程序有两类注释:实现注释`(implementation comments)`和文档注释`(document comments)`。
+实现注释是使用/*...*/和//界定的注释。文档注释(被称为"doc comments")由/**...*/界定。文档注释可以通过javadoc 工具转换成HTML 文件。
+
+1. 类注释
+ 每一个类都要包含如下格式的注释,以说明当前类的功能等。
+ /**
+ * 类名
+ * @author 作者
+ * 实现的主要功能。
+ * 创建日期
+ * 修改者,修改日期,修改内容。
+ */
+
+2. 方法注释
+ 每一个方法都要包含 如下格式的注释 包括当前方法的用途,当前方法参数的含义,当前方法返回值的内容和抛出异常的列表。
+ /**
+ *
+ * 方法的一句话概述
+ * 方法详述(简单方法可不必详述)
+ * @param s 说明参数含义
+ * @return 说明返回值含义
+ * @throws IOException 说明发生此异常的条件
+ * @throws NullPointerException 说明发生此异常的条件
+ */
+
+3. 类成员变量和常量注释
+ 成员变量和常量需要使用`java doc`形式的注释,以说明当前变量或常量的含义
+ /**
+ * XXXX含义
+ */
+
+4. 其他注释
+ 方法内部的注释 如果需要多行 使用/*…… */形式,如果为单行是用//……形式的注释。
+ 不要再方法内部使用 java doc 形式的注释“/**……*/”
+
+代码风格
+---
+
+1. 缩进
+ 除了换行符之外,ASCII空格(0x20)是唯一合法的空格字符。这意味着
+ 不允许使用`Tab`进行缩进,应该使用空格进行缩进,推荐缩进为4个空格
+ `Eclipse`中将`Tab`替换为4个空格的设置方法(很多人都习惯直接按4次空格,感觉不设置习惯了也挺好)
+ - 代码设置
+ `Window->Preferences->General->Editors->Text Editors->`勾选`Insert spaces for tabs``
+ - XML文件的Tab配置
+ `Window->Preferences->XML->XML Files->Editor>`选择右侧区域的`Indent using spaces`
+
+
+2. 空行
+ 空行将逻辑相关的代码段分隔开,以提高可读性。
+
+ 下列情况应该总是使用空行:
+ - 一个源文件的两个片段之间
+ - 类声明和接口声明之间
+ - 两个方法之间
+ - 方法内的局部变量和方法的第一条语句之间
+ - 一个方法内的两个逻辑段之间,用以提高可读性
+
+ 通常在 变量声明区域之后要用空行分隔,常量声明区域之后要有空行分隔,方法声明之前要有空行分隔。
+
+3. 方法
+ - 一个方法尽量不要超过15行(可能会有难度,但是尽量不要太多,弄个方法几千行这是绝对不允许的),如果方法太长,说明当前方法业务逻辑已经非常复杂,
+ 那么就需要进行方法拆分,保证每个方法只作一件事。
+ - 不要使用`try catch`处理业务逻辑!!!!
+
+4. 参数和返回值
+ - 一个方法的参数尽可能的不要超过4个(根据情况可能也会有些难度)
+ - 如果一个方法返回的是一个错误码,请使用异常!!
+ - 尽可能不要使用`null`替代为异常
+
+5. 神秘数字
+ 代码中不允许出现单独的数字,字符!如果需要使用数字或字符,则将它们按照含义封装为静态常量!(`for`语句中除外)
+
+6. 控制语句
+ 判断中如有常量,则应将常量置于判断式的右侧。如:
+ `if (true == isAdmin())...`
+ 尽量不要使用三目条件的嵌套。
+
+ 在`if`、`else`、`for`、`do`和`while`语句中,即使没有语句或者只有一行,也不得省略花括号:
+ ```java
+ if (true){
+ //do something......
+ }
+ ```
+ 不要使用下面的方式:
+ ```java
+ if (true)
+ i = 0; //不要使用这种
+ ```
+
+ 对于循环:
+ //将操作结构保存在临时变量里,减少方法调用次数
+ ```java
+ final int count = products.getCount();
+ while(index < count){
+ // ...
+ }
+ ```
+ 而不是
+ ```java
+ while(index < products.getCount()){
+ //每此都会执行一次getCount()方法,
+ //若此方法耗时则会影响执行效率
+ //而且可能带来同步问题,若有同步需求,请使用同步块或同步方法
+ }
+ ```
+
+
+7. 访问控制
+ 若没有足够理由,不要把实例或类变量声明为公有。
+
+8. 变量赋值
+ 不要使用内嵌(embedded)赋值运算符试图提高运行时的效率,这是编译器的工作。例如:
+ `d = (a = b + c) + r;`
+ 应该写成
+ ```java
+ a = b + c;
+ d = a + r;
+ ```
+
+9. 圆括号的试用
+ 一般而言,在含有多种运算符的表达式中使用圆括号来避免运算符优先级问题,是个好方法。
+ 即使运算符的优先级对你而言可能很清楚,但对其他人未必如此。你不能假设别的程序员和你一样清楚运算符的优先级。
+ 不要这样写:
+ `if (a == b && c == d)`
+ 正确的方式为:
+ `if ((a == b) && (c == d))`
+
+10. 返回值
+ 设法让你的程序结构符合目的。例如:
+ ```java
+ if (booleanExpression) {
+ return true;
+ } else {
+ return false;
+ }
+ ```
+ 应该代之以如下方法:
+ `return booleanExpression`
+
+ 类似地:
+ ```java
+ if (condition) {
+ return x;
+ }
+ return y;
+ ```
+ 应该写做:
+ `return (condition ? x : y);`
+
+11. 条件运算符`?`前的表达式
+ 如果一个包含二元运算符的表达式出现在三元运算符" ? : "的"?"之前,那么应该给表达式添上一对圆括号。例如:
+ `(x >= 0) ? x : -x`
+
+12. 所有未使用的import语句应该被删除。
+
+13. 重载(Overload)方法必须放在一起
+
+14. 非空块中花括号的使用
+ 在非空代码块中使用花括号时要遵循`K&R`风格`(Kernighan and Ritchie Style):
+ 左花括号({)前不能换行,在其后换行。
+ 在右花括号(})前要有换行。
+
+15. 空代码块中花括号的使用
+ 如果一个代码块是空的,可以直接使用`{}`。除了`if/else-if/else`和`try/catch/finally`这样的多块语句.
+
+16. 列宽
+ 列宽必须为120字符,以下情况可以不遵守列宽限制:
+ 无法限制宽度的内容,比如注释里的长`URL`
+ `package`和`import`语句
+ 注释中需要被粘贴到`Shell`里去执行的命令
+
+17. 枚举
+ 用逗号分割每个枚举变量,并且变量要单独在一行
+ ```java
+ enum Color {
+ RED,
+ GREEN,
+ YELLOW
+ }
+ ```
+
+18. 长整形数字
+ 长整型数字必须使用大写字母`L`结尾,不能使用小写字母`l`,以便和数字1进行区分。例如使用3000000000L而不是3000000000l
+
+
+开发格式统一
+---
+
+1. Eclipse
+ `Windows -> Preferences -> Java -> Code Style`
+ 然后选择`Import`导入相应的`Clean Up`、`Code Templates`、`Formatter`等XML文件。
+ 如果不需要Copyright信息,想要自定义的,可以不导入Code Templates。
+
+2. IDEA
+ `File -> Import Settings`选择下载链接中的`IDEA_Style.jar`文件,
+ 可以看到两个选项,只需代码风格的,可以仅选择`Code style schemes`,
+ 如果需要默认的`Copyright`信息,选择`Default Project settings`。
+
+
+代码严谨性要求
+---
+
+1. `ArrayList`通过`get`方法使用下标获取元素,如果使用的下标不在`ArrayList`大小范围内,将产生`java.lang.IndexOutOfBoundsException`的异常,导致`app`出现`Crash`。
+
+2. 方法中存在`return null`返回对象直接进行方法调用隐患, 在使用时需要先判断是否为`null`,一般尽量不要在方法中直接`return null`,最好用异常代替。
+
+3. 销毁`Dialog`前是否`isShowing`未判断隐患
+ 调用`Android.app.Dialog.cancel()`方法前,如果这个`dialog`不处于`showing`状态时,会抛出`java.lang.IllegalArgumentException`的异常,导致`app`出现`Crash`。
+
+4. 使用`String.split`结果未判断长度隐患
+ 在使用`String.split`得到的结果数组前,未对数组进行长度检查,取字段的时候可能发生越界而导致`Crash`。
+ ```java
+ String source = "
";
+ String[] infos = source.split("
");
+ if(0 < infos.length){
+ String poiName = infos[0];
+ }
+ ```
+
+
+
+
+---
+
+- 邮箱 :charon.chui@gmail.com
+- Good Luck!
\ No newline at end of file
diff --git "a/Android\345\237\272\347\241\200/Ant\346\211\223\345\214\205.md" "b/BasicKnowledge/Ant\346\211\223\345\214\205.md"
similarity index 59%
rename from "Android\345\237\272\347\241\200/Ant\346\211\223\345\214\205.md"
rename to "BasicKnowledge/Ant\346\211\223\345\214\205.md"
index 4c957d63..16c5733e 100644
--- "a/Android\345\237\272\347\241\200/Ant\346\211\223\345\214\205.md"
+++ "b/BasicKnowledge/Ant\346\211\223\345\214\205.md"
@@ -2,16 +2,14 @@ Ant打包
===
使用步骤:
-1. 对于已经存在的工程需要利用`Ant`命令更新一下:
- ```
- android update project -n Test -p D:/workspace/Test -s -t 1
- ```
- -n (name) 后面跟的是这个工程的名子
- -p (path)后面跟的是这个工程的目录路径
- -t (target)后面是当前共有的`SDK`版本。表明我们的*目标版本*(如果有了`project.properties`就不用再跟`target`这个参数了).
- `android list target`这样就能够列出来所有的sdk版本
+1. 对于已经存在的工程需要利用`Ant`命令更新一下:
+ `android update project -n Test -p D:/workspace/Test -s -t 1`
+ -n (name) 后面跟的是这个工程的名子
+ -p (path)后面跟的是这个工程的目录路径
+ -t (target)后面是当前共有的`SDK`版本。表明我们的*目标版本*(如果有了`project.properties`就不用再跟`target`这个参数了).
+ `android list target`这样就能够列出来所有的sdk版本
-2. 将签名文件keystore复制到工程根目录下,并且在根目录下新建`ant.properties`内容如下(配置签名文件):
+2. 将签名文件keystore复制到工程根目录下,并且在根目录下新建`ant.properties`内容如下(配置签名文件):
```
key.store=keystore.keystore //把签名放到根目录中
key.alias=tencent
@@ -20,17 +18,19 @@ Ant打包
```
3. 刷新工程
- 在`eclipse`中的`Ant`视图中右键`add build files`选择工程中的`build.xml`,选择最下面的release或者是debug,注意release是生成带签名的apk包.生成的apk在bin目录中,名字为工程名-release.apk.
+ 在`eclipse`中的`Ant`视图中右键`add build files`选择工程中的`build.xml`,选择最下面的`release`或者是`debug`,
+ 注意`release`是生成带签名的`apk`包.生成的apk在`bin`目录中,名字为工程名`-release.apk`.
-4. 常见错误:
- 有时候在用ant打包的时候会报一些错误,一般按照错误的提示进行修改即可,如文件的非法字符等。
+4. 常见错误:
+ 有时候在用`ant`打包的时候会报一些错误,一般按照错误的提示进行修改即可,如文件的非法字符等。
```java
Error occurred during initialization of VM
Could not reserve enough space for object heap
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
```
- 如果发现以上错误,就是说明栈内存不足了,一种是内存设置的太小,还有一种情况就是你设置的内存大小已经超过了当前系统限制的大小。打开`D:\Java\adt-bundle-windows\sdk\build-tools\android-4.4\dx.bat`将`set defaultXmx=-Xmx1024M`改为`set defaultXmx=-Xmx512M`即可。
+ 如果发现以上错误,就是说明栈内存不足了,一种是内存设置的太小,还有一种情况就是你设置的内存大小已经超过了当前系统限制的大小。
+ 打开`D:\Java\adt-bundle-windows\sdk\build-tools\android-4.4\dx.bat`将`set defaultXmx=-Xmx1024M`改为`set defaultXmx=-Xmx512M`即可。
---
diff --git "a/Android\345\237\272\347\241\200/Bitmap\344\274\230\345\214\226.md" "b/BasicKnowledge/Bitmap\344\274\230\345\214\226.md"
similarity index 69%
rename from "Android\345\237\272\347\241\200/Bitmap\344\274\230\345\214\226.md"
rename to "BasicKnowledge/Bitmap\344\274\230\345\214\226.md"
index 5bffef38..42b7954b 100644
--- "a/Android\345\237\272\347\241\200/Bitmap\344\274\230\345\214\226.md"
+++ "b/BasicKnowledge/Bitmap\344\274\230\345\214\226.md"
@@ -1,11 +1,15 @@
Bitmap优化
===
-1. 一个进程的内存可以由2个部分组成:`native和dalvik`,`dalvik`就是我们平常说的`java`堆,我们创建的对象是在这里面分配的,而`bitmap`是直接在`native`上分配的。
-一旦内存分配给`Java`后,以后这块内存即使释放后,也只能给`Java`的使用,所以如果`Java`突然占用了一个大块内存,即使很快释放了,`C`能用的内存也是16M减去`Java`最大占用的内存数。
-而`Bitmap`的生成是通过`malloc`进行内存分配的,占用的是C的内存,这个也就说明了,上述的4MBitmap无法生成的原因,因为在13M被Java用过后,剩下C能用的只有3M了。
+1. 一个进程的内存可以由2个部分组成:`native和dalvik`
+ `dalvik`就是我们平常说的`java`堆,我们创建的对象是在这里面分配的,而`bitmap`是直接在`native`上分配的。
+ 一旦内存分配给`Java`后,以后这块内存即使释放后,也只能给`Java`使用,所以如果`Java`突然占用了一个大块内存,
+ 即使很快释放了,`C`能用的内存也是16M减去`Java`最大占用的内存数。
+ 而`Bitmap`的生成是通过`malloc`进行内存分配的,占用的是`C`的内存,这个也就说明了,有时候`4MBitmap`无法生成的原因,
+ 因为在`13M`被`Java`用过后,剩下`C`能用的只有`3M`了。
-2. 在`Android`应用里,最耗费内存的就是图片资源。而且在`Android`系统中,读取位图`Bitmap`时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现`OutOfMemory`异常。
+2. 在`Android`应用里,最耗费内存的就是图片资源。
+ 在`Android`系统中,读取位图`Bitmap`时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现`OutOfMemory`异常。
3. 及时回收Bitmap的内存
```java
@@ -19,7 +23,8 @@ Bitmap优化
```
4. 捕获异常
- 在实例化`Bitmap`的代码中,一定要对`OutOfMemory`异常进行捕获。下面对初始化`Bitmap`对象过程中可能发生的`OutOfMemory`异常进行了捕获。如果发生了异常,应用不会崩溃,而是得到了一个默认的图片。
+ 在实例化`Bitmap`的代码中,一定要对`OutOfMemory`异常进行捕获。下面对初始化`Bitmap`对象过程中可能发生的`OutOfMemory`异常进行了捕获。
+ 如果发生了异常,应用不会崩溃,而是得到了一个默认的图片。
```java
Bitmap bitmap = null;
try {
@@ -33,14 +38,17 @@ Bitmap优化
return defaultBitmapMap;
}
```
+
5. 缓存通用的Bitmap对象
6. 压缩图片
如果图片像素过大可以将图片缩小,以减少载入图片过程中的内存的使用,避免异常发生。
-使用`BitmapFactory.Options.inSampleSize`就可以缩小图片。属性值`inSampleSize`表示缩略图大小为原始图片大小的几分之一。即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片的大小就为原始大小的1/4。
-如果知道图片的像素过大,就可以对其进行缩小。那么如何才知道图片过大呢?
-使用`BitmapFactory.Options`设置`inJustDecodeBounds`为`true`后,并不会真正的分配空间,即解码出来的`Bitmap`为`null`,但是可计算出原始图片的宽度和高度,即`options.outWidth`和`options.outHeight`。
-通过这两个值,就可以知道图片是否过大了。
+ 使用`BitmapFactory.Options.inSampleSize`就可以缩小图片。属性值`inSampleSize`表示缩略图大小为原始图片大小的几分之一。
+ 即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片的大小就为原始大小的1/4。
+ 如果知道图片的像素过大,就可以对其进行缩小。那么如何才知道图片过大呢?
+ 使用`BitmapFactory.Options`设置`inJustDecodeBounds`为`true`后,并不会真正的分配空间,即解码出来的`Bitmap`为`null`,
+ 但是可计算出原始图片的宽度和高度,即`options.outWidth`和`options.outHeight`。
+ 通过这两个值,就可以知道图片是否过大了。
```java
BitmapFactory.Options opts = new BitmapFactory.Options();
// 设置inJustDecodeBounds为true
@@ -50,7 +58,7 @@ Bitmap优化
// 打印出图片的宽和高
Log.d("example", opts.outWidth + "," + opts.outHeight);
```
- 在实际项目中,可以利用上面的代码,先获取图片真实的宽度和高度,然后判断是否需要跑缩小。如果不需要缩小,设置inSampleSize的值为1。如果需要缩小,则动态计算并设置inSampleSize的值,对图片进行缩小。需要注意的是,在下次使用BitmapFactory的decodeFile()等方法实例化Bitmap对象前,别忘记将opts.inJustDecodeBound设置回false。否则获取的bitmap对象还是null。
+ 在实际项目中,可以利用上面的代码,先获取图片真实的宽度和高度,然后判断是否需要缩小。如果不需要缩小,设置inSampleSize的值为1。如果需要缩小,则动态计算并设置inSampleSize的值,对图片进行缩小。需要注意的是,在下次使用BitmapFactory的decodeFile()等方法实例化Bitmap对象前,别忘记将opts.inJustDecodeBound设置回false。否则获取的bitmap对象还是null。
以从Gallery获取一个图片为例讲解缩放:
```java
@@ -126,4 +134,4 @@ Bitmap优化
---
- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
+- Good Luck!
diff --git "a/Android\345\237\272\347\241\200/Fragment\344\270\223\351\242\230.md" "b/BasicKnowledge/Fragment\344\270\223\351\242\230.md"
similarity index 66%
rename from "Android\345\237\272\347\241\200/Fragment\344\270\223\351\242\230.md"
rename to "BasicKnowledge/Fragment\344\270\223\351\242\230.md"
index a05b5af2..81ceb228 100644
--- "a/Android\345\237\272\347\241\200/Fragment\344\270\223\351\242\230.md"
+++ "b/BasicKnowledge/Fragment\344\270\223\351\242\230.md"
@@ -1,28 +1,34 @@
Fragment专题
===
-##简介
+## 简介
-A Fragment is a piece of an application's user interface or behavior that can be placed in an Activity. Interaction with fragments is done through FragmentManager,
+A Fragment is a piece of an application's user interface or behavior that can be placed in an Activity.
+Interaction with fragments is done through FragmentManager,
which can be obtained via Activity.getFragmentManager() and Fragment.getFragmentManager().
-The Fragment class can be used many ways to achieve a wide variety of results. In its core, it represents a particular operation or interface that is running within a larger Activity.
-A Fragment is closely tied to the Activity it is in, and can not be used apart from one. Though Fragment defines its own lifecycle, that lifecycle is dependent on its activity: if the activity is stopped,
+The Fragment class can be used many ways to achieve a wide variety of results.
+In its core, it represents a particular operation or interface that is running within a larger Activity.
+A Fragment is closely tied to the Activity it is in, and can not be used apart from one.
+Though Fragment defines its own lifecycle, that lifecycle is dependent on its activity: if the activity is stopped,
no fragments inside of it can be started; when the activity is destroyed, all fragments will be destroyed.
-All subclasses of Fragment must include a public no-argument constructor. The framework will often re-instantiate a fragment class when needed, in particular during state restore,
-and needs to be able to find this constructor to instantiate it. If the no-argument constructor is not available, a runtime exception will occur in some cases during state restore.
+All subclasses of Fragment must include a public no-argument constructor.
+The framework will often re-instantiate a fragment class when needed, in particular during state restore,
+and needs to be able to find this constructor to instantiate it.
+If the no-argument constructor is not available, a runtime exception will occur in some cases during state restore.
-##生命周期
+## 生命周期
-`onAttach()`(`Fragment`被绑定到`Activity`时调用) ---> `onCreate()`(`Fragment`创建) --> `onCreateView()`(创建和`Fragment`关联的`View Hierarchy`时调用) --> `onActivityCreated()`(`Activity`的`onCreate()`方法返回时调用)
+`onAttach()`(`Fragment`被绑定到`Activity`时调用) ---> `onCreate()`(`Fragment`创建) -->
+`onCreateView()`(创建和`Fragment`关联的`View Hierarchy`时调用) --> `onActivityCreated()`(`Activity`的`onCreate()`方法返回时调用)
--> `onStart()` --> `onResume()` --> `onPause()` --> `onStop()` --> `onDestroyView()`当和`Fragment`关联的`view hierarchy`正在被移除时调用.
--> `onDestroy()`(`Activity`的`onDestroy`执行后的回调), --> `onDetach()`(当`Fragment`从`Activity`解除关联时被调用)

-##使用
+## 使用
1. 布局添加
```xml
@@ -55,12 +61,14 @@ and needs to be able to find this constructor to instantiate it. If the no-argum
}
}
```
- **每一个fragment 都需要一个唯一的标识,如果activity重启,系统可以用来恢复fragment(并且你也可以用来捕获fragment 来处理事务,例如移除它.)**
- 有3 种方法来为一个`fragment` 提供一个标识:
- 1. 为`android:id`属性提供一个唯一ID.
- 2. 为`android:tag`属性提供一个唯一字符串.
- 3. 如果以上2个你都没有提供,系统使用容器`view`的`ID`.
-
+ **每一个fragment 都需要一个唯一的标识,如果activity重启,系统可以用来恢复fragment(并且你也可以用来捕获fragment 来处理事务,例如移除它.)**
+
+ 有3 种方法来为一个`fragment` 提供一个标识:
+
+ 1. 为`android:id`属性提供一个唯一ID.
+ 2. 为`android:tag`属性提供一个唯一字符串.
+ 3. 如果以上2个你都没有提供,系统使用容器`view`的`ID`.
+
```java
public static ArticleFragment newInstance(int index) {
ArticleFragment f = new ArticleFragment();
@@ -109,19 +117,19 @@ and needs to be able to find this constructor to instantiate it. If the no-argum
}
```
-##管理Fragment
+## 管理Fragment
-要在activity 中管理fragment,需要使用FragmentManager. 通过调用activity 的getFragmentManager()取得它的实例.
-可以通过FragmentManager 做一些事情, 包括:
+要在`activity`中管理`fragment`,需要使用`FragmentManager`. 通过调用`activity`的`getFragmentManager()`取得它的实例.
+可以通过`FragmentManager`做一些事情, 包括:
1. 使用findFragmentById() (用于在activitylayout 中提供一个UI 的fragment)或findFragmentByTag()(适用于有或没有UI 的fragment)获取activity 中存在的fragment
2. 将fragment 从后台堆栈中弹出, 使用popBackStack() (模拟用户按下BACK 命令).
3. 使用addOnBackStackChangeListener()注册一个监听后台堆栈变化的listener.
## 处理Fragment事务
-每一个事务都是同时要执行的一套变化.可以在一个给定的事务中设置你想执行的所有变化,使用诸如add(), remove(),和replace().然后, 要给activity 应用事务, 必须调用commit().在调用commit()之前,
-你可能想调用addToBackStack(),将事务添加到一个fragment 事务的backstack. 这个
-
+每一个事务都是同时要执行的一套变化.可以在一个给定的事务中设置你想执行的所有变化,使用诸如`add()`, `remove()`,和`replace()`.
+要给`activity`应用事务, 必须调用`commit()`.在调用`commit()`之前,
+你可能想调用`addToBackStack()`,将事务添加到一个fragment 事务的`backstack`
将一个fragment 替换为另一个, 并在后台堆栈中保留之前的状态:
```java
// Create new fragment and transaction
@@ -139,7 +147,8 @@ transaction.commit();
## Fragment真正的onPause以及onResume
-`Fragment`虽然有`onResume()`和`onPause()`方法,但是这两个方法是`Activity`的方法调用时机也与`Activity`相同,和`ViewPager`搭配使用这个方法就很鸡肋了,根本不是你想要的效果,这里介绍一种方法。
+`Fragment`虽然有`onResume()`和`onPause()`方法,但是这两个方法是`Activity`的方法调用时机也与`Activity`相同,
+和`ViewPager`搭配使用这个方法就很鸡肋了,根本不是你想要的效果,这里介绍一种方法。
```java
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
@@ -152,9 +161,10 @@ public void setUserVisibleHint(boolean isVisibleToUser) {
}
```
-通过阅读`ViewPager`和`PageAdapter`相关的代码,切换`Fragment`实际上就是通过设置`setUserVisibleHint`和`setMenuVisibility`来实现的,调用这个方法时并不会释放掉`Fragment`(即不会执行onDestoryView)。
+通过阅读`ViewPager`和`PageAdapter`相关的代码,切换`Fragment`实际上就是通过设置`setUserVisibleHint`和`setMenuVisibility`来实现的,
+调用这个方法时并不会释放掉`Fragment`(即不会执行`onDestoryView`)。
-##Fragment与ViewPager搭配
+## Fragment与ViewPager搭配
`FragmentStatePagerAdapter`,会自动保存和恢复`Fragment`。
```java
import android.support.v4.app.Fragment;
@@ -225,7 +235,6 @@ public class ScreenSlidePagerActivity extends FragmentActivity {
如何给`ViewPager`切换时增加动画.
```java
ViewPager mPager = (ViewPager) findViewById(R.id.pager);
-...
mPager.setPageTransformer(true, new DepthPageTransformer ());
```
@@ -268,7 +277,61 @@ public class DepthPageTransformer implements ViewPager.PageTransformer {
}
```
+
+## 判断首次进入`Fragment`的时机
+
+上面介绍了`Fragment`真正的`onPause`及`onResume`方法。也就是说`Fragment`和`ViewPager`一起用时,由于`ViewPager`的缓存机制,在打开一个`Fragment`时,它旁边的几个 `Fragment`其实也已经被创建了,如果我们是在`Fragment`的`onCreat()`或者`onCreateView()`里去跟服务器交互,下载界面数据,那么这时这些已经被创建的`Fragment`,就都会出现在后台下载数据的情况了。所以我们通常需要在`setUserVisibleHint()`里去判断当前`Fragment`是否可见,可见时再去下载数据,但是这样还是会出现一个问题,就是每次可见时都会重复去下载数据,即使我们在`setUserVisibleHint()`做了很多判断,实现了可见时加载并且只有第一次可见时才加载,可能还是会遇到其他问题。比如说,我下载完数据就直接需要对`ui`进行操作,将数据展示出来,但有时却报了`ui`控件`null`异常,这是因为`setUserVisibleHint()`有可能在`onCreateView()`创建`view`之前调用,而且数据加载时间很短,这就可能出现`null` 异常了,那么我们还需要再去做些判断,保证在数据下载完后`ui`控件已经创建完成。我最近就遇到了这个问题,想要在第一次进入
+某个`fragment`的时候在某个`view`上面显示一个`popunwindow`,我想到的就是在`setUserVisibleHint()`方法中去显示,但是发现有时候对应的`view`还没初始化。
+下面就是如何判断首次进入`Fragment`的时机。
+
+```
+public abstract class BaseFragment extends Fragment {
+ private View mRootView;
+ protected boolean isFirstVisible = true;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ isFirstVisible = true;
+ mRootView = null;
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ if (mRootView == null) {
+ mRootView = view;
+ if (getUserVisibleHint()) {
+ if (isFirstVisible) {
+ onFragmentFirstVisible();
+ isFirstVisible = false;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setUserVisibleHint(boolean isVisibleToUser) {
+ super.setUserVisibleHint(isVisibleToUser);
+ if (mRootView == null) {
+ return;
+ }
+ if (isFirstVisible && isVisibleToUser) {
+ onFragmentFirstVisible();
+ isFirstVisible = false;
+ }
+ }
+
+ protected void onFragmentFirstVisible() {
+ // 首次进入改fragment的时机
+ }
+}
+
+```
+
+
+
---
- 邮箱 :charon.chui@gmail.com
-- Good Luck!
\ No newline at end of file
+- Good Luck!
diff --git "a/Android\345\237\272\347\241\200/Home\351\224\256\347\233\221\345\220\254.md" "b/BasicKnowledge/Home\351\224\256\347\233\221\345\220\254.md"
similarity index 100%
rename from "Android\345\237\272\347\241\200/Home\351\224\256\347\233\221\345\220\254.md"
rename to "BasicKnowledge/Home\351\224\256\347\233\221\345\220\254.md"
diff --git "a/Android\345\237\272\347\241\200/HttpClient\346\211\247\350\241\214Get\345\222\214Post\350\257\267\346\261\202.md" "b/BasicKnowledge/HttpClient\346\211\247\350\241\214Get\345\222\214Post\350\257\267\346\261\202.md"
similarity index 100%
rename from "Android\345\237\272\347\241\200/HttpClient\346\211\247\350\241\214Get\345\222\214Post\350\257\267\346\261\202.md"
rename to "BasicKnowledge/HttpClient\346\211\247\350\241\214Get\345\222\214Post\350\257\267\346\261\202.md"
diff --git "a/BasicKnowledge/JNI_C\350\257\255\350\250\200\345\237\272\347\241\200.md" "b/BasicKnowledge/JNI_C\350\257\255\350\250\200\345\237\272\347\241\200.md"
new file mode 100644
index 00000000..3bd5e206
--- /dev/null
+++ "b/BasicKnowledge/JNI_C\350\257\255\350\250\200\345\237\272\347\241\200.md"
@@ -0,0 +1,467 @@
+JNI_C语言基础
+===
+
+1. JNI(java native interface)
+ `Java`本地开发接口,`JNI`是一个协议,这个协议用来沟通`Java`代码和外部的本地代码(`c/c++`).
+ 通过这个协议`Java`代码就可以调用外部的`c/c++`代码,外部的`c/c++`代码也可以调用java代码,
+ 使用JNI技术,其实就是在Java程序中,调用C语言的函数库中提供的函数,来完成一些Java语言无法完成的任务。由于Java语言和C语言结构完全不相同,因此若想让它们二者交互,则需要制定一系列的规范。
+ JNI就是这组规范,此时 Java只和JNI交互,而由JNI去和C语言交互。
+
+ JNI技术分为两部分:Java端和C语言端。且以Java端为主导。
+ - 首先,Java程序员在Java端定义一些native方法,并将这些方法以C语言头文件的方式提供给C程序员。
+ - 然后,C程序员使用C语言,来实现Java程序员提供的头文件中定义的函数。
+ - 接着,C程序员将函数打包成一个库文件,并将库文件交给Java程序员。
+ - 最后,Java程序员在Java程序中导入库文件,然后调用native方法。
+ 在Java程序执行的时候,若在某个类中调用了native方法,则虚拟机会通过JNI来转调用库文件中的C语言代码。提示:C代码最终是在Linux进程中执行的,而不是在虚拟机中。
+
+2. 为什么要用JNI
+ - 首先,Java语言提供的类库无法满足要求(驱动开发 wifi等),且在数学运算,实时渲染的游戏上,音视频处理等方面上与C/C++相比效率稍低。
+ - 然后,Java语言无法直接操作硬件,C/C++代码不仅能操作硬件而且还能发挥硬件最佳性能。
+ - 接着,使用Java调用本地的C/C++代码所写的库,省去了重复开发的麻烦,并且可以利用很多开源的库提高程序效率。Opencore
+ - 接着,特殊的业务场景,java能反编译但是c不能,因此对于一些不想让别人知道的东西可以用c,加密等
+
+3. 怎么用JNI
+ 1. C/C++语言
+ 2. 掌握java jni流程
+ 3. NDK (native develop kits )
+
+4. 指针和指针变量的关系
+ 指针就是地址,地址就是指针
+ 地址就是内存单元的编号
+ 指针变量是存放地址(指针)的变量
+ 指针和指针变量是两个不同的概念
+ 但是要注意: 通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样
+
+ - 未经过初始化的指针变量,不能够直接使用
+ - 指针变量的类型 不能够相互转换
+ - 函数的变量(静态)不能够跨函数访问,失去了函数变量的访问范围(生命周期),因为方法执行完之后会释放内存,所以方法中的变量就没有了,
+ 但是地址值还是能拿到的,因为地址值是内存中真实存在的地址位置
+ - 指针声明的三种方式
+ int * p; //p 是变量的名字, int * 是一个类型,这个变量存放的是int类型变量的地址。
+ int* p int * p int *p
+
+5. *号的三种含义
+ 1. 乘法 3*5
+ 2. 定义指针变量 int * p;
+ 3. 指针运算符,如果p是一个已经定义好的指针变量,则*p表示以p的内容为地址的变量
+
+6. 为什么要使用指针(指针的重要性)
+ 直接访问硬件 (opengl 显卡绘图)
+ 快速传递数据(指针表示地址)
+ 返回一个以上的值(返回一个数组或者结构体的指针)
+ 表示复杂的数据结构(结构体)
+ 方便处理字符串
+ 指针有助于理解面向对象
+
+7. 指针和数组的关系
+ 一维数组的数组名是个指针常量,它存放的是一维数组第一个元素的地址
+ C中数组的定义比较死板,中括号必须放到名字的后面
+ int a[5];
+ printf("%#X\n",&a[0]);
+ printf("%#X\n",&a);
+
+ 如果p是一维数组 则p[i] 等价于 *(p+i),都是得到一维数组中的第i个元素。
+ 在c语言中不会检查角标越界如int a[5]写a[5]不会报错
+
+8. 动态分配内存Malloc
+ ```c
+ 采用malloc在椎内存中申请空间
+ #include //不能省 malloc 是 memory(内存) allocate(分配)的缩写
+ #include
+
+ main(){
+ //malloc() 在堆空间中动态的申请一块连续的内存空间(数组)
+ // 参数: 指定申请的内存空间的大小(字节)
+ // 返回值: 所申请空间的首地址(数组的第一个元素的地址),返回值是Void数据类型
+
+ int* p = (int*) malloc( sizeof(int) ); //因为返回值是一个Void类型,所以要强转
+ *p = 99;
+
+ //free()释放已经分配的内存块
+ //参数: 指定释放哪块内存空间(地址)
+
+ free(p);
+ printf("内容是 %d\n", *p); //上面的free只是释放内存块中的内容,但是打印这个内存块的地址还是能够打印出来的,因为这个内存块的地址是内存上的地址是真实存在的
+ system("pause");
+ }
+
+ 如果动态申请的内存不够用,那么可以继续申请内存
+ 用realloc
+ /*
+ 1\创建数组
+ 2、赋值
+ 3、打印
+ */
+ #include
+ #include
+
+ void printArr(int* arr, int len){
+ int i;
+ for( i = 0 ; i < len; i++){
+ printf("arr[ %d ]= %d\n", i, *(arr+i));
+ }
+
+ }
+
+ main(){
+ printf("请您输入所要创建的数组大小: \n");
+ int len ;
+ scanf("%d", &len); &是取地址符
+
+ //动态数组创建
+ int* arr = (int*) malloc( sizeof(int) * len);
+
+ printf("请您为每个元素赋值: \n");
+
+ int i;
+ for(i = 0; i < len; i++){
+ int temp;
+ scanf("%d", &temp);
+
+ *(arr + i) = temp;
+ }
+
+ //打印
+ printf("数组元素的值为: \n");
+ printArr(arr, len);
+
+ //-----------------------------------------
+
+ printf("请输入增加的元素个数: \n");
+ int count;
+ scanf("%d", &count);
+
+ //更改数组大小
+ //realloc()
+ //参数1: 指定所需修改的数组
+ //参数2: 指定修改后的数组的大小
+ //返回值:修改后数组的首地址 (VOID)
+ arr = (int*) realloc(arr, len + count);
+
+ printf("请为新增加的元素赋值: \n");
+
+ int j;
+ for(j = len; j < len + count; j++){
+ int temp;
+ scanf("%d", &temp);
+
+ *(arr + j) = temp;
+ }
+
+ //打印
+ printf("数组元素的值为: \n");
+ printArr(arr, len + count);
+
+ system("pause");
+ }
+ 或者有个简单的写法
+ main()
+ {
+ int* arr =(int* ) malloc(sizeof(int)*len) ; //动态申请的内存
+ int i=0;
+ for(;i char str[] ={'h','e','l','l','o','\0'};
+ char cc[20] = "heima 15";
+ char cc[20] = {'h','e','i','m','a'};
+
+11. c文件的后缀是.c
+ ```c
+ 示例代码:
+ c中的打印语句中要有类似占位符,在后面的参数对占位符的内容进行声明
+ #include
+ main() {
+ printf("%d\n",sizeof(int)); //sizeof() 得到制定数据类型的长度(占用字节数)参数 接受一个数据类型
+ printf("%d\n",sizeof(char));
+ system("pause");//可以执行命令行中的命令如 system("shutdown -s -t 60");如果不加pause,运行窗口会一闪而过,因为会释放内存,把dos关闭了,所以要加上pause
+ }
+ ```
+
+12. C中的输入输出
+ %d - int
+ %ld – long int
+ %c - char
+ %f - float
+ %lf – double
+ %x – 十六进制输出 int 或者long int 或者short int
+ %#x – 以0x开头 十六进制输出 int 或者long int 或者short int
+ %o - 八进制输出
+ %s – 字符串
+
+13. c语言从键盘输入一个字符串
+ ```c
+ //scanf() 接收键盘输入的数据,参数1: 指定接收的数据的数据类型参数 2: 指定接收的数据存放的位置
+ #include
+ main() {
+ char c[20];
+ scanf("%s", c);
+ printf("%s", c);
+ system("pause");
+ }
+ ```
+
+14. 取地址符 &(能得到一个对象的地址)
+
+15. C中两个数的交换
+ ```c
+ #include
+ void swap(int* i, int* j) {
+ int temp = *i;
+ *i = *j;
+ *j = temp;
+ }
+ main() {
+ int i = 3;
+ int j = 5;
+ swap(&i, &j);
+ printf("%d",i);
+ printf("%d",j);
+ system("pause");
+ }
+ ```
+
+16. C中的for循环
+ ```c
+ #include
+
+ /**
+ 打印输出数组的每一个元素
+ */
+ void printArr(int* arr, int len){
+ int i;
+ for(i=0;i
+ int add(int x,int y){
+ return x+y;
+ }
+ main()
+ {
+ int (*pf)(int x, int y); //定义一个函数的指针,就是讲函数的名字改了,其它的都和函数的定义一样
+ pf = add; //将pf指向add
+ printf("result=%d\n", pf(3,5)); //使用pf
+
+ system("pause");
+ }
+
+ 内存的四个部分 Stack Heap CodeSegment DataSegment
+ 函数是存放到CodeSegment中的,这个函数的地址就是CodeSegment中的这个函数的地址,我们得到函数的地址如果去访问这个地址就相当于调用了这个函数
+ ```
+
+19. 结构体(类似于java中的类)
+ ```c
+ #include
+ struct Student
+ {
+ int age; //4
+ float score; //4
+ long id; //4
+ char sex; //1
+ };
+ int main(void)
+ {
+ struct Student st={80,55.6f,10001,'F'};
+ printf("st.age=%d\n",st.age);
+
+ printf("结构体的长度为%d\n",sizeof(st));//打印出来的结果是16为什么呢? 编译器为了方便起见 做了处理,它将所有的变量的长度都统一成最大的长度
+
+ struct Student* pst = &st;//结构体的指针
+
+ printf("st.age=%d\n",(*pst).age);//(*pst)就是得到结构体,由于*的优先级比较低,通常要用括号括起来。
+
+ printf("age=%d\n",pst->age);//这一行是上一行的简单写法,pst->age 在计算机内部会被转换为 (*pst).age pst->age的含义: pst所指向的结构体变量中的age这个成员
+ system("pause");
+ }
+ ```
+ 结构体的三种写法
+ 第一种
+ ```c
+ struct Student
+ {
+ int age;
+ float score;
+ char sex;
+ }
+ ```
+ 第二种
+ ```c
+ struct Student2
+ {
+ int age;
+ float score;
+ char sex;
+ } st2;//相当于java中直接弄了一个对象
+ ```
+ 第三种
+ ```c
+ struct
+ {
+ int age;
+ float score;
+ char sex;
+ } st3;
+ ```
+
+20. Union联合体
+ ```c
+ #include
+ main() {
+ struct date { int year, month, day; }today;
+ union { long i; int k; char ii; double d; } mix;
+
+ printf("date:%d\n",sizeof(struct date));
+ printf("mix:%d\n",sizeof(mix));
+ mix.i = 33;
+ mix.ii = 'a';
+ printf("i=%d\n",mix.i); //结果是96,因为联合体是一个公用的内存空间,在存ii的时候将i的值给覆盖了
+ //110100000101
+
+ system("pause");
+ }
+ 联合体是一个公用的内存空间,联合体长度为: 占有字节数最大的元素的长度(字节数)
+ ```
+
+21. 枚举
+ ```c
+ enum WeekDay {
+ Monday=8,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
+ };//这里一定要加分号
+
+ int main(void)
+ {
+ enum WeekDay day = Sunday;
+ printf("%d\n",day);//打印出来是14,因为是从8开始往后逐个加1
+ system("pause");
+ return 0;
+ }
+ 默认的情况是从0开始往后递加
+ ```
+
+22. typedef
+ 定义别名
+ 声明自定义数据类型,配合各种原有数据类型来达到简化编程的目的的类型定义关键字。
+ ```c
+ typedef int haha; //定义数据类型的别名.
+ int main(void)
+ {
+ haha i = 3;这里haha就相当于int
+ printf("i=%d\n",i);
+ }
+ ```
+ 每一个指针占四个字节
+
+23. 多级指针
+ ```c
+ #include
+ main() {
+ int i = 88;
+ int* p = &i;
+ int** q = &p; //指针的指针前面要加两个*
+ int*** r = &q;
+ printf("i=%d\n",***r);
+ system("pause");
+ }
+ ```
+
+C语言常见术语:
+库函数:
+- 为了代码重用,在C语言中提供了一些常用的、用于执行一些标准任务(如输入/出)的函数,这些函数事先被编译,并生成目标代码,然后将生成的目标代码打包成一个库文件,
+以供再次使用。 库文件中的函数被称为库函数,库文件被称为函数库。
+通过头文件的方式 把函数库里面所有的函数暴露 .h
+- 在Windows中C语言库函数中的目标代码都是以.obj为后缀的,Linux中是以 .o为后缀。
+提示:单个目标代码是无法直接执行的,目标代码在运行之前需要使用连接程序将目标代码和其他库函数连接在一起后生成可执行的文件。Windows ->.exe .dll
+Linux -> .so 动态库
+ .a 静态库
+头文件:
+- 头文件中存放的是对某个库中所定义的函数、宏、类型、全局变量等进行声明,它类似于一份仓库清单。若用户程序中需要使用某个库中的函数,
+ 则只需要将该库所对应的头文件include到程序中即可。
+- 头文件中定义的是库中所有函数的函数原型。而函数的具体实现则是在库文件中。
+- 简单的说:头文件是给编译器用的,库文件是给连接器用的。
+- 在连接器连接程序时,会依据用户程序中导入的头文件,将对应的库函数导入到程序中。头文件以.h为后缀名。
+函数库:
+- 动态库:在编译用户程序时不会将用户程序内使用的库函数连接到用户程序的目标代码中,只有在运行时,且用户程序执行到相关函数时才会调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。 .so 动态库
+- 静态库:在编译用户程序时会将其内使用的库函数连接到目标代码中,程序运行时不再需要动态库。使用静态库生成可执行文件比较大。
+在Linux中:
+- 静态库命名一般为:lib+库名+.a 。
+- 如:libcxy.a 其中lib说明此文件是一个库文件,cxy是库的名称,.a说明是静态的。
+- 动态库命名一般为:lib+库名+.so 。.so说明是动态的。
+Windows 下的动态库 .dll
+
+---
+
+- 邮箱 :charon.chui@gmail.com
+- Good Luck!
\ No newline at end of file
diff --git "a/BasicKnowledge/JNI\345\237\272\347\241\200.md" "b/BasicKnowledge/JNI\345\237\272\347\241\200.md"
new file mode 100644
index 00000000..700f59a8
--- /dev/null
+++ "b/BasicKnowledge/JNI\345\237\272\347\241\200.md"
@@ -0,0 +1,410 @@
+JNI基础
+===
+
+1. 将java中的字符串转换成C中字符串的工具方法
+ ```c
+ char* Jstring2CStr(JNIEnv* env, jstring jstr){
+ char* rtn = NULL;
+ jclass clsstring = (*env)->FindClass(env,"java/lang/String");
+ jstring strencode = (*env)->NewStringUTF(env,"GB2312");
+ jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
+ jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");
+ jsize alen = (*env)->GetArrayLength(env,barr);
+ jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
+ if(alen > 0)
+ {
+ rtn = (char*)malloc(alen+1); //"\0"
+ memcpy(rtn,ba,alen);
+ rtn[alen]=0;
+ }
+ (*env)->ReleaseByteArrayElements(env,barr,ba,0); //
+ return rtn;
+ }
+ ```
+
+2. 程序被运行要经历两个步骤(1.编译 2.链接)
+ 编译就是将源文件编译成二进制代码,而链接则是将二进制代码转换成可执行的文件如.exe等头文件.(函数的声明,函数的清单文件)作用: 给编译器看的.
+ 库函数: 头文件里面函数的实现.
+ 作用:给连接器看的.
+
+3. jni开发的常见错误:
+ 错误1: 忘记编写android.mk文件 unknown file: ./jni/Android.mk
+ Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk
+ /cygdrive/c/android-ndk-r7b/build/core/add-application.mk:133: Android NDK: Aborting... 。 停止。
+
+ 错误2: ndk-build 没有任何反应.
+ 忘记配置android.mk脚本
+
+ 错误3: $ ndk-build jni/Android.mk:4: 遗漏分隔符 。 停止。
+中文的回车或者换行
+
+ 错误4:java.lang.UnsatisfiedLinkError: hello
+ 忘记加载了c代码的.so库 或者 函数的签名不正确,没有找到与之对应的c代码
+
+ 错误5:07-30 java.lang.UnsatisfiedLinkError: Library Hel1o not found
+ 没有找到对应的c代码库
+
+ 错误6: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
+ 07-30 11:53:17.898: INFO/DEBUG(31): Build fingerprint:
+ 'generic/sdk/generic/:2.2/FRF91/43546:eng/test-keys'
+ c代码里面有严重的逻辑错误,产生内存的泄露.
+
+ 错误7:
+ make: *** [obj/local/armeabi/objs/Hello/Hello.o] Error 1
+ 编译的时候 程序出现了问题,c语言的语法有问题
+ c语言代码编译错误的时候 先去解决第一个错误.
+
+4. Java调用JNI的前提
+ 开发所使用的电脑(windows系统, x86的CPU)
+ 目标代码: android手机上运行的.( linux系统, arm的CPU)
+ 所以我们要模拟手机的系统,手机的处理器,生成手机上可以运行的二进制代码这就要用到交叉编译;
+ 根据运行的设备的不同,可以将cpu分为:
+ - arm结构 :主要在移动手持、嵌入式设备上。
+ - x86结构 : 主要在台式机、笔记本上使用。如Intel和AMD的CPU 。
+ 交叉编译: 在一种操作系统平台或者cpu平台下 编译生成 另外一个平台(cpu)可以运行的二进制代码.(使用NDK中的ndk-build命令)
+
+
+- 工具一: 交叉编译的工具链: NDK
+ NDK全称:Native Development Kit 。
+ - NDK是一系列工具的集合,它有很多作用。
+ - 首先,NDK可以帮助开发者快速开发C(或C++)的动态库。
+ - 其次,NDK集成了交叉编译器。使用NDK,我们可以将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
+
+ NDK工具是提供给Linux系统用的(随着版本的升级也可以直接在Windows下使用,但是现在仍不完善有bug),
+ 所以要在windows下使用ndk的工具,必须要提供一个工具(linux环境的模拟器)
+
+- 工具二: cygwin(windows下linux系统环境的模拟器, 主要是为了能够运行ndk的工具)
+ 安装 devel shell
+ 
+ linux 特点:所有的设备 硬件 都是以文件的方式定义的.
+ 安装完后进入`cygwin`打印`make -v`命令如果能打印出`GNU Make ...`就说明安装木问题了。
+
+- 工具三: cdt(c/c++ develop tools) eclipse 的一个插件 用来让c\c++代码 语法高亮显示.
+ adt(android develop tools)
+
+- 工具四:
+ 为了不用每次使用ndk-build命令都要进入到ndk的安装目录,这里要进行Path变量的配置。
+ 配置cygwin的环境变量: 在cygwin安装目录,etc目录,profile的文件 32行 添加ndk工具所在的目录.
+ `PATH="/usr/local/bin:/usr/bin:/cygdrive/d/android-ndk-r7b:${PATH}"`在这个后面加上:ndk-build的路径(注意:在linux中路径的分隔符不是分号而是冒号),
+ 改成这样
+ `PATH="/usr/local/bin:/usr/bin:${PATH}:/cygdrive/d/android-ndk-r7b"`//注意这里的路径是在linux系统下的ndk路径而不是windows下的路径,/cygdrive/d/是在linux下看到的d盘。
+
+### JNI开发步骤:
+
+1. 创建一个android工程
+2. JAVA代码中写声明native 方法 public native String helloFromJNI();
+3. 用javah工具生成头文件
+4. 创建jni目录,引入头文件,根据头文件实现c代码
+5. 编写Android.mk文件
+6. Ndk编译生成动态库
+7. Java代码load 动态库.调用native代码
+
+### JNI开发之Java中调用C代码步骤
+
+1. 在java中定义一个要调用的C的方法(本地方法)
+ //1.定义一个native的方法
+ `public native String helloFromC();`
+
+2. 在工程中新建一个jni文件夹(然后在这个文件夹中写c代码,在C中实现java里面定义的c方法默认的时候是自己手写c的方法名,
+ 但是很麻烦这里要参考七里面提供的方式,用javah编译后,然后拷贝h的头文件到jni文件夹中,在从h文件拷贝方法的名字,然后实现该方法).
+ ```
+ C:\Users\Administrator>javah -help
+ 用法:
+ javah [options]
+ 其中, [options] 包括:
+ -o 输出文件 (只能使用 -d 或 -o 之一)
+ -d 输出目录
+ -v -verbose 启用详细输出
+ -h --help -? 输出此消息
+ -version 输出版本信息
+ -jni 生成 JNI 样式的标头文件 (默认值)
+ -force 始终写入输出文件
+ -classpath