Android内存泄漏、内存溢出及处理

JAVA是垃圾回收语言的一种,开发者无需特意管理内存分配。但是JAVA中还是存在着许多内存泄露的可能性,如果不好好处理内存泄露,会导致APP内存单元无法释放被浪费掉,最终导致内存全部占据堆栈(heap)挤爆进而程序崩溃。

内存泄露

说到内存泄露,就不得不提到内存溢出,这两个比较容易混淆的概念,我们来分析一下。

内存泄露:程序在向系统申请分配内存空间后(new),在使用完毕后未释放。结果导致一直占据该内存单元,我们和程序都无法再使用该内存单元,直到程序结束,这是内存泄露。

内存溢出:程序向系统申请的内存空间超出了系统能给的。比如内存只能分配一个int类型,我却要塞给他一个long类型,系统就出现oom。又比如一车最多能坐5个人,你却非要塞下10个,车就挤爆了。

大量的内存泄露会导致内存溢出(oom)。

6.0设备获取mac地址问题

众所周知,Android 6.0系统,做出许多重大的变化,例如获取获取蓝牙MAC地址,如果使用‘BluetoothAdapter.getAddress()’将返回的是02:00:00:00:00:00 常量,不是真实的蓝牙MAC地址。
看看官方是怎么描述的。为了给用户更多的数据保护,从这个版本开始, Android 移除了通过 WiFi 和蓝牙 API 来在应用程序中可编程的访问本地硬件标示符。现在 WifiInfo.getMacAddress() 和 BluetoothAdapter.getAddress() 方法都将返回 02:00:00:00:00:00 。
注意:在一个运行 Android 6.0 (API 级别 23) 的设备初始化后台的 WiFi 或蓝牙扫描时,操作对于外部设备是可见的,且被赋予一个随机的 MAC 地址。
但是,我们在实际开发中,依旧需要使用 MAC地址,那没有一种‘万能’方法,不管是在6.0,还是在低版本都可以获取到 MAC地址呢?答案是有的!下面就介绍一种解决方法。这种方法获取的WLAN MAC地址。
具体代码如下:
[java] view plain copy
/**

  • 获取Mac地址
    */
    public class MacUtils {
/** 
 * 获取手机的MAC地址 
 *  
 * @return 
 */  
public static String getMac() {  
    String str = "";  
    String macSerial = "";  
    try {  
        Process pp = Runtime.getRuntime().exec(  
                "cat /sys/class/net/wlan0/address ");  
        InputStreamReader ir = new InputStreamReader(pp.getInputStream());  
        LineNumberReader input = new LineNumberReader(ir);  

        for (; null != str;) {  
            str = input.readLine();  
            if (str != null) {  
                macSerial = str.trim();// 去空格  
                break;  
            }  
        }  
    } catch (Exception ex) {  
        ex.printStackTrace();  
    }  
    if (macSerial == null || "".equals(macSerial)) {  
        try {  
            return loadFileAsString("/sys/class/net/eth0/address")  
                    .toUpperCase().substring(0, 17);  
        } catch (Exception e) {  
            e.printStackTrace();  

        }  

    }  
    return macSerial;  
}  

public static String loadFileAsString(String fileName) throws Exception {  
    FileReader reader = new FileReader(fileName);  
    String text = loadReaderAsString(reader);  
    reader.close();  
    return text;  
}  

public static String loadReaderAsString(Reader reader) throws Exception {  
    StringBuilder builder = new StringBuilder();  
    char[] buffer = new char[4096];  
    int readLength = reader.read(buffer);  
    while (readLength >= 0) {  
        builder.append(buffer, 0, readLength);  
        readLength = reader.read(buffer);  
    }  
    return builder.toString();  
}     

}

经测试,该代码在6.0和4.x版本上都可以获取到真实的MAC地址。
PS:在6.0上需要AndroidManifest.xml在加入以下2个权限,
[java] view plain copy


String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), “bluetooth_address”);
即可解决,获取的是蓝牙的地址。

public static String getBluetoothAddress(Context context) {
String macAddress = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(),
“bluetooth_address”);
} else {
BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
if (bluetooth != null) {
String address = bluetooth.isEnabled() ? bluetooth.getAddress() : null;
if (!TextUtils.isEmpty(address)) {
// Convert the address to lowercase for consistency with the wifi MAC address.
return address.toLowerCase();
} else {
return context.getString(R.string.status_unavailable);
}
}
}
return macAddress;
}

如何实现DialogActivity样式

activity android:name=".megvii.LoadingActivity" android:screenOrientation="portrait" android:theme="@style/DialogTransparentStyle"/

activity中onCreate()中创建一个自定义的progressDialog
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.loading_layout);

init();
netWorkWarranty();
}

Android奇葩bug

java.lang.RuntimeException: Unable to instantiate application com.ztph.mall.ZTPHApplication: java.lang.ClassNotFoundException: Didn’t find class “com.ztph.mall.ZTPHApplication” on path: DexPathList[[zip file “/data/app/com.ztph.mall-1/base.apk”],nativeLibraryDirectories=[/data/app/com.ztph.mall-1/lib/arm64, /data/app/com.ztph.mall-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]
at android.app.LoadedApk.makeApplication(LoadedApk.java:591)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4937)
at android.app.ActivityThread.access$1700(ActivityThread.java:180)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1555)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5791)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:762)
Caused by: java.lang.ClassNotFoundException: Didn’t find class “com.ztph.mall.ZTPHApplication” on path: DexPathList[[zip file “/data/app/com.ztph.mall-1/base.apk”],nativeLibraryDirectories=[/data/app/com.ztph.mall-1/lib/arm64, /data/app/com.ztph.mall-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at android.app.Instrumentation.newApplication(Instrumentation.java:986)
at android.app.LoadedApk.makeApplication(LoadedApk.java:586)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4937)
at android.app.ActivityThread.access$1700(ActivityThread.java:180)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1555)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5791)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:762)
Suppressed: java.lang.ClassNotFoundException: com.ztph.mall.ZTPHApplication
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
… 12 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available

Java正则表达式中的匹配模式

前言:最开始看的是这篇文章“Java正则表达中Greedy Reluctant Possessive 的区别”来进行学习理解,但是发现这篇文章说得并不是很清楚,经过最终领悟,现在将自己的理解作为笔记分享出来。

从Java的官方文档中我们可以看到,正则表达式表示数量词的符号有三套,分别是Greedy(贪婪的)、Reluctant(勉强的)和Possessive(独占的)。

通过官方文档对比我们可以看出规律:
贪婪模式即在X字符后面增加限定符号如:?、*、+、{n}、{n,}、{n,m}

懒惰模式是在带有限定符号:?、*、+、{n}、{n,}、{n,m}的后面,增加”?”,如:X??

独占模式也叫侵占模式,是在带有限定符号:?、*、+、{n}、{n,}、{n,m}的后面,增加”+”,如:X?+

用代码说话

1、Greedy 贪婪模式

public static void main(String[] args) {
    String targetStr = "xfooxxxxxxxfoo";
    Pattern pattern = Pattern.compile(".*foo");
    Matcher matcher = pattern.matcher(targetStr);

    while (matcher.find()) {
        System.out.println("find text = "
            + matcher.group()
            + "   start index = "
            + matcher.start()
            + "  end index = "
            + matcher.end());
    }
}

输出结果:

find text = xfooxxxxxxxfoo   start index = 0  end index = 14

2、Reluctant 懒惰模式

 public static void main(String[] args) {
    String targetStr = "xfooxxxxxxxfoo";
    Pattern pattern = Pattern.compile(".*?foo");

    Matcher matcher = pattern.matcher(targetStr);

    while (matcher.find()) {
        System.out.println("find text = "
            + matcher.group()
            + "   start index = "
            + matcher.start()
            + "  end index = "
            + matcher.end());
    }
}

输出结果:

   find text = xfoo   start index = 0  end index = 4
find text = xxxxxxxfoo   start index = 4  end index = 14

3、Possessive 独占模式

public static void main(String[] args) {
    String targetStr = "xfooxxxxxxxfoo";
    Pattern pattern = Pattern.compile(".*+foo");

    Matcher matcher = pattern.matcher(targetStr);

    while (matcher.find()) {
        System.out.println("find text = "
            + matcher.group()
            + "   start index = "
            + matcher.start()
            + "  end index = "
            + matcher.end());
    }
}

输出结果为空白,即matcher.find()返回false,未匹配成功.

下面说说原理:

Greedy“贪婪模式”是因为匹配器被强制要求第一次尝试匹配时就读入整个输入串,如果第一次尝试匹配失败,则从后往前逐个字符地回退并尝试再次匹配,直到匹配成功或没有字符可回退。
模式串:.*foo
查找串:xfooxxxxxxxfoo
结果:find text = xfooxxxxxxxfoo start index = 0 end index = 14
greedy

要点:一次性读入整个输入串,第一次匹配整个字符串时,符合 .* ,此时到达末尾,回退1个字符,继续进行第二次匹配,依次类推,直到回退到 foo时,匹配成功,此时 match.find()==true,输出结果

Reluctant采用与Greedy相反的方法,它从输入串的首字符位置开始,在一次尝试匹配查找中只勉强地读一个字符,直到尝试完整个字符串。
模式串:.*?foo
查找串:xfooxxxxxxxfoo
结果: find text = xfoo start index = 0 end index = 4
find text = xxxxxxxfoo start index = 4 end index = 14

reluctant

这个应该也很容易理解,主要思想同greedy,只是首次读入是从头开始。

最难理解的应该是独占模式吧(其实特别简单,哈哈):

Possessive(独占模式)同greedy一样一次性读入整个输入串,但是只尝试一次仅且一次,Possessive从不回退.

(参考greedy的图的第一次匹配,区别在于执行第一次匹配后不再进行第二次回退匹配,直接返回matcher.find结果)

根据greedy要点推出,当第一次读取匹配时,读取在末尾,此时只符合. ,并未匹配到foo,所以直接返回matcher.find()== false
模式串:.
+foo
查找串:xfooxxxxxxxfoo
结果:
//未匹配成功

到此,应该就明白了吧!

简单总结一下:
贪婪性:能够使匹配成功的最大可能重复数
勉强性:匹配最小的重复次数
独占性:即使让整个匹配失败,也要匹配最大的重复数。

下面来个”独占模式”成功匹配的例子

目标匹配字段:adbcde
匹配模式:[a-z]*+
匹配结果,匹配成功,mactcher.find()==true,matcher.group()==””,匹配成功的开始位置为6,结束位置为6,刚好是目标匹配字符的长度

    public static void main(String[] args) {
    String targetStr = "adbcde";
    Pattern pattern = Pattern.compile("[a-z]*+");

    Matcher matcher = pattern.matcher(targetStr);

    while (matcher.find()) {
        System.out.println(matcher.find());
        System.out.println("find text = "
            + matcher.group()
            + "   start index = "
            + matcher.start()
            + "  end index = "
            + matcher.end());
    }
}

结果输出:

true
find text =    start index = 6  end index = 6

个人觉得独占模式的使用率不高,因为太严格了,严格到没出路!!!

Git命令清单

git的使用,首先要了解git仓库的原理,日常使用只要记住下图的6个命令就可以了。

git_construct.png

几个专用名词的译名如下:
•Workspace:工作区
•Index/Stage:暂存区
•Repository:仓库区(或本地仓库)
•Remote:远程仓库

建立一个git仓库后,通过add命令,将track的代码由工作区workspace添加到暂存区Index,再使用commit命令,将暂存区的代码提交到git仓库中,并添加提交注释,这时可以在本地仓库中看到git提交记录及日志,此时代码只保存在本地仓库,多人协助的同学还无法获取到你更新的代码,所以必须通过push指令将代码“推送”到远程服务器中。

1、新建仓库

在当前目录新建一个Git代码库

git init

新建一个目录,将其初始化为Git代码库

git init [project-name]

下载一个项目和它的整个代码历史

git clone [url]

新建仓库通常我们有两种情景:
情景一:在github(远程服务器)创建好一个仓库,得到指定url,同时在本地开发了一些代码,并未将其初始化为git仓库:
1、git init #将当前目录初始化成一个git仓库
2、在根目录下添加并编辑.gitignore忽略文件(子模块modules中也可有.gitignore文件,需要根据需求进行编辑),此时可以发现项目目录被忽略的文件颜色是黑的,未被忽略的文件颜色则是明亮的。.gitignore文件的作用是将不该提交的由工具编译产生的文件进行忽略,以免提交到远程仓库后,其他人pull获取代码时破坏对方的配置信息等。这里提供一个可以帮助生成.gitignore文件内容的工具地址 gitignore.io
3、git add . #注意后面跟的小点,意思是添加所有文件到git仓库中,也可以用–all或-A来替代这个小点,意思都是添加所有文件。
4、git commit -m “first commit” #将初次代码进行提交
5、git remote add origin git@github.com:qingsong-xu/ZtphTest.git #将本地仓库和远程仓库地址进行关联,这里的远程仓库地址是git@github.com:qingsong-xu/ZtphTest.git
6、git push -u origin master #将仓库repository中的代码进行推送到远程仓库,此时其他人就可以在这个地址上获取到你的相应代码了。git push -u origin master 等价于 git push –set-upstream origin master,意思是将当前所在的master本地分支和远端分支进行默认关联,以后在本地master分支开发提交代码时可以直接使用命令: git push (不用跟参数 <本地分支名>,每次push的完整写法应该是 git push )
以上步骤就完成

这里要特别指出.gitignore文件的重要性,因为往往很多冲突需要解决,都是有用其他人提交了该忽略的文件,导致自己pull项目下来后本地环境和代码都乱

情景二:已有开发项目,需要你接手继续开发(大多数我们都是遇到这样的情况)提供Git远程仓库地址url。

1、git clone 远程仓库地址url
2、添加.gitignore 忽略文件
3、git add 指定文件/–all/-A/.(‘.’同all是一样的意思)
4、git commit -m “提交注释”
5、git fetch //获取远端更新到本地仓库
6、git rebase origin/master(或指定别的远端) //此操作,其实是先将当期提交到本地仓库的节点代码同指定远端仓库代码进行比较,若有冲突,需要解决冲突后,通过git rebase –continue或git rebase –skip继续rebase知道完成,
7、rebase结束后,本地工作区代码未解决冲突合并后的代码,需要重新执行add、commit直接进行提交
8、commit提交后的代码,需要使用git push origin master,push到远端。

ReactNative学习基础(一)

ReactNative最头痛之—-wrap_content match_parent

ReactNative之生命周期:
1、场景A组件中只定义Navigator,并设置B组件为第一个默认组件,B组件中调用自定义的C组件控件
首先需要了解组件生命周期有那几个函数:

componentWillMount(){

 }

 componentDidMount(){

}

shouldComponentUpdate(){
     return true;
 }

 componentWillUpdate(){

 }

 componentDidUpdate(){

 }

先解释说明一下生命周期的含义

执行后的:

http://www.tuicool.com/articles/nu6zInB

####Iconfont的使用:这是旧语法
1、下载对应的model
如:
npm install –save react-native-iconic-font
这时你会在当前RN项目下的找到你这个font的model,如图

2、Android将想要引入的ttf文件拷贝到指定的android assets/fonts/目录下
如图:

3、在app/build.gradle文件里添加compile指令:
compile ‘com.facebook.react:react-native:0.16.+’

4、在RN项目的js文件中去引用文字图标,代码如:

<Text style={{fontFamily: 'fontawesome', fontSize: 30}}>
                    {icon('twitter')}
                </Text>

这个注意属性fontFamily,值和导入的ttf文件的文件名必须保持一致。否则显示的是一个 ‘X’图标,是不正常的。

5、如果刷新查看不到具体效果,重新运行指令react-native run-android 安装app即可。

####Iconfont的使用:新语法
1、下载对应的model
https://github.com/qingsong-xu/react-native-vector-icons

2、引入到Android中进行编译
3、在app/build.gradle文件里添加compile指令:
compile project(‘:react-native-vector-icons’)
4、在RN项目中导入使用

import Icon from 'react-native-vector-icons/FontAwesome';

<TabNavigatorItem selected={this.state.selectedTab === '首页'}
                                  ......
                                  renderIcon={() => <Icon name="home" size={22} color="gray" />}
                                  renderSelectedIcon={() => <Icon name="home" size={22} color="#3b95d3" />}
                                  .........
                </TabNavigatorItem>

###自定义控件时,往往会发现不指定具体高度的时候组合控件会比ReactNative的单控件要高出很多,所以这里要知道,是需要指定具体控件高度的。

自定义控件时,涉及到PropsType指定属性,

ReactPropTypes = {
array: createPrimitiveTypeChecker('array'),
bool: createPrimitiveTypeChecker('boolean'),
func: createPrimitiveTypeChecker('function'),
number: createPrimitiveTypeChecker('number'),
object: createPrimitiveTypeChecker('object'),
string: createPrimitiveTypeChecker('string'),
symbol: createPrimitiveTypeChecker('symbol'),

any: createAnyTypeChecker(),
arrayOf: createArrayOfTypeChecker,
element: createElementTypeChecker(),
instanceOf: createInstanceTypeChecker,
node: createNodeChecker(),
objectOf: createObjectOfTypeChecker,
oneOf: createEnumTypeChecker,
oneOfType: createUnionTypeChecker,
shape: createShapeTypeChecker


弄清楚具体控件属性的意思

####ListView实现GridView效果要领:
1、Listview中可以使用SrcollView的所有效果,包括:horizontal={true},此属性使得排列方向为横向。但是若使用此属性后,会发现,items都会被渲染,只是方向改变而已,所以不能用此属性来实现GridView

2、ScrollView中有属性contentContainerStyle,此style是将定义的style应用到内容容器包裹的item中,说白了就是容器属性,所以设置此style为:

contentContainerStyle={
    {
     flexDirection: 'row',
        flexWrap: 'wrap',
     alignItems:'center',
     justifyContent:'center'
    }
}

首先设置内容为横向,其次设置子items为自动换行,alignItems:'center',justifyContent:'center'这两个属性只是为了让内容居中而已

###ReactNative全局变量如何创建和使用

可以的

哈哈

React学习第一天

###理解ReactDOM.render
ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点
1、此方法接受两个参数,中间用逗号隔开,第一个参数要么是

html块,要么是组件。直接写{} js代码是错误的。
2、有且只能有一个顶层标签,有两个平级的顶层标签会出错

###组件 React.createClass

var ComponentModel =  React.createClass({
    render:function(){ return ****; }
    });

1、组件只能包含一个顶层标签,不能包含两个顶层标签,否则报错
2、组件属性名,避免和JavaScript的保留字冲突,class改成className,for改成hemlFor。(自己试验了下,不改也是ok的,奇怪了)
3、 React.createClass(),括号里,必须用‘{’大括号把render:function(){return *;}包裹起来

###this.props.children
this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点
这里比较有意思的是:

var NotesList = React.createClass({
render: function(){
    return (
    <div>
    {
        React.Children.map(this.props.children,function(child){
        return <span>{child}</span>;
        })
    }
    </div>
    );
}
});

ReactDOM.render(
    <NotesList>
        <span>hello 第一</span>
        <span>world 第二</span>
    </NotesList>,
    document.getElementById("container1")
);

其中:
return (
    <div>
    {
        React.Children.map(this.props.children,function(child){
        return <span>{child}</span>;
        })
    }
    </div>
    );
return后面跟的()后面必须是html标签。不能直接‘{’大括号。

###PropTypes
验证组件实例的属性是否符合要求

/*** 组件的属性定义验证 ***/
var MyTitle = React.createClass({
propTypes:{
    title:React.PropTypes.number.isRequired,
},
render:function(){
    return <span>{this.props.title}</span>;
}});

ReactDOM.render(
    <MyTitle title={520.1314}/>,
    document.getElementById("container")
);

1、propTypes: 第一个字母大小写都ok
2、function(){
    return <span>{this.props.title}</span>;
}})必须有html标签括起来
3、title的值,string可以直接“字符串”,数字的话需要用大括号括起来"{520.1314}"


否则会报类似:Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.的错误

###状态state的改变
模板代码

var LinkedButton = React.createClass({
getInitialState:function(){
    return ({liked : false});
}
,
handleClick: function(){
    this.setState({liked: !this.state.liked});
}
, 
render: function(){
    var text = this.state.liked ? 'like':'haven\'t liked';
    return (<p onClick={this.handleClick}>
        You {text} this.Click to toggle.
    </p>)
}
});

ReactDOM.render(
<LinkedButton />,
document.getElementById("container")
);

Reat 改变控件状态 state,属性props的话,一经定义,就改不了了,使用state状态的话可以改

###表单提交
文本输入框(input)中的内容(value),若想读取到的话,不能使用this.props.value读取,要定义一个onChange事件的回调函数,通过event.target.value读取用户输入的值,textarea元素、select元素、radio元素都属于这种情况。

1、创建组件时,value属性写法为={value},其中的value值要在此function中创建。
2、必须有onChange事件监听,去处理触发改变后的动作
3、触发改变的事件里,改变状态值的写法为:this.setState({value:event.target.value}),必须通过event.target.value去获取到事件的改变值。
4、getInitialState:function中,必须返回(return)一个值写法为:{value:’this is a init value.’};

/*** 做一个表单提交组件 ***/
var InputComponent = React.createClass({
getInitialState:function(){
    return {value:'this is a init value.'};
}
,
handleTextChange:function(event){
    console.log(event.target.value);
    this.setState({value:event.target.value});
}
,
render: function(){
var value = this.state.value;
return (<div>
    <input type="text" name="inputComponent" value={value} onChange={this.handleTextChange} />
    <p>{value}</p>
</div>);
}
});


ReactDOM.render(
    <InputComponent />
    ,
    document.getElementById("container")
);

###生命周期
组件的生命周期分成三个状态:

  • Mount:已插入真实 DOM
  • Updat:正在被重新渲染
  • Unmount:已移出真实 DOM
/*** 组件的生命周期练习 ***/
var LifeCycleComponent = React.createClass({
    getInitialState:function(){
     return { opacity: 1.0};
    }
    ,
    componentWillMount:function(){
        /**只会调用一次,相当于onCreate()**/
        console.log("渲染前...."+new Date().getMilliseconds());
    }
    ,
    componentDidMount:function(){
        /**只会调用一次,一次性的onResume()方法 **/
        console.log("渲染完成"+new Date().getMilliseconds());
        setInterval(function(){
        var mOpacity = this.state.opacity;
        mOpacity -= 0.05;
        if(mOpacity < 0.1){
            mOpacity = 1.0;
        }
        this.setState({opacity:mOpacity})
        }.bind(this),100);
    }
    ,
    componentWillUpdate:function(){
        /**可重复调用,相当于reStart()**/
        console.log("将要重新渲染...."+new Date().getMilliseconds());
    }
    ,
    componentDidUpdate:function(){
        /**可重复调用,相当于reStart()后的onResume**/
        console.log("重新渲染完成"+new Date().getMilliseconds());
    }
    ,
    componentWillUnmount:function(){
        console.log("移出真实DOM"+new Date().getMilliseconds());
    }
    ,
    render: function(){
        return (<div style={{opacity:this.state.opacity}}>
            <p>Hello {this.props.name}!</p>
        </div>);
    }
});

ReactDOM.render(
    <LifeCycleComponent name="World"/>
    ,
    document.getElementById("container")
);

怎么理解生命周期里需要bind()及其bind在this参数的这个this的意义。

###Ajax嵌入使用
使用过程中需要注意的地方:
1、首先需要导入jquery.js
2、其中标识解析时,注意,导入js是src=”jquery.min.js”,而编写React时,,是type,而不是src。
3、组件中

render:function(){
return (<div></div);/** <div>外面就是return的"()",不能用“{}”包裹 ***/
}

##常见问题
Warning: Each child in an array or iterator should have a unique “key” prop. Check the top-level render call using

. See https://fb.me/react-warning-keys for more information.

xml第一天

##XML学习
xml - Expansible Mark Language 可拓展性语言,主要用处:1、用于描述关系 2、作为配置文件
(最初是w3c想让其替代html,然而并没有)

xml的重要组成部分:1、文档声明 <?xml version=”1.0” encoding=”UTF-8” standalone=”no” ?>
version=”1.0”//遵循的版本号
encoding=“UTF-8”//文档编码格式
standalone=”no”//是否独立存在,no代表不独立,但是IE浏览器仍然可以打开,是没有遵循xml的规范,忽略了这个属性

注意:这里主要涉及到的是“乱码”问题。

2、元素(1):xml元素指xml文件中出现的–标签。element,标签分为开始标签和结束标签,还有1、包含标签体的标签 2、不包含标签体的标签。

标签中也可以嵌套若干子标签,但是不能随意嵌套,必须合理配对。

格式良好的xml文档必须有且只有一个根标签,其他的标签都是这个标签的子孙标签。

元素(2):对于xml标签中出现的所有空格和换行,xml解析都会当作标签内容进行处理。例如:

<网址>www.baidu.com</网址>

<网址>
    www.baidu.com
</网址>

上面两种意义是不一样的。所以编写xml文件时,换行和缩进的方式的“良好”书写习惯可能要被迫改变。

元素(3):命名规范
一个xml元素可以包含字母、数字以及其他一些可见字符,但是必须遵守规范:1、区分大小写,如

是不同的两个标记。2、不能以数字或“_”(下划线)开头。3、不能以xml(或Xml,XML等)开头。4、不能包含空格。5、中间不能包含冒号(:)。

3、属性:·一个标签可以有多个属性,每个属性有自己的命名和取值,如:
·属性值一定要有双引号(“”)或单引号(‘)引起了。
·定义属性必须遵循与标签相同的命名规范
·多学一招:在xml技术中,标签属性所代表的信息,也可以被改成用子元素的形式描述,例如:

<input>
    <name>text</name>
</input>

4、注释:xml文件中的注释采用:
(1)xml声明之前是不允许有注释的。
(2)注释不能嵌套。 –> 这样是有问题的。

5、CDATA区:
编写xml文件时,不想被解析引擎解析执行的,想当做原始内容处理的,可以放到CDATA区,这样xml程序会原封不动的输出。如:

<![CDATA[
    <aa>
    严封不动输出!
    </aa>
]]>

6、转义字符
对于一些单个字符,若想显示其原始样式,也可以使用转义的形式处理。简而言之,言而简之:若是想输出给人看,使用转义字符来代替;若想给机器看,让其原始输出,则才有CDATA区。

特殊字符 替代字符
& &
< <

&gt;

“ "
‘ '

7、处理指令:处理指令,检查PI(processing instruction).处理指令用来指挥解析引擎如何解析xml文档内容.
通知xml解析引擎,应用css文件显示xml文档内容。语法:”<?”开头”?>”结尾。常见的如:<?xml-stylesheet type=”text/css” href=”1.css” ?>

xml约束概述:
1、什么是xml约束,在xml技术里,可以编写一个文档来约束另一个xml文档的书写规范,称之为xml约束。
2、为什么要约束,凡事都需要xml约束来规范。
3、常用的约束技术:xml DTD、xml Schema。

DTD约束快速入门:Document type definition,文档类型定义。 <!DOCTYPE 跟标签 SYSTEM “book.dtd” >

 <?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE 书架 SYSTEM "books.dtd">
<书架>
    <书>
        <书名>哎呦</书名>
        <作者>你觉得呢</作者>
        <售价>23.9</售价>
    </书>
    <书>
        <书名>哎呦</书名>
        <作者>你觉得呢</作者>
        <售价>23.9</售价>
    </书>
    <书>
        <书名>哎呦</书名>
        <作者>你觉得呢</作者>
        <售价>23.9</售价>
    </书>
</书架>

##编写DTD,
有两种编写方式,可以作为单个文件进行引入,也可以直接写在内部。

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE 书架[
    <!ELEMENT 书架(书+)>
    <!ELEMENT 书(书名,作者,售价)>
    <!ELEMENT 书名(#PCDATA)>
    <!ELEMENT 作者(#PCDATA)>
    <!ELEMENT 售价(#PCDATA)>
]>
<书架>
    <书>
        <书名>哎呦</书名>
        <作者>你觉得呢</作者>
        <售价>23.9</售价>
    </书>
    <书>
        <书名>哎呦</书名>
        <作者>你觉得呢</作者>
        <售价>23.9</售价>
    </书>
    <书>
        <书名>哎呦</书名>
        <作者>你觉得呢</作者>
        <售价>23.9</售价>
    </书>
</书架>

·当引用的文档在本地时,采用<!DOCTYPE 书架 SYSTEM “book.dtd”>
·当引用的文件是一个公共的文件时,采用<!DOCTYPE 文档根节点 PUBLIC “DTD名称” “DTD的url地址”>

元素的定义:
<!ELEMENT 元素名 元素里的内容>
属性的定义:
<!ATTLIST 元素名 属性名1 属性值类型 设置说明
属性名1 属性值类型 设置说明
……….
>

<!ENTITY AA “I LOVE YOU”> //引用实体
<!ENTITY % 实体名称 “实体内容”>//参数实体,只能被DTD文件自身使用,做到代码的重用和简化

##Dom和sax解析方法的区别:
1、dom解析的优点是对文档crud比较方便,缺点是占用内存比较大
2、sax解析的优点是占用内存少,解析速度快,缺点是只适合做文档读取,不适合做文档的crud