android基础_android基础知识 - CSDN
  • Android从入门到精通

    千人学习 2019-12-17 16:15:14
    本课程针对Android初学者的入门实战课程,详尽的介绍Android基础的方方面面,从开发环境搭建到基础控件的使用、Android四大组件的应用、数据存储、AndroidUI设计、网络请求、数据解析、第三方SDK集成、app框架搭建...
  • Android基础知识总结

    千次阅读 2018-06-11 12:21:34
    Android开发环境的搭配1. 启动电脑加速器:A. 重启电脑,按住F12((台式机)),进入[Startup Device Menu]后点击[Enter Setup]B. 如果提示要密码【Enter Password】,输入密码bwfC.如果把【Disabled】改为了...

    Android开发环境的搭配
    1. 启动电脑加速器:
    A. 重启电脑,按住F12((台式机)),进入[Startup Device Menu]后点击[Enter Setup]
    B. 如果提示要密码【Enter Password】,输入密码bwf

    C.如果把【Disabled】改为了[Enabled]按键盘上的【Esc】退到:都点[Yes]


    D.笔记本电脑:重启电脑,按住F10(hp电脑,不同型号的电脑不同,有些可以按F2)进入BIOS设置界面


     
    2. 安装sdk
    A. 配置环境变量:找到sdk文件存放的地址;把【platform-tools】和【tools】文件夹的路径放在环境变量的Pash
    B. 安装:找到sdk\extras\intel\Hardware_Accelerated_Execution_Manager文件夹下的【intelhaxm-android.exe】文件运行安装
    3. 安装eclipse:
    A. 在放sdk的文件夹下有一个eclipse的文件夹,打开运行【eclipse.exe】
    B. 安装好了打开了eclipse,在Window下的Open Perspective下添加Java和DDMS,

    C. 只有添加了Java才会显示打开安卓虚拟机的图标


    安卓四大组件
    1. Activity:应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应
    2. Service  服务:一个Service 是一段长生命周期的,没有用户界面的程序,可以用来开发如监控类程序。
    3. BroadcastReceive广播接收器:你的应用可以使用它对外部事件进行过滤只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。
    4. Content Provider内容提供者 :android平台提供了Content Provider使一个应用程序的指定数据集提供给其他应用程序
    五大布局
    1.LinearLayout线性布局:将此布局中的UI主键一个挨一个排列,有两种排列方法:横向排列和纵向排列
    2.RelativeLayout相对布局:相对布局里面的组件的位置总是相对于其他组件或者父布局来决定的
    3.FrameLayout帧布局:先定义的位于底层,后先定义的位于上层
    4.AbsoluteLayout是绝对位置布局:在此布局中的子元素的android:layout_x和android:layout_y属性将生效,用于描述该子元素的坐标位置。

    5.TableLayout表格布局:适用于N行N列的布局格式。一个TableLayout由许多TableRow组成,一个TableRow就代表TableLayout中的一行


    控制组件是否位于父布局的什么位置(RelativeLayout.LayoutParams)
      <!--android:layout_centerInParent="true" 控制组件是否位于父布局容器的中央位置-->
          <!--android:layout_centerHorizontal="true" 控制组件是否位于父布局水平居中位置-->
          <!--android:layout_centerVertical="true" 控制组件是否位于父布局垂直居中位置-->
          <!--android:layout_alignParentTop="true" 控制组件是否与父布局顶端对齐-->

    android:layout_alignWithParentIfMissing 如果对应的兄弟元素找不到的话就以父元素做参照物



    TextView控件(文本控件)
    1、简介:
            TextView控件可用来展示文本信息(包括HTML文本),可以手动来设置可编辑或不可编辑。
    2、创建对象:
            1)在代码中通过new的方式创建,创建,设置文本,样式后,通过setContentView方法,将空间设置到界面中。
            2)通过在main.xml中添加TextView配置节来创建,设计基础属性,宽度、高度、颜色、字体大小等,需要注意的是设置字体大小的几个单位(sp/dp/ps)之间的区别,几个单位的解释如下:
    dp也就是dip。这个和sp基本类似。如果设置表示长度、高度等属性时可以使用dp 或sp。但如果设置字体,需要使用sp。dp是与密度无关,sp除了与密度无关外,还与scale无关。如果屏幕密度为160,这时dp和sp和px是一样的。1dp=1sp=1px,但如果使用px作单位,如果屏幕大小不变(假设还是3.2寸),而屏幕密度变成了320。那么原来TextView的宽度设成160px,在密度为320的3.2寸屏幕里看要比在密度为160的3.2寸屏幕上看短了一半。但如果设置成160dp或160sp的话。系统会自动将width属性值设置成320px的。也就是160 * 320 / 160。其中320 / 160可称为密度比例因子。也就是说,如果使用dp和sp,系统会根据屏幕密度的变化自动进行转换。 
        下面看一下其他单位的含义 
    px:表示屏幕实际的象素。例如,320*480的屏幕在横向有320个象素,在纵向有480个象素。
    in:表示英寸,是屏幕的物理尺寸。每英寸等于2.54厘米。例如,形容手机屏幕大小,经常说,3.2(英)寸、3.5(英)寸、4(英)寸就是指这个单位。这些尺寸是屏幕的对角线长度。如果手机的屏幕是3.2英寸,表示手机的屏幕(可视区域)对角线长度是3.2*2.54 = 8.128厘米。读者可以去量一量自己的手机屏幕,看和实际的尺寸是否一致。 
    mm:表示毫米,是屏幕的物理尺寸。 
    pt:表示一个点,是屏幕的物理尺寸。大小为1英寸的1/72。 
            3)设置字体颜色可用如下方法(亦可在文本中添加HTML标签代码来设置颜色):
    TextView tv=(TextView)findViewById(R.id.tv);
    String str="欢迎大家收看《Android开发从零开始》系列课程。感谢大家的支持。";
    SpannableStringBuilder style=new SpannableStringBuilder(str);
    style.setSpan(new ForegroundColorSpan(Color.RED), 0, 6, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    style.setSpan(new ForegroundColorSpan(Color.GREEN), 6, 21, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    style.setSpan(new ForegroundColorSpan(Color.BLUE), 21, 34, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    tv.setText(style);
    3、android:autoLink属性:
            可设置内容为“none/web/email/phone/map/all” 几项,系统会自动识别所设置的格式,可链接到浏览器或拨号面板。
    4、跑马灯效果:
            android:ellipsize 设置当文字过长时,该控件该如何显示。可选项“start/end/middle/marquee”来分别设置省略号的出现位置,当设置为marquee时,可设置跑马灯效果。同时需设置以下几项(缺一不可):
    android:singleLine="true"   // 设置文本在一行显示
    android:focusable="true"   // 设置是否可以获取焦点
    android:ellipsize="marquee"   //设置文本以marquee方式显示
    android:marqueeRepeatLimit="marquee_forever"   //设置滚动次数,marquee_forever 为无限次
    android:focusableInTouchMode="true"   // 设置是否在触摸模式下获得焦点
    5、部分TextView属性介绍:
    android:autoLink设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接。可选值(none/web/email/phone/map/all)
    android:autoText如果设置,将自动执行输入值的拼写纠正。此处无效果,在显示输入法并输入的时候起作用。
    android:bufferType指定getText()方式取得的文本类别。选项editable 类似于StringBuilder可追加字符,也就是说getText后可调用append方法设置文本内容。spannable 则可在给定的字符区域使用样式,参见这里1、这里2。
    android:capitalize设置英文字母大写类型。此处无效果,需要弹出输入法才能看得到,参见EditView此属性说明。
    android:cursorVisible设定光标为显示/隐藏,默认显示。
    android:digits设置允许输入哪些字符。如“1234567890.+-*/% ()”
    android:drawableBottom在text的下方输出一个drawable,如图片。如果指定一个颜色的话会把text的背景设为该颜色,并且同时和background使用时覆盖后者。
    android:drawableLeft在text的左边输出一个drawable,如图片。
    android:drawablePadding设置text与drawable(图片)的间隔,与drawableLeft、drawableRight、drawableTop、drawableBottom一起使用,可设置为负数,单独使用没有效果。
    android:drawableRight在text的右边输出一个drawable。
    android:drawableTop在text的正上方输出一个drawable。
    android:editable设置是否可编辑。
    android:editorExtras设置文本的额外的输入数据。
    android:ellipsize设置当文字过长时,该控件该如何显示。有如下值设置:”start”—-省略号显示在开头;”end” ——省略号显示在结尾;”middle”—-省略号显示在中间;”marquee” ——以跑马灯的方式显示(动画横向移动)
    android:freezesText设置保存文本的内容以及光标的位置。
    android:gravity设置文本位置,如设置成“center”,文本将居中显示。
    android:hintText为空时显示的文字提示信息,可通过textColorHint设置提示信息的颜色。此属性在 EditView中使用,但是这里也可以用。
    android:imeOptions附加功能,设置右下角IME动作与编辑框相关的动作,如actionDone右下角将显示一个“完成”,而不设置默认是一个回车符号。这个在EditView中再详细说明,此处无用。
    android:imeActionId设置IME动作ID。
    android:imeActionLabel设置IME动作标签。
    android:includeFontPadding设置文本是否包含顶部和底部额外空白,默认为true。
    android:inputMethod为文本指定输入法,需要完全限定名(完整的包名)。例如:com.google.android.inputmethod.pinyin,但是这里报错找不到。
    android:inputType设置文本的类型,用于帮助输入法显示合适的键盘类型。在EditView中再详细说明,这里无效果。
    android:linksClickable设置链接是否点击连接,即使设置了autoLink。
    android:marqueeRepeatLimit在ellipsize指定marquee的情况下,设置重复滚动的次数,当设置为 marquee_forever时表示无限次。
    android:ems设置TextView的宽度为N个字符的宽度。这里测试为一个汉字字符宽度
    android:maxEms设置TextView的宽度为最长为N个字符的宽度。与ems同时使用时覆盖ems选项。
    android:minEms设置TextView的宽度为最短为N个字符的宽度。与ems同时使用时覆盖ems选项。
    android:maxLength限制显示的文本长度,超出部分不显示。
    android:lines设置文本的行数,设置两行就显示两行,即使第二行没有数据。
    android:maxLines设置文本的最大显示行数,与width或者layout_width结合使用,超出部分自动换行,超出行数将不显示。
    android:minLines设置文本的最小行数,与lines类似。
    android:lineSpacingExtra设置行间距。
    android:lineSpacingMultiplier设置行间距的倍数。如”1.2”
    android:numeric如果被设置,该TextView有一个数字输入法。此处无用,设置后唯一效果是TextView有点击效果,此属性在EdtiView将详细说明。
    android:password以小点”.”显示文本
    android:phoneNumber设置为电话号码的输入方式。
    android:privateImeOptions设置输入法选项,此处无用,在EditText将进一步讨论。
    android:scrollHorizontally设置文本超出TextView的宽度的情况下,是否出现横拉条。
    android:selectAllOnFocus如果文本是可选择的,让他获取焦点而不是将光标移动为文本的开始位置或者末尾位置。 TextView中设置后无效果。
    android:shadowColor指定文本阴影的颜色,需要与shadowRadius一起使用。
    android:shadowDx设置阴影横向坐标开始位置。
    android:shadowDy设置阴影纵向坐标开始位置。
    android:shadowRadius设置阴影的半径。设置为0.1就变成字体的颜色了,一般设置为3.0的效果比较好。
    android:singleLine设置单行显示。如果和layout_width一起使用,当文本不能全部显示时,后面用“…”来表示。如android:text="test_ singleLine "
    android:singleLine="true" android:layout_width="20dp"将只显示“t…”。如果不设置singleLine或者设置为false,文本将自动换行
    android:text设置显示文本.
    android:textAppearance设置文字外观。如 “?android:attr/textAppearanceLargeInverse”这里引用的是系统自带的一个外观,?表示系统是否有这种外观,否则使用默认的外观。可设置的值如下:textAppearanceButton/textAppearanceInverse/textAppearanceLarge/textAppearanceLargeInverse/textAppearanceMedium/textAppearanceMediumInverse/textAppearanceSmall/textAppearanceSmallInverse
    android:textColor设置文本颜色
    android:textColorHighlight被选中文字的底色,默认为蓝色
    android:textColorHint设置提示信息文字的颜色,默认为灰色。与hint一起使用。
    android:textColorLink文字链接的颜色.
    android:textScaleX设置文字之间间隔,默认为1.0f。
    android:textSize设置文字大小,推荐度量单位”sp”,如”15sp”
    android:textStyle设置字形[bold(粗体) 0, italic(斜体) 1, bolditalic(又粗又斜) 2]可以设置一个或多个,用“|”隔开
    android:typeface设置文本字体,必须是以下常量值之一:normal 0, sans 1, serif 2, monospace(等宽字体) 3]
    android:height设置文本区域的高度,支持度量单位:px(像素)/dp/sp/in/mm(毫米)
    android:maxHeight设置文本区域的最大高度
    android:minHeight设置文本区域的最小高度
    android:width设置文本区域的宽度,支持度量单位:px(像素)/dp/sp/in/mm(毫米),与layout_width 的区别看这里。
    android:maxWidth设置文本区域的最大宽度
    android:minWidth设置文本区域的最小宽度
    EditText控件(父类是TextView):输入框
    1. android:typeface="sans" 设置字体,除了在XML代码中通过默认提供的4中字体之外,还可以在Java代码中引用.ttf字体文件来自定义字体的外观。
      <EditText
            android:id="@+id/edit02"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:cursorVisible="false"
            android:editable="false"
            android:lines="4" 
            android:gravity="top">
    <requestFocus />
    <!--<requestFocus />强制焦点,当很多个EditText控件时,设置这个该控件会强制焦点-->
    </EditText>
        <!-- android:gravity="top"焦点从第一行开始
    android:cursorVisible="false"设定光标为显示/隐藏
    android:editable="false"设置是否可编辑 -->
    设置 android:imeOptions="actionDone" ,软键盘下方变成“完成”,点击后光标保持在原来的输入框上,并且软键盘关闭
      android:imeOptions="actionSend" 软键盘下方变成“发送”,点击后光标移动下一个
      actionSearch  搜索
      actionGo 去往
      actionSend 发送
      actionNext  下一步
      actionDone 完成
    1. 属性在另一个文本文档中
    Button控件:按钮
    1. 父类是TextView
    2. 属性在文本文件中
    android:layout_weight="1"  权重(两个按钮的比例)


    Marquee:跑马灯(字体滚动):
    1. Android:ellipsize="marquee" 设置走马灯的效果,无缝滚动
    2. activity_marquee_text.xml布局里的代码:
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <!-- 走马灯:当TextView失去焦点的时候,字体不在滚动(跑马灯失效)-->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:singleLine="true"
            android:text="世界上最遥远的距离不是生和死,而是你亲手制造的BUG就在你眼前,你却怎么都找不到她!"
            android:textSize="20sp" />
        <!--
    android:ellipsize="marquee" 设置走马灯的效果,无缝滚动
         Android:ellipsize="start" 省略号在开头
             android:ellipsize="middle" 省略号在中间
             android:ellipsize="end" 省略号在结尾
             android:ellipsize="marquee" 跑马灯显示
    android:focusable(设置焦点)和android:focusableInTouchMode这两个属性,简单来说把这两个属性都设置成
    true,那么在运行程序以后跑马灯效果就显示出来了
       -->
        <!--
    XML代码设置:
    android:marqueerepeatlimit="1"。1代表1次,-1代表无限循环。不设置默认无限循环
    Java代码设置:
    mTVText.setMarqueeRepeatLimit(-1);
        -->
        <!-- 输入框 -->
    <EditText
            android:id="@+id/account"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="15dip"
            android:background="@color/blue"
            android:hint="请输入用户名/手机号"
            android:inputType="text"
            android:singleLine="true" />
    <!-- <永远有焦点的跑马灯> -->
    <com.cm.android03.MarqueeText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dip"
            android:background="@color/tomato"
            android:ellipsize="marquee"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:singleLine="true"
            android:text="老鼠扛刀,满街找猫!没有焦点,仍然可以滚滚动,牛叉,定义一个自定义TextView"
            android:textColor="@android:color/black"
            android:textSize="25sp"/>
    </LinearLayout>
    1. 设置跑马灯永远有焦点的类(重新定义了TextView):MarqueeText.java
    /**
     * 设置跑马灯永远有焦点
     * @author Administrator
     */
    public class MarqueeText extends TextView{
    //该构造方法必须要有
    public MarqueeText(Context context,AttributeSet a) {
    super(context,a);
    }
    //重写父类中的方法  一直返回结果为true,此自定义组件将一直有焦点
    public boolean isFocused() {
    return true;
    }
    }
    1. MainActivity.java代码
    public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //跑马灯效果
    setContentView(R.layout.activity_marquee_text);
    }
    }


    ScrollView:滚动条
    1. ScrollView 加滚动条,内容太多的时候,可以滚动到底部
    2. ScrollView里只能有一个控件,所以所有的控件都写在LinearLayout布局的控件中
    3. 代码案例:
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
            <!-- android:orientation="vertical"  设置垂直布局 -->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical" >
                <!-- android:autoLink="phone"  链接到打电话界面 -->
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:autoLink="phone"
                    android:text="15361191669" />
                <!-- android:autoLink="phone"  链接到发邮件界面 -->
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:autoLink="email"
                    android:text="15361191669@163.com" />
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:autoLink="web"
                    android:text="http://www.baidu.com" />
                <!-- android:drawableLeft="@drawable/ic_launcher" 在左侧添加图片 -->
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:drawableLeft="@drawable/ic_launcher"
                    android:text="左侧添加图片" />
                <!-- android:password="true" 以”.”形式显示文本 -->
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:password="true"
                    android:text="我是输入框EditText 、按钮Button的父类"
                    android:textColor="@color/text_color"
                    android:textSize="38px" />
            </LinearLayout>
        </ScrollView>
    </RelativeLayout>


    ImageView :图片的设置的控件
      <ImageView 
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/penguins01"/>    
             <!-- android:adjustViewBounds="true" 调整ImageView的界限来保持图像纵横比不变。 -->
               <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:background="@color/gray"
                android:src="@drawable/penguins01" 
                android:adjustViewBounds="true"/>
                <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:background="@color/gray"
                android:src="@drawable/penguins01" 
                android:adjustViewBounds="true"
                android:maxWidth="80dp"
                android:maxHeight="80dp"/>
             <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:background="@color/gray"
                android:src="@drawable/pic02" 
                android:maxWidth="80dp"
                android:maxHeight="80dp"/>
              <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:src="@drawable/penguins01"            
                android:scaleType="fitStart"/>
                <!-- android:scaleType="fitStart" 将图片边界缩放,以适应视图边界时的可选项。 -->


    RadioButton控件:单选框
    <!-- 单选按钮组 -->
            <RadioGroup
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal" >
                <!-- <单选按钮> -->
                <RadioButton
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="男" />
                <RadioButton
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="女" />
            </RadioGroup>
    CheckBox:复选框
    AutoCompleteTextView:自动提示文本框
            <!-- 自动提示文本框 -->
            <AutoCompleteTextView
                android:id="@+id/autoEt"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:completionHint="你好"
                android:completionThreshold="1"
                android:dropDownHeight="80dp" />
            <!--
            android:completionThreshold="1"  设置用户至少输入几个字符才会显示提示
            android:completionHint="你好"  设置出现在下拉菜单中的提示标题 -->


    时钟
    <!-- 圆形时钟 -->
            <AnalogClock 
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
            <!-- 电子表 -->
            <DigitalClock 
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="20sp"
                />
    Spinner:下拉列表
    1. 定义要有哪些选择项,点击控件时下拉框会显示定义的选项,选项你要的选项即可
    2. XML的代码
    <Spinner 
            android:layout_margin="10dp"
          android:background="@drawable/edittext_default"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:entries="@array/books"/>
    <!-- android:entries="@array/books"要选择的项在Values文件夹下arrays文件里的定义好了-->
      <Spinner 
             android:id="@+id/spinner"
             android:layout_margin="10dp"
            android:background="@drawable/edittext_default"
            android:layout_width="fill_parent"
            android:layout_height="30dp"
            android:spinnerMode="dialog"/>
         <!--  android:spinnerMode  设置Spinner的展现形式,是下拉列表?还是对话框?
         默认是下拉列表 -->


    SeekBar滑动条(动态显示进度):改变音量,清晰度等
    1. 属性:
    Android:thumb 改变滑块的外观
    Android:progressDrable 自定义轨道的外观
    Max  progress
    OnSeekChangeListener  监听器
    1. 改变图片的清晰度(例子),activity_seek_bar_test.xml代码:
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" 
        android:gravity="center">
        <ImageView 
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:maxHeight="200dp"
            android:maxWidth="200dp"
            android:src="@drawable/tulips"/>
        
        <SeekBar 
            android:id="@+id/seekbar"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:max="225"
            android:progress="50"
            android:thumb="@drawable/gray"/>
    </LinearLayout>
    1. Activity里的代码
    /**
     * 滑块位置变换是,图片的清晰度在变换
     * @author Administrator
     */
    public class SeekBarTest extends Activity {
    ImageView image;
    SeekBar sb;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 滑块位置变换是,图片的清晰度在变换
    setContentView(R.layout.activity_seek_bar_test);
    image = (ImageView)findViewById(R.id.image);
    sb = (SeekBar)findViewById(R.id.seekbar);
    //监听器
    sb.setOnSeekBarChangeListener(lis);

    }
    OnSeekBarChangeListener lis = new OnSeekBarChangeListener() {
    public void onStopTrackingTouch(SeekBar seekBar) { }
    public void onStartTrackingTouch(SeekBar seekBar) {}
    // 当拖动条的滑块位置发生改变的时候出发这个方法
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    //setAlpha方法设置透明度
    image.setAlpha(progress);
    }
    };
    }


    ProgressBar进度条
    1. xml里的代码:
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <!-- 大环形进度条 -->
        <!-- style="@android:style/Widget.ProgressBar.Large" 最大的圆-->
        <ProgressBar
            android:id="@+id/big"
            style="@android:style/Widget.ProgressBar.Large"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true" />
        <!-- 中等环形进度条 -->
        <ProgressBar
            android:id="@+id/mid"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true" />
        <!-- 小环形进度条 -->
      <!-- style="@android:style/Widget.ProgressBar.Small"  最小的圆 -->
        <ProgressBar
            style="@android:style/Widget.ProgressBar.Small"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true" />
        <!-- style 设置进度条 风格的 -->
        <ProgressBar
            android:id="@+id/bar"
            style="@android:style/Widget.ProgressBar.Horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:progressDrawable="@drawable/my_bar" />
        <!-- android:progressDrawable="@drawable/my_bar" 进度条的样式 -->
    <!-- style= "@android:style/Widget.ProgressBar.Horizontal" 长条进度条-->
     <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="progress = 0, max = 100" />
        <ProgressBar
            android:id="@+id/pb01"
            style="@android:style/Widget.ProgressBar.Horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <!-- android:text="progress = 100, max = 100" 进度和长度-->
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="progress = 100, max = 100" />
        <ProgressBar
            android:id="@+id/pb02"
            style="@android:style/Widget.ProgressBar.Horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    1. 进度自己增加(用到Thread + Handler),Acyivity里的代码
    public class ProgressBarTest extends Activity {
    // 自定义定义进度
    private int hasData = 0;
    private ProgressBar bar,pb01,pb02;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.llpro_layout);
    bar = (ProgressBar) findViewById(R.id.bar);
    //设置进度条的长度显示的值
    bar.setMax(100);
    pb01 = (ProgressBar)findViewById(R.id.pb01);
    pb02 = (ProgressBar)findViewById(R.id.pb02);
    //设置进度条的长度显示的值
    pb01.setMax(100);
    //设置进度
    pb01.setProgress(0);
    pb02.setMax(100);
    pb02.setProgress(100);
    //设置线程
    new Thread() {
    public void run() {
    getDataFromHttp();
    }
    }.start();
    }
    //Handler子线程和主线程的信使
    Handler mHandler = new Handler(){
    public void handleMessage(Message msg) {
    if(msg.what == 0x111){
    bar.setProgress(hasData);
    }
    }
    };
    protected void getDataFromHttp() {
    while(hasData <= 100){
    hasData ++;
    try {
    Thread.sleep(200);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    mHandler.sendEmptyMessage(0x111);
    }
    }

    }


    4.星级评分条 RatingBar
    Android:numStats 设置这个星级评分条总共有多少个星级
    Android:rating  设置这个星级评分条默认的星级
    Android:stepSize 设置每次最少需要改变多少个星级
    OnRationgBarChangeListener 监听器
    Handler子线程和主线程的信使
    1. 含义:主要接受子线程发送的数据, 并用此数据配合主线程更新UI
    2. 使用过程:
    A.定义Handler对象并初始化,重写handleMessage()函数
    B.定义Thread线程对象,通常写成一个类形式(如class ThreadTest implements Runnable),在run()方法中操作数据,并把数据handler.sendMessage()方法传输     到handler对象中,并开启线程。(注意:该步骤不一定用Thread实现,也可以利用TimeTask实现,具体的操作同样放在run()方法中)
    C.在handleMessage()函数中根据不同的数据形式实现不同的方法。
    1. 非UI线程发送消息到UI线程分为两个步骤
    A. 发送消息到UI线程的消息队列
    通过使用Handler的Message obtainMessage(int what,Object object)构造一个Message对象,这个对象存储了是否成功获取图片的标识what和bitmap对象,然后通过message.sendToTarget()方法把这条message放到 消息队列中去。
    B.处理发送到UI线程的消息
    在ui线程中,我们覆盖了handler的 public void handleMessage (Message msg)这个方法是处理分发给ui线程的消息,判断msg.what的值可以知道mThread是否成功获取图片,如果图片成功获取,那么可以通过msg.obj获取到这个对象。最后,我们通过mImageView.setImageBitmap((Bitmap) msg.obj);设置ImageView的bitmap对象,完成UI的更新。


    ListView组件:
    1. 属性:
    android:cacheColorHint="#00000000"  //设置拖动背景色为透明  
    android:dividerHeight="30px"         //listview item之间的高度
    android:divider="@drawable/ic_launcher"    //listview item之间的背景或者说是颜色
    android:fadingEdge="vertical"       //上边和下边有黑色的阴影      值为none的话就没有阴影
    android:scrollbars="horizontal|none" //只有值为horizontal|vertical的时候,才会显示滚动条,并且会自动影藏和显示
    android:fastScrollEnabled="true"        //快速滚动效果,配置这个属性,在快速滚动的时候旁边会出现一个小方块的快速滚动效果,自动隐藏和显示,
    android:scrollbarStyle="outsideInset"  //四个值的含义如下
       1>outsideInset :  该ScrollBar显示在视图(view)的边缘,增加了view的padding. 如果可能的话,该ScrollBar仅仅覆盖这个view的背景.
       2>outsideOverlay :  该ScrollBar显示在视图(view)的边缘,不增加view的padding,该ScrollBar将被半透明覆盖
       3>insideInset :该ScrollBar显示在padding区域里面,增加了控件的padding区域,该ScrollBar不会和视图的内容重叠.
       4>insideOverlay : 该ScrollBar显示在内容区域里面,不会增加了控件的padding区域,该ScrollBar以半透明的样式覆盖在视图(view)的内容上.
    android:stackFromBottom="true"  该属性之后你做好的列表就会显示你列表的最下面,值为true和false          
    android:transcriptMode="alwaysScroll",transciptMode属性,需要用ListView或者其它显示大量Items的控件实时跟踪或者查看信息,并且希望最新的条目可以自动滚动到可视范围内。通过设置的控件transcriptMode属性可以将Android平台的控件(支持ScrollBar)自动滑动到最底部。   
    cacheColorHint属性,很多人希望能够改变一下它的背景,使他能够符合整体的UI设计,改变背景背很简单只需要准备一张图片然后指定属性 android:background="@drawable/bg",不过不要高兴地太早,当你这么做以后,发现背景是变了,但是当你拖动,或者点击list空白位置的时候发现ListItem都变成黑色的了,破坏了整体效果。如果你只是换背景的颜色的话,可以直接指定android:cacheColorHint为你所要的颜色,如果你是用图片做背景的话,那也只要将android:cacheColorHint指定为透明(#00000000)就可以了。当然为了美化是要牺牲一些效率的。
    android:divider="@drawable/list_driver" ,divider属性,该属性作用是每一项之间需要设置一个图片做为间隔,或是去掉item之间的分割线;其中@drawable/list_driver 是一个图片资源,如果不想显示分割线则只要设置为android:divider="@drawable/@null" 就可以了
    fadingEdge属性,上边和下边有黑色的阴影,android:fadingEdge="none" 设置后没有阴影了
    scrollbars属性,作用是隐藏listView的滚动条,android:scrollbars="none"与setVerticalScrollBarEnabled(true);的效果是一样的,不活动的时候隐藏,活动的时候也隐藏
    fadeScrollbars属性,android:fadeScrollbars="true"  配置ListView布局的时候,设置这个属性为true就可以实现滚动条的自动隐藏和显示。
    android:drawSelectorOnTop="true" 点击某一条记录,颜色会显示在最上面,记录上的文字被遮住,所以点击文字不放,文字就看不到
    android:drawSelectorOnTop="false" 点击某条记录不放,颜色会在记录的后面,成为背景色,但是记录内容的文字是可见的
    1. activity_main.xml里的代码
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <ListView 
           android:id="@+id/lv01"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"/>
    </LinearLayout>
    1. MainActivity.java里的代码
    package com.cm.android04_listview01;
    import android.app.Activity;//省略一些引用包
    /**
     * ListView组件
     * @author Administrator
     *
     */
    public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //获得ListView控件
    ListView list=(ListView)findViewById(R.id.lv01);
    //设置ListView控件中的值
    String[] arr = {"路飞","索隆","娜美","乌索普","罗宾","乔巴","山治",
    "弗兰奇","布鲁克","罗宾","乔巴","山治",
    "弗兰奇","布鲁克"};
    //适配器
    ArrayAdapter<String> aa=new ArrayAdapter<String>(MainActivity.this,
    android.R.layout.simple_list_item_single_choice,arr);
    /* android.R.layout.simple_list_item_single_choice
    android.R.layout.simple_dropdown_item_1line
    android.R.layout.simple_expandable_list_item_1
    android.R.layout.simple_expandable_list_item_2*/


    list.setAdapter(aa);
    }

    }


    适配器(自定义适配器)
    1. SimpleAdapter(很多时候需要继承它,来自定义adapter):simpleAdapter的扩展性最好,可以定义各种各样的布局出来,可以放上ImageView(图片)等。可以显示比较复杂的列表,包括每行显示图片、文字等,但不能对列表进行后期加工(在java代码中加工),也是只是单纯的负责显示。使用simpleAdapter的数据用一般都是HashMap构成的List,list的每一节对应ListView的每一行。HashMap的每个键值数据映射到布局文件中对应id的组件上。因为系统没有对应的布局文件可用,我们可以自己定义一个布局imagelayout.xml
    2. ArrayAdapter:只可以简单的显示一行文本
    使用了ArrayAdapter(Context context, int textViewResourceId, List<T> objects)来装配数据,要装配这些数据就需要一个连接ListView视图对象和数组数据的适配器来两者的适配工作,ArrayAdapter的构造需要三个参数,依次为this,布局文件(注意这里的布局文件描述的是列表的每一行的布局,android.R.layout.simple_list_item是系统定义好的布局文件只显示一行文字,数据源(一个List集合)。同时用 setAdapter()完成适配的最后工作。
    1. BaseAdapter(自定义的时候很多,尤其是一些复杂的布局,不自定义实现不了啊;SimpleAdapter和ArrayAdapter布局都继承了BaseAdapter;自定义适配器继承BaseAdapter):实现复杂的列表布局,由于BaseAdapter是一个抽象类,使用该类需要自己写一个适配器继承该类,正是由于继承了该类,需要我们重写一些方法,让我们可以在代码里控制列表的样式,更加灵活。
    2. 使用自带的适配器
    A. activity_main.xml里的代码
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="${relativePackage}.${activityClass}" >
        <ListView 
           android:id="@+id/mylist"
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"></ListView>


    </RelativeLayout>
    A. 绝对布局rlitem_layout.xml的代码(也可以用线性布局)
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
        android:padding="10dp">
        
        <ImageView 
            android:id="@+id/pic"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:adjustViewBounds="true"
            android:maxWidth="60dp"
            android:maxHeight="60dp"
            android:src="@drawable/ic_launcher"/>
        <TextView 
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/app_name"
            android:textSize="20sp"
            android:layout_toRightOf="@id/pic"
            android:layout_alignTop="@id/pic"/> 
        <TextView 
            android:id="@+id/content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            android:layout_toRightOf="@id/pic"
            android:layout_below="@id/name"    
            android:paddingTop="10sp"
            android:textColor="#ff7f7f7f"/>
        <TextView 
            android:id="@+id/date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="4月29日"
            android:textSize="15sp"
            android:singleLine="true"
            android:layout_alignParentRight="true"
            android:layout_alignTop="@id/pic"
            android:textColor="#ff7f7f7f"/>
    </RelativeLayout>
    A. MainActivity的代码
    package com.cm.android04_listview02;
    import java.util.ArrayList;//省略一些引用包
    public class MainActivity extends Activity {
    //定义信息
    private String[] names = {"刘诗诗","李丽","刘思思","陈思思","陈慧琳","王薇","林琳"};
    private String[] contents = {"晚上有空吗?","........","我很喜欢你","老地方见...","华哥最近好吗","我很喜欢你","老地方见..."};
    //放图片
    private int[] imageIds={R.drawable.jingjing,R.drawable.huixin,R.drawable.ruo,
    R.drawable.ruodan,R.drawable.yifei,R.drawable.huixin,R.drawable.ruo};
    private String[] dates = {"2016.5.4","2016.5.5","2016.5.6","2016.5.7","2016.5.8","2016.5.9","2016.5.10"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    List<Map<String,Object>> listItems=new ArrayList<Map<String,Object>>();
    //把信息保存在list集合中
    for (int i = 0; i < names.length; i++) {
    Map<String,Object> item=new HashMap<String,Object>();
    //把数据放在Map集合中
    item.put("header", imageIds[i]);
    item.put("personName",names[i]);
    item.put("desc", contents[i]);
    item.put("data", dates[i]);
    //把数据加入到List集合中
    listItems.add(item);
    }
    //适配器
    SimpleAdapter simpleAdapter=new SimpleAdapter(this,listItems,R.layout.rlitem_layout,
    new String[]{"header","personName","desc","data"},
    new int[]{R.id.pic,R.id.name,R.id.content,R.id.date}
    );
    ListView lv=(ListView)findViewById(R.id.mylist);
    lv.setAdapter(simpleAdapter);

    //点击每个人时显示信息,监听事件
    lv.setOnItemClickListener(new OnItemClickListener() {
    //点击事件
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    //Toast.makeText(context, text, duration);
    Toast.makeText(getApplicationContext(), names[position]+",好吗", Toast.LENGTH_SHORT).show();
    }
    });
    }
    }
    1. 自定义适配器,优化适配器(加了缓存)
    A. MyCustomAdapter.java自定义适配器的类
    package com.cm.android04_listview03;
    import java.util.List;//省略一些引用包
    /**
     * 自定义适配器,优化适配器
     * 
     * @author Administrator
     *
     */
    public class MyAdapter extends BaseAdapter {
    // 声明加载xml类的对象
    private LayoutInflater inflater;// 找res/layout/下的xml布局文件,
    // 声明上下文对象,通过构造器传值
    private Context context;
    // 声明数据源
    private List<Map<String, Object>> mData;


    public MyAdapter(Context c) {
    this.context = c;
    }
    // 定义构造器,创建对象 初始化 传值
    public MyAdapter(Context c, List<Map<String, Object>> mData) {
    inflater = LayoutInflater.from(c);
    this.context = c;
    this.mData = mData;
    }
    // 重写父类的方法
    public int getCount() {
    // 返回这个适配器共有多条数据 或 item
    return mData.size();
    }
    // 重写父类的方法
    public Object getItem(int position) {
    // 返回此索引position对应的数据项
    return mData.get(position);
    }
    // 重写父类的方法
    public long getItemId(int position) {
    // 返回此索引position对应的item的id
    return position;
    }
    // 自定义适配器的优化:缓存view(convertView) + ViewHolder静态类

    // 定义一个静态类,来缓存已经创建的 item布局中的 组件对象,避免重复 调用findViewById方法
    static class ViewHolder
    {
    ImageView pic;
    TextView name;
    TextView content;
    TextView date;
    }

    // 重写父类的方法
    public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder=null;
    //如果存储convertView 为null,说明 listView的第一页被加载了,这时候 会调用
    //convertView = mInflater.inflate(R.layout.sa_item, parent, false);来加载item的布局,
    //并且 通过findViewById来得到item布局中的每一个组件对象
    if(convertView==null)
    {
    convertView=inflater.inflate(R.layout.rlitem_layout, parent,false);
    viewHolder=new ViewHolder();
    viewHolder.pic=(ImageView)convertView.findViewById(R.id.pic);
    viewHolder.name = (TextView) convertView.findViewById(R.id.name);
    viewHolder.content = (TextView) convertView.findViewById(R.id.content);
    viewHolder.date = (TextView) convertView.findViewById(R.id.date);
    // 设置Tag,tag标示
    convertView.setTag(viewHolder);
    }else    //listView首页所有的item加载之后,会一致 通过tag标识 来引用内存中的convertView
    {
    // 得到tag标示
    viewHolder=(ViewHolder)convertView.getTag();
    }
    //为item布局中的每一个item的组件赋值// 给组件对象设置值
    viewHolder.pic.setImageResource((Integer)mData.get(position).get("header"));
    viewHolder.name.setText((String)mData.get(position).get("personName"));
    viewHolder.content.setText((String) mData.get(position).get("desc"));
    viewHolder.date.setText((String) mData.get(position).get("data"));

    return convertView;
    }
    }
    A. MainActivity.java里的代码


    package com.cm.android04_listview03;
    import java.util.ArrayList;
    public class MainActivity extends Activity {
    //存放信息
    private String[] names = {"苍井空","波多野结衣","刘思思","陈思思","陈慧琳","苍井空","波多野结衣","刘思思","陈思思","陈慧琳","苍井空","波多野结衣","刘思思","陈思思","陈慧琳"};
    private String[] contents = {"晚上有空吗?","........","我很喜欢你","老地方见...","华哥最近好吗","晚上有空吗?","........","我很喜欢你","老地方见...","华哥最近好吗","晚上有空吗?","........","我很喜欢你","老地方见...","华哥最近好吗"};
    private int[] imageIds = {R.drawable.jingjing,R.drawable.huixin,R.drawable.ruo,
    R.drawable.ruodan,R.drawable.yifei,R.drawable.jingjing,R.drawable.huixin,R.drawable.ruo,
    R.drawable.ruodan,R.drawable.yifei,R.drawable.jingjing,R.drawable.huixin,R.drawable.ruo,
    R.drawable.ruodan,R.drawable.yifei};
    private String[] dates = {"2016.5.4","2016.5.5","2016.5.6","2016.5.7","2016.5.8","2016.5.4","2016.5.5","2016.5.6","2016.5.7","2016.5.8","2016.5.4","2016.5.5","2016.5.6","2016.5.7","2016.5.8"};
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    List<Map<String,Object>> listItems=new ArrayList<Map<String,Object>>();
    for(int i = 0;i< names.length;i++){
    Map<String,Object> item = new HashMap<String,Object>();
    item.put("header", imageIds[i]);
    item.put("personName",names[i]);
    item.put("desc", contents[i]);
    item.put("data", dates[i]);
    listItems.add(item);
    }
    //实例化自定义的适配器
    MyAdapter ma=new MyAdapter(this,listItems);
    //设置适配器
    ListView lv=(ListView)findViewById(R.id.mylist);
    lv.setAdapter(ma);
    }

    }


    GirdView组件
    1. GridView和ListView的父类是AbsListView;GridView也需要通过适配器来包装数据和 设置每一个item的界面视图。这个适配器,一般使用 SimpleAdapter  或者 定义一个BaseAdapter的子类适配器(重写getView)
    2. ListView和GridView区别:ListView是在垂直方向上类表分布;而GridView则会在横向和纵向两个方向上分布,或者网格状分布。
    3. GridView组件里的一些属性
    android:columnWidth  //每列的宽度,也就是Item的宽度 ---   setcolumnWidth(int)
    Android:gravity  设置对齐方式    -----  setGravity(int)
    Android:horizontalSpacing  设置元素之间的水平间距-----setHorizontalSpacing(int)
    android:verticalSpacing   设置元素之间的垂直间距------setVerticalSpacing(int)
    Android:numColumnts   设置列数  ---- setNumColumnts(int)
    android:stretchMode=”columnWidth"//缩放与列宽大小同步
    android:cacheColorHint="#00000000" //去除拖动时默认的黑色背景
    android:listSelector="#00000000"        //去除选中时的黄色底色
    android:scrollbars="none"                   //隐藏GridView的滚动条
    android:fadeScrollbars="true"      //设置为true就可以实现滚动条的自动隐藏和显示
    android:fastScrollEnabled="true"    //GridView出现快速滚动的按钮(至少滚动4页才会显示)
    android:fadingEdge="none"    //GridView衰落(褪去)边缘颜色为空,缺省值是vertical。(可以理解为上下边缘的提示色)
    android:fadingEdgeLength="10dip" //定义的衰落(褪去)边缘的长度
    android:stackFromBottom="true"  //设置为true时,你做好的列表就会显示你列表的最下面
    android:transcriptMode="alwaysScroll" //当你动态添加数据时,列表将自动往下滚动最新的条目可以自动滚动到可视范围内
    android:drawSelectorOnTop="false"  //点击某条记录不放,颜色会在记录的后面成为背景色,内容的文字可见(缺省为false)
    1. 代码
    A.activity_main.xml里的代码:
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="${relativePackage}.${activityClass}" >
        <!-- GridView组件-->
        <GridView 
           android:id="@+id/grid01"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:gravity="center"
           android:verticalSpacing="10dp"
           android:numColumns="2"
            ></GridView>
    <!--   android:gravity="center" 限定它里面的内容要居中显示
           android:verticalSpacing="10dp"  //两行之间的边距
           android:numColumns="2" //GridView的列数设置为2-->
    </LinearLayout>
    B.rlgridview01_layout.xml里的代码
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!-- 设置图片 -->
        <ImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:layout_centerHorizontal="true"
            android:adjustViewBounds="true"
            android:maxWidth="150dp"
            android:maxHeight="150dp"
            android:src="@drawable/ic_launcher"
            />
        <!-- 设置名字 -->
        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:layout_below="@id/image"
            android:layout_centerHorizontal="true"
            android:text="姓名"
            android:textSize="20sp"
            />
    </RelativeLayout>
    C.自定义适配器:CustomAdapter.java里的代码
    /**
     * 自定义适配器
     * @author Administrator
     */
    public class CustomAdapter extends BaseAdapter {
    // 声明加载xml类的对象
    private LayoutInflater layoutInflater;// 找res/layout/下的xml布局文件,
    // 声明上下文对象,通过构造器传值
    private Context context;
    // 声明数据源
    private List<Map<String, Object>> mDatas;
    // 定义构造器,创建对象 初始化 传值
    public CustomAdapter(Context context, List<Map<String, Object>> mdatas) {
    this.context = context;
    this.mDatas = mdatas;
    layoutInflater = LayoutInflater.from(context);
    }
    // 重写父类的方法
    public int getCount() {
    // 返回适配器共有多少条数据或item
    return mDatas.size();
    }
    // 重写父类的方法
    public Object getItem(int position) {
    // 返回此索引position对应的数据项
    return mDatas.get(position);
    }
    // 重写父类的方法
    public long getItemId(int position) {
    // 返回此索引position对应的item的id
    return position;
    }
    // 自定义适配器的优化:缓存view(convertView) + ViewHolder静态类
    // 定义一个静态类,来缓存已经创建的 item布局中的 组件对象,避免重复 调用findViewById方法
    static class ViewHolder {
    ImageView image;
    TextView name;
    }
    // 重写父类的方法
    public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder = null;
    // 如果存储convertView 为null,说明 listView的第一页被加载了,这时候 会调用
    // convertView = mInflater.inflate(R.layout.sa_item, parent,
    // false);来加载item的布局,
    // 并且 通过findViewById来得到item布局中的每一个组件对象
    if (convertView == null) {
    convertView = layoutInflater.inflate(R.layout.rlgridview01_layout, parent, false);
    viewHolder = new ViewHolder();
    // 通过VieHolder来包装xml布局中用到的组件,得到组件对象(此处没有上下文环境,所以不可以使用上下文中的方法findViewById方法)
    viewHolder.image = (ImageView) convertView.findViewById(R.id.image);
    viewHolder.name = (TextView) convertView.findViewById(R.id.name);
    // 设置Tag,tag标示
    convertView.setTag(viewHolder);
    } else {
    // 得到tag
    viewHolder = (ViewHolder) convertView.getTag();
    }
    // 给组件对象设置值
    viewHolder.image.setImageResource((Integer) mDatas.get(position).get("image"));
    viewHolder.name.setText((String) mDatas.get(position).get("name"));
    return convertView;
    }
    }
    D.MainActivity.java里的代码:
    /**
     * GridView组件
     * @author Administrator
     */
    public class MainActivity extends Activity {

    GridView grid;
    int[] imageIds={R.drawable.huixin,R.drawable.jingjing,R.drawable.ruo,R.drawable.ruodan,R.drawable.yifei};
    String[] name={"彗星","箐箐","洛丹","小妹","一菲"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //得到GridView对象
    grid=(GridView)findViewById(R.id.grid01);
    //定义一个集合形式的数据源
    List<Map<String,Object>> listItem=new ArrayList<Map<String,Object>>();
    //把数据放入集合数据源中
    for (int i = 0; i < imageIds.length; i++) {
    Map<String,Object> item=new HashMap<String, Object>();
    item.put("image", imageIds[i]);
    item.put("name", name[i]);
    listItem.add(item);
    }
    /*//实例化SimpleAdapter适配器
    SimpleAdapter simpleAdapter=new SimpleAdapter(this,listItem,R.layout.rlgridview01_layout,
    new String[]{"image","name"},
    new int[]{R.id.image,R.id.name});
    //设置适配器
    grid.setAdapter(simpleAdapter);*/
    //实例化自定义的适配器
    CustomAdapter ca=new CustomAdapter(this,listItem);
    //设置适配器
    grid.setAdapter(ca);
    }

    }


    Gallery画廊和ImageSwitcher图片切换器
      1.Gallery的简介
        Gallery(画廊)是一个锁定中心条目并且拥有水平滚动列表的视图,一般用来浏览图片,并且可以响应事件显示信息。Gallery还可以和ImageSwitcher组件结合使用来实现一个通过缩略图来浏览图片的效果。

    Gallery常用的XML属性


    2.首先介绍Gallery单独使用的例子:
    MainActivity.java
    package com.android.gallerydemo;  
     
    import android.app.Activity;  
    import android.content.Context;  
    import android.os.Bundle;  
    import android.view.View;  
    import android.view.ViewGroup;  
    import android.widget.AdapterView;  
    import android.widget.AdapterView.OnItemClickListener;  
    import android.widget.BaseAdapter;  
    import android.widget.Gallery;  
    import android.widget.ImageView;  
    import android.widget.Toast;  
     
    public class MainActivity extends Activity {  
     
       private Gallery gallery;  
        @Override 
        public void onCreate(Bundle savedInstanceState) {  
     
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.main);  
            gallery = (Gallery)findViewById(R.id.gallery);  
            //设置图片适配器  
            gallery.setAdapter(new ImageAdapter(this));  
            //设置监听器  
            gallery.setOnItemClickListener(new OnItemClickListener() {  
             @Override 
             public void onItemClick(AdapterView<?>parent, View v, int position, long id) {  
                Toast.makeText(MainActivity.this, "点击了第"+(position+1)+"张图片", Toast.LENGTH_LONG).show();  
             }  
         });  
        }  
    }  
     
    class ImageAdapter extends BaseAdapter{  
      //声明Context   
      private Context context;  
      //图片源数组  
      private Integer[] imageInteger={  
             R.drawable.pic1,  
             R.drawable.pic2,  
             R.drawable.pic3,  
             R.drawable.pic4,  
             R.drawable.pic5,  
             R.drawable.pic6,  
             R.drawable.pic7  
      };  
        
      //声明 ImageAdapter  
      public ImageAdapter(Context c){  
         context = c;  
      }  
     
      @Override 
      //获取图片的个数  
      public int getCount() {  
         return imageInteger.length;  
      }  
     
      @Override 
      //获取图片在库中的位置  
      public Object getItem(int position) {  
     
         return position;  
      }  
     
      @Override 
      //获取图片在库中的位置  
      public long getItemId(int position) {  
         // TODO Auto-generated method stub  
         return position;  
    }  
     
      @Override 
      public View getView(int position, View convertView, ViewGroup parent) {  
     
         ImageView imageView = new ImageView(context);  
         //给ImageView设置资源  
         imageView.setImageResource(imageInteger[position]);  
         //设置比例类型  
         imageView.setScaleType(ImageView.ScaleType.FIT_XY);  
         //设置布局 图片128x192显示  
         imageView.setLayoutParams(new Gallery.LayoutParams(128, 192));  
         return imageView;  
      }  
    }  
     
     
    main.xml
    <?xml version="1.0" encoding="utf-8"?> 
    <Gallery xmlns:android="http://schemas.android.com/apk/res/android"   
          android:id="@+id/gallery"         
          android:layout_width="fill_parent" 
          android:layout_height="wrap_content" 
          android:gravity="center_vertical" 
          android:background="?android:galleryItemBackground" 

    /> 


    AlertDialog对话框
    1. 创建AlertDialog.Build的对象,
    2. 调用AlertDialog.Build的方法,设置图标 标题 内容等
    3. AlertDialog.Build的create()
    4. AlertDialog的show()
    5. activity里的代码:
    /**
     * 对话框
     * @author Administrator */
    public class MainActivity extends Activity {
    private TextView show02;
    private Button button;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 对话框
    setContentView(R.layout.activity_main);
    show02 = (TextView) findViewById(R.id.show02);
    button = (Button) findViewById(R.id.button);
    // 按钮的点击监听事件
    button.setOnClickListener(listen);
    }
    // 监听事件
    android.view.View.OnClickListener listen = new android.view.View.OnClickListener() {
    // 点击方法
    public void onClick(View v) {
    simple();
    }
    };
    // 创建对话框
    protected void simple() {
    //对话框的内容
    AlertDialog.Builder builder = new AlertDialog.Builder(this).
    // 设置对话框标题
    setTitle("简单的对话框")
    // 设置图标
    .setIcon(R.drawable.ic_launcher)
    // 定义对话框内容
    .setMessage("对话框的测试内容\n第二行内容");
    //对话框中显示确定按钮
    setPositiveButton(builder);
    //对话框中显示退出按钮
    setNegativeButton(builder);
    //显示对话框
    builder.create().show();
    }
    //确认按钮的点击监听事件的方法
    private AlertDialog.Builder setPositiveButton(AlertDialog.Builder builder)
    {
    return builder.setPositiveButton("确认", new OnClickListener() {
    //确定按钮的点击事件
    public void onClick(DialogInterface dialog, int which) {
    show02.setText("点击了【确定】按钮");
    }
    });
    }
    // 退出按钮的点击监听事件的方法
    private AlertDialog.Builder setNegativeButton(AlertDialog.Builder builder)
    {
    return builder.setNegativeButton("取消", new OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
    show02.setText("点击了【取消】按钮");
    }
    });
    }
    1. 更多案例在Android知识点的文件夹里

    2. 展示:


    PopupWindow的显示与关闭:弹出(框)效果
    1. PopupWindow的效果就类似一个固定的小窗口
    2. 使用PopupWindow创建对话框风格的窗口只需要两步:
    A.调用Popupwindow的构造器创建对象
    B.调用PopU盘window的showAsDropDown(View01)将PopupWindow作为View01组件的下落组件显示出来; 或者 调用PopupWindow的showAtLocation方法将PopupWindow在指定的位置显示出来
    1. 得到Activity里的代码:
    public class MainActivity extends Activity {
    private Context context; //得到上下文
    private PopupWindow pw;//弹出框组件
    private Button btn;
    private LinearLayout llayout;//线性布局
    private int width;//宽
    private int height;//高
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    context=MainActivity.this;
    btn=(Button)findViewById(R.id.btn);
    llayout=(LinearLayout)findViewById(R.id.llayout);
    //给按钮设置监听器
    btn.setOnClickListener(listen);
    }
    //按钮的点击事件
    OnClickListener listen=new OnClickListener(){
    public void onClick(View v) {
    //弹窗框有内容时,点击按钮会把内容销毁
    if(pw!=null && pw.isShowing())
    {
    pw.dismiss();//销毁popupWindow对象 外观
    pw=null;
    btn.setText("展开PopupWindow");
    }else
    {
    //得到llppw_layout的Xml的视图
    View view=LayoutInflater.from(context).inflate(R.layout.llppw_layout, null);
    width=btn.getWidth();
    height=llayout.getHeight();
    pw=new PopupWindow(view,width,height,true);
    //pw.setFocusable(false);和pw.setOutsideTouchable(false);最好设置一下,
    //否则Popupwindow展开之后,Popup之外的地方可能就无法获得焦点,就是无法点击btn
    pw.setFocusable(false); 
    pw.setOutsideTouchable(false); 
    //设置popuwindow的显示方式,作为btn组件的下落视图显示
    pw.showAsDropDown(btn,0,0);
    btn.setText("关闭PopupWindow");
    }}};}
    1. 展示:

     

    Toast(消息提示 )
    1. Toast用法:
    2. 调用makeText 方法来创建一个Toast对象
    3. 调用Toast的show()方法将其显示出来
    4. 代码展示
    /**
     * Toast:是一个类,主要管理消息的提示。
     * @author Administrator
     *
     */
    public class MainActivity extends Activity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button btn=(Button)findViewById(R.id.btn);
    //按钮的监听事件
    btn.setOnClickListener(new OnClickListener(){
    //按钮的点击事件
    public void onClick(View v) {
    //makeText(),是Toast的一个方法,用来显示信息,分别有三个参数。
    //Toast.LENGTH_LONG,指你提示消息显示的时间,有3秒
    Toast.makeText(MainActivity.this,"我很闷骚", Toast.LENGTH_LONG).show();
    }
    });
    }
    //第二个按钮的点击事件
    public void toastButton(View v)
    {
    Toast.makeText(MainActivity.this, "我明骚", Toast.LENGTH_SHORT).show();
    }
    WebView:加载网页的组件,WebView是android特有的
    1. 代码展示:
    public class OtherActivity extends Activity {
    //加载网页的组件,WebView是android特有的
    private WebView webView;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //表示设置当前的Activity 无Title(Android的标题)并且全屏调用这个方法有个限制,即必须在setContentView(R.layout.main);之前调用,否则会抛出异常
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_other);
    //天猫网址
    String url="https://shouji.tmall.com/?spm=875.7931836/A.subpannel2016040.8.84xzLJ&acm=2016030713.1003.2.709043&aldid=5JbSSboQ&scm=1003.2.2016030713.OTHER_1460877513687_709043&pos=8#floor4";
    //获取xml里的WebView组件对象
    webView=(WebView)findViewById(R.id.webView);
    //定义WebView的设置类的对象
    WebSettings wSet=webView.getSettings();
    //WebView基于webkit引擎展现web页面的控件,使用前需要在Android Manifest file中配置internet访问权限,否则提示页面无法访问。
    //WebViewClient会在一些影响内容喧嚷的动作发生时被调用,比如表单的错误提交需要重新提交、页面开始加载及加载完成、资源加载中、接收到http认证需要处理、页面键盘响应、页面中的url打开处理等等

    //默认情况下,点击webview中的链接,会使用Android系统自带的浏览器打开这个链接。如果希望点击链接继续在我们自己的Browser(浏览器)中响应,必须覆盖 webview的WebViewClient对象:
    //给WebView加一个监听
    webView.setWebViewClient(new WebViewClient(){
    //对网页中超链接按钮的响应。当按下某个连接时WebViewClient会调用这个方法,并传递参数:按下的url。
    public boolean shouldOverrideUrlLoading(WebView wView,String url)
    {
    //在当前的webview中跳转到新的url
    wView.loadUrl(url);
    return true;
    }
    });
    webView.loadUrl(url);
    }
    }
    Notification(通知)
    1. 实现通知一遍有以下几个步骤:
    2. 调用getSystemServer(....) 方法获得系统的通知服务器对象NotificationManager
    3. 通过构造器创建一个Notification对象
    4. 为Notification设置各种属性
    4.通过NotificationManager发送Notification
    1. 代码展示:
    /**
     * Notification:通知管理器,Notification:是可以设置icon、文字、提示声音、振动等等参数
     *  我们在用手机的时候,如果来了短信,而我们没有点击查看的话,是不是在手机的最上边的状态栏里有一个短信的小图标提示啊?
     *  你是不是也想实现这种功能呢?今天的Notification就是解决这个问题的。
     * @author Administrator */
    public class MainActivity extends Activity {
    //定义一个Id 标示通知
    static final int NOTIFICATION_ID = 0x123;
    //声明一个通知服务
    NotificationManager nm;

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //获取系统的NoficationManager的服务
    nm=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
    }
    //为发送通知的按钮的点击事件定义事件处理方式
    public void send(View view)
    {
    //创建一个启动其他Activity的Intent
    //定义一个Intent对象,通过OtherActivity里的WebView跳转到网页
    Intent intent=new Intent(this,OtherActivity.class);
    //跳转
    PendingIntent pIntent=PendingIntent.getActivity(this, 20, intent, 20);
    //创建Notification对象,并且设置各种属性
    Notification notifi=new Notification.Builder(this)
    .setAutoCancel(true)//设置通知,这个通知会自动消失
    .setTicker("天猫三星促销")//设置显示在状态栏的通知提示信息
    .setSmallIcon(R.drawable.notify)//设置通知的图片
    .setContentTitle("天猫")//设置通知内容的标题
    .setContentText("双11 美女大促销,全民狂欢!")//设置通知内容
    //设置声音    声音的路径是本地工程
    .setSound(Uri.parse("android.resource://com.cm.android05_notification/"+R.raw.msg))
    声音的路径是sdcard
    //.setSound(Uri.parse("file://sdcard/click.mp3"))
    .setWhen(System.currentTimeMillis())//设置当前系统事件
    .setContentIntent(pIntent).build();//设置通知将要启动程序的Intent
    //发送通知
    nm.notify(NOTIFICATION_ID, notifi);
    }
    //为删除通知的按钮的点击事件定义事件处理方式
    public void del(View v)
    {
    //取消通知
    nm.cancel(NOTIFICATION_ID);
    }
    }

    1. 图片展示


    携程首页之Animation动画
    /**
     * 携程首页
     * @author Administrator */
    public class WelcomeActivity extends Activity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //隐藏Title
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.welcome_layout);

    //得到Xml里的组件
    TextView tv01 = (TextView)findViewById(R.id.activity_welcome_tv);
    TextView tv02 = (TextView)findViewById(R.id.activity_welcome_tv2);
    //Animation实现UI界面动画效果
    Animation animation=AnimationUtils.loadAnimation(this, R.anim.textview);
    Animation animation2=AnimationUtils.loadAnimation(this, R.anim.textview2);
    //在TextView组件里设置这个动画
    tv01.setAnimation(animation);
    tv02.setAnimation(animation2);
    //Handler主线程和子线程之间的信使,实现UI线程的更新的
    new Handler().postDelayed(new Runnable(){
    //使用PostDelayed方法,两秒后调用此Runnable对象,实际上也就实现了一个5s的一个定时器
    public void run() {
    //startActivity()仅仅是跳转到目标页面,若是想跳回当前页面,则必须再使用一次startActivity(),启动另一个activity的效果
    //从WelcomeActivity页面跳到MainActivity
    startActivity(new Intent(WelcomeActivity.this,MainActivity.class));
    //overridePendingTransition()的作用:实现两个 Activity 切换时的动画。在Activity中使用有两个参数:进入动画和出去的动画
    overridePendingTransition(R.anim.left,R.anim.right);
    //关闭WelcomeActivity
    WelcomeActivity.this.finish();
    }}, 5000);//动画结束后等待5秒进入下一个界面
    }
    public boolean onKeyDown(int keyCode,KeyEvent event)
    {
    if(keyCode==KeyEvent.KEYCODE_BACK)
    {
    WelcomeActivity.this.finish();
    return false;
    }
    return true;
    }


    OnTouchListener触摸事件和onTouchEvent触摸事件
    1. OnTouchEvent()方法:是获取的对屏幕的各种操作,比如向左向右滑动,点击返回按钮等等。
    2. OnTouchListener()方法:是获取某一个控件某一个View的点击监控。
    3. 两者的区分:
    1、如果setOnTouchListener中的onTouch方法返回值是true(事件被消费)时,则onTouchEvent方法将不会被执行;
    2、只有当setOnTouchListener中的onTouch方法返回值是false(事件未被消费,向下传递)时,onTouchEvent方法才被执行。
    3、以上说的情况适用于View对象(事件会最先被最内层的View对象先响应)而不是ViewGroup对象(事件会最先被最外层的View对象先响应)。
    综合来讲:
    onTouchListener的onTouch方法优先级比onTouchEvent高,会先触发。
    假如onTouch方法返回false,会接着触发onTouchEvent,反之onTouchEvent方法不会被调用。
    内置诸如click事件的实现等等都基于onTouchEvent,假如onTouch返回true,这些事件将不会被触发。
    1. 代码展示:
    public class MainActivity extends Activity {
    public Button myButton;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //得到XML里的Button组件
    myButton=(Button)findViewById(R.id.myButton);
    //虽然在UI组件MyButton中重写了父类的相应方法,但仍然可以在绑定一个事件监听器
    myButton.setOnTouchListener(new OnTouchListener(){
    public boolean onTouch(View v, MotionEvent event) {
    System.out.println("处理OnTouchListener的触摸事件");
    switch (event.getAction()) {
    // 按下
    case MotionEvent.ACTION_DOWN:
    Log.e("down", " 处理OnTouchListener down ");
    break;
    // 松开
    case MotionEvent.ACTION_UP:
    Log.e("up", "处理OnTouchListener  UP ");
    break;
    // 其他动作状态
    default:
    Log.e("----", "处理OnTouchListener 其他动作状态 ");
    break;
    }
    //只有当setOnTouchListener中的onTouch方法返回值是false(事件未被消费,向下传递)时,onTouchEvent方法才被执行
    return false;
    }
    });
    }
    //重写父类的onTouchEvent方法
    public boolean onTouchEvent(MotionEvent event) {
    System.out.println("处理activity触摸事件");
    //设置返回false,表明这个未完全处理触摸事件,触摸事件将继续向外扩散
    return true;
    }}


    混合编程,在XML不定义组件,在java中用代码实现;实现图片的点击更换
    1. Xml中:
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/root_layout"
      android:orientation="vertical">


    </LinearLayout>
    1. MainActivity 中代码的实现:
    public class MainActivity extends Activity {
    //图片展示数据源
    int[] pics={R.drawable.huixin,R.drawable.jingjing,R.drawable.ling
    ,R.drawable.luojing,R.drawable.mochou,R.drawable.naichai};
    //初始值
    int currentPic=0;
    ImageView pic;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //将一个XML布局展现在一个Activity中
    setContentView(R.layout.activity_main);
    //通过Id获取线性布局的对象
    LinearLayout l_layout=(LinearLayout)findViewById(R.id.root_layout);
    //向布局中添加一些组件之前,必须先创建创建出来一些UI组件,代码来创建ImageView的对象
    pic=new ImageView(this);
    //定义长和宽(若不设置 用默认值)
    pic.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
    //将定义的组件添加到布局中
    l_layout.addView(pic);
    //展示一张图片
    pic.setImageResource(pics[0]);
    //图片的监听点击事件
    pic.setOnClickListener(new OnClickListener(){
    //图片的点击方法
    public void onClick(View v) {
    //因为图片数据源数组的长度为5,若不进行 元素索引判断,则会引发数组越界异常。
    //当索引 等于5的时候,说明 这个元素正是数组的最后一个元素,此时必须将索引值currentPic强制初始化
    if(currentPic>5)
    {
    currentPic=0;
    }
    //展示一张图片
    pic.setImageResource(pics[currentPic++]);
    }});}}


    Intent意图
    1. 显示跳转和隐式跳转:最主要的区别是隐式跳转中有:intent.setData(Uri.parse("meinv:隐式意图传递的参数"));隐式意图:在实现一个功能的时候,只是在指定一个动作,只要符合这个动作的组件都会被启动。隐式意图 是符合android、window等系统设计思想的,这是一种优秀的设计思想。
    MainActivity.java中的代码:
    /**
     * Intent 意图:就是启动其他组件,也是组件之间数据传递的重要媒介
     * @author Administrator
     *
     */
    public class MainActivity extends Activity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    }
    //Intent 意图:就是启动其他组件,也是组件之间数据传递的重要媒介
    //显示跳转
    public void btn_intent(View v)
    {
    /*//创建Intent对象
    Intent i=new Intent();
    //调用intent的方法,来指定将要启动的  类.class(另一个Activity)
    i.setClass(this, OtherActivity.class);
    //启动这个Intent意图
    startActivity(i);*/

    //创建Intent对象,并指定将要启动的  类.class(另一个Activity)
    Intent i=new Intent(this,OtherActivity.class);//此句表示显式意图,因为明确设置激活对象为Other类
    //启动这个Intent意图
    startActivity(i);
    }
    //隐式跳转
    public void btn_i_filter(View v)
    {
    Intent intent=new Intent();
    //调用intent的setAction方法,这个方法的形参为咱们在清单文件中 自定义动作匹配
    intent.setAction("com.cn.intent");//此句只是指定了Action
    //如果自己定义的某个Activity要通过隐式启动,在AndroidManifest.xml那么必须加上android.intent.category.DEFAULT,否则不起作用
    intent.addCategory("android.intent.category.DEFAULT");
    //隐式意图 传递参数
    intent.setData(Uri.parse("meinv:隐式意图传递的参数"));
    startActivity(intent);
    }
    //显示跳转
    public void btn_gallery(View v)
    {
    Intent intent = new Intent();
    //会话位置|指定要激活的具体的Activity
    intent.setClassName("com.android.gallery","com.android.camera.GalleryPicker");
    startActivity(intent);
    }
    public void btn_contacts(View v)
    {
    /*//显示启动,"com.android.contacts.activities.PeopleActivity" sdk API >=17 都可以。
    //但是 若在API=10 的,模拟器上 就报错啦,找不到对应的 类
    Intent intent = new Intent();
    intent.setClassName("com.android.contacts","com.android.contacts.activities.PeopleActivity");
    startActivity(intent);*/

    /*//隐式调用拨打电话的界面,没有形参的意图
    Intent intent=new Intent();
    //通过对应的动作Intent.ACTION_DIAL 启动拨打电话的界面
    intent.setAction(Intent.ACTION_CALL);
    //传入参数 电话号码
    intent.setData(Uri.parse("tel:"+"13766367322"));
    //启动意图
    startActivity(intent);*/
    //隐式意图  启动浏览器
    Intent intent=new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse("http://www.baidu.com"));
    startActivity(intent);
    }
    }
    OtherActivity.java中的代码:
    public class OtherActivity extends Activity {


    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_other);
    //获取控件
    TextView tv=(TextView)findViewById(R.id.tv_other);
    //获取启动OtherActivity的intent的意图对象
    Intent intent=getIntent();
    //获取隐式传递的参数
    Uri uri=intent.getData();
    String result=uri.toString();
    tv.setText(result);
    }
    }
    AndroidManifest.xml里的代码:
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.android07_intent"
        android:versionCode="1"
        android:versionName="1.0" >
        <uses-sdk
            android:minSdkVersion="8"
            android:targetSdkVersion="23" />
    <uses-permission android:name="android.permission.CALL_PHONE"/>
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity
                android:name=".OtherActivity"
                android:label="@string/title_activity_other" >
                 <!--在OtherActivity注册信息中自定义intent-filter标签  -->
                   <intent-filter>
                       <!-- action 动作匹配 -->
                    <action android:name="com.cn.intent" />
      <!--category 动作匹配附加项 ,这里啊  咱们使用默认值  -->
                    <category android:name="android.intent.category.DEFAULT" />
                     <!--使用data定义隐式意图 中床底函数   什么类型  -->
                    <!-- 使用 android:scheme ,scheme 是规范的意思,规范数据类型,程序员可以自己定义  -->
                    <data android:scheme = "meinv"/>
                </intent-filter>
            </activity>
        </application>
    </manifest>
    1. Intent意图传参
    MainActivity.java代码:通过intent.putExtra("names", name);标示传(保存)值
    /**
     * Intent意图传参
     * @author Administrator
     */
    public class MainActivity extends Activity {
    private EditText et_name,et_age;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    et_name=(EditText)findViewById(R.id.et_name);
    et_age=(EditText)findViewById(R.id.et_age);
    }
    //按钮的点击
    public void clickButton(View v)
    {
    String name=et_name.getText().toString().trim();
    String age=et_age.getText().toString().trim();
    int ageInt=Integer.parseInt(age);//Integer.valueOf(age)
    //对于一个UI界面中,当判断用户是否输入用户名或密码时,我们常用TextUtils.isEmpty()方法来判断;因为你从EditText返回的是一个变量。
    //如果这个变量本身为null值,那么你掉它的equals方法是要报错的。但是如果你调用TextUtils.isEmpty() 把这个变量作为参数传进去。
    //只要这个参数为空或者为“”,都会返回真
    if(TextUtils.isEmpty(name))//如果没有输入名字
    {
    Toast.makeText(this, "请输入名字", Toast.LENGTH_SHORT).show();
    }
    //跳转到另一个activity,用意图
    Intent intent=new Intent(this,OtherActivity.class);
    //putExtra("A",B)中,AB为键值对,第一个参数为键名,第二个参数为键对应的值。顺便提一下,如果想取出Intent对象中的这些值,
    //需要在你的另一个Activity中用getXXXXXExtra方法,注意需要使用对应类型的方法,参数为键名
    intent.putExtra("names", name);
    intent.putExtra("ages", age);
    //启动意图
    startActivity(intent);
    }
    }
    OtherActivity.java里的代码:通过getIntent().getStringExtra(“name”);来获取值
    /**
     * Intent意图传参
     * @author Administrator
     */
    public class OtherActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_other);
    TextView tv_result=(TextView)findViewById(R.id.tv_result);
    //得到意图对象
    Intent intent=getIntent();
    //通过预定好的标示,从intent中得到数据
    //String name=getIntent().getStringExtra("names");
    string name=intent.getStringExtra("names");
    //如果没有传值,默认值为18
    int age=intent.getIntExtra("ages", 18);
    //通过随机数random来任意定义一个IQ值
    Random random=new Random();
    int r_iq=random.nextInt(100);
    tv_result.setText("姓名:"+name+",年龄:"+age+",IQ:"+r_iq);
    }
    }
    1. 返回值的传参:下一个Acyivity的参数可以返回给上一个Activity中
    1.//启动意图
    /*startActivityForResult与startActivity的不同之处在于:
    1、startActivity( ) 
    仅仅是跳转到目标页面,若是想跳回当前页面,则必须再使用一次startActivity( )。
    2、startActivityForResult( ) 
    可以一次性完成这项任务,当程序执行到这段代码的时候,假若从T1Activity跳转到下一个Text2Activity, 而当这个Text2Activity
    调用了finish()方法以后,程序会自动跳转回T1Activity,并调用前一个T1Activity中的 onActivityResult( )方法。*/
    2. MainActivity里的代码:
    /**
     * 跳转到目标页面,若是想跳回当前页面并在当前页面获得目标页面中的数据,用startActivityForResult(intent, 100);启动Intent意图
     * @author Administrator */
    public class MainActivity extends Activity {
    private TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    tv=(TextView)findViewById(R.id.tv);
    }
    public void btn01(View v)
    {
    //意图
    Intent intent=new Intent(this,SecondActivity.class);
    //启动意图
    /*startActivityForResult与startActivity的不同之处在于:
    1、startActivity( ) 
    仅仅是跳转到目标页面,若是想跳回当前页面,则必须再使用一次startActivity( )。
    2、startActivityForResult( ) 
    可以一次性完成这项任务,当程序执行到这段代码的时候,假若从T1Activity跳转到下一个Text2Activity,而当这个Text2Activity
    调用了finish()方法以后,程序会自动跳转回T1Activity,并调用前一个T1Activity中的onActivityResult( )方法。*/
    //startActivity(intent);
    startActivityForResult(intent, 100);
    }
    public void btn02(View v)
    {
    //意图
    Intent intent=new Intent(this,ThreeActivity.class);
    //启动意图
    startActivityForResult(intent,101);
    }
    //重写父类的方法onActivityResult()来处理一些已经绑定了requestCode的activity可能返回的数据
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {//通过第一个参数requestCode来辨别数据来自哪个activity
    case 100://通过requestCode=100来筛选出SecondActivity返回的数据
    switch (resultCode) {//通过第二个参数resultCode来筛选出具体是SecondActivity哪个功能模块返回的数据
    case 0:
    //通过第三个参数data可以传递数据,通过intent将其它的activity的数据携带到当前的activity中
    String result01=data.getStringExtra("result");
    tv.setText(result01);
    break;
    case 1:
    String result02=data.getStringExtra("result01");
    tv.setText(result02);
    break;
    }
    break;
    case 101://通过requestCode=101 来筛选出ThreeActivity返回的数据
    switch (resultCode) {
    case RESULT_OK:
    String result03=data.getStringExtra("result03");
    tv.setText(result03);
    break;
    default:
    break;
    }
    break;}}}
    2. SecondActivity里的代码:
    public class SecondActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
    }
    public void second_btn01(View v)
    {
    //得到意图
    Intent intent=getIntent();
    EditText et=(EditText)findViewById(R.id.et);
    String res=et.getText().toString();
    //putExtra保存值
    intent.putExtra("result", res);
    //传递参数,返回值;返回数据给上一个Activity的
    setResult(0, intent);
    finish();
    }
    public void second_btn02(View v)
    {
    //得到意图
    Intent intent=getIntent();
    intent.putExtra("result01", "好热啊");
    //传递参数,返回值;返回数据给上一个Activity的
    setResult(1,intent);
    finish();
    }
    }
    2. ThreeActivity代码:
    public class ThreeActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_three);
    }
    public void btn_three(View v)
    {
    EditText et03=(EditText)findViewById(R.id.et_three);
    String res=et03.getText().toString();
    Intent intent=getIntent();
    //putExtra保存值
    intent.putExtra("result03", res);
    setResult(RESULT_OK, intent);
    finish();}
    }


    登录界面之文字变换的事件响应方法onTextChanged()和焦点改变方法onFocusChanged()与输入框清除图标和功能的实现
    1. 自定义输入框(EditTextWithClearButton.java):
    /**
     * 自定义输入框
     * @author Administrator */
    public class EditTextWithClearButton extends EditText {
    // 构造函数
    public EditTextWithClearButton(Context context) {
    super(context);
    }
    public EditTextWithClearButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    }
    public EditTextWithClearButton(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    }
    // 在TextView中集成了接口TextWatcher,并且也重写了文字变换的事件响应方法和焦点改变方法,所以子类EditTextWithClearButton中直接来重写父类中的
    // 文字变化的事件响应方法 onTextChanged和焦点改变方法onFocusChanged()
    // onTextChanged参数解释及实现EditText字数监听,文本框里的内容变化是会触发OnTextChanged事件
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
    super.onTextChanged(text, start, lengthBefore, lengthAfter);
    // getCompoundDrawables()这个方法返回的是一个Drawable[]数组,这个数组有4个元素,分别为TextView的左上右下
    // 4个方向的drawable对象,
    // 通过这些Drawable对象 可以分别为一个TextView的左上右下 这几个方向添加图片
    Drawable[] draw = getCompoundDrawables();
    // 如果输入框里面的文本字符长度不为0,且有焦点,则给这个输入框的右边 动态的添加一个 删除的图标
    if (!getText().toString().equals("") && hasFocus()) {
    setCompoundDrawablesWithIntrinsicBounds(draw[0], draw[1],
    getContext().getResources().getDrawable(R.drawable.ic_clear), draw[3]);
    } else {
    // 因为draw数组中无图片
    setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
    }
    // 最后调用invalidate()方法来刷新
    invalidate();
    }
    // onFocusChanged只能在View中重写。该方法是焦点改变的回调方法,当某个控件重写了该方法后,当焦点发生变化时,会自动调用该方法来处理焦点改变事件
    // 参数focused:参数gainFocus表示触发该事件的View是否获得了焦点,当该控件获得焦点时,gainFocus等于true,否则等于false。
    // 参数direction:参数direction表示焦点移动的方向,用数值表示。
    // 参数previouslyFocusedRect:表示触发事件的View的坐标系中,前一个获得焦点的矩形区域,即表示焦点是从哪里来的。如果不可以则为null。
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
    super.onFocusChanged(focused, direction, previouslyFocusedRect);
    // getCompoundDrawables()这个方法返回的是一个Drawable[]数组,这个数组有4个元素,分别为TextView的左上右下
    // 4个方向的drawable对象,
    // 通过这些Drawable对象 可以分别为一个TextView的左上右下 这几个方向添加图片
    Drawable[] draw = getCompoundDrawables();
    // 如果输入框里面的文本字符长度不为0,且有焦点,则给这个输入框的右边 动态的添加一个 删除的图标
    if (!getText().toString().equals("") && hasFocus()) {
    setCompoundDrawablesWithIntrinsicBounds(draw[0], draw[1],
    getContext().getResources().getDrawable(R.drawable.ic_clear), draw[3]);
    } else {
    // 因为draw数组中无图片
    setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
    }
    // 最后调用invalidate()方法来刷新
    //invalidate();  --- UI线程中
    //postInvalidate(); ---- 非UI线程中
    invalidate();
    }
    // 重写(覆盖)父类中的方法 onTouchEvent(MotionEvent event) ,当用户手指触摸此组件 会触发这个方法,并且 在这里
    // 定义根据业务需求实现的逻辑代码
    public boolean onTouchEvent(MotionEvent event) {
    boolean re = super.onTouchEvent(event);
    // 当你在屏幕上 操作了,类MotionEvent能够知道你的 具体动作
    switch (event.getAction()) {// event.getAction()得到你的具体动作状态
    case MotionEvent.ACTION_DOWN:// 当触摸动作按下的时候,啥都不做
    break;
    case MotionEvent.ACTION_UP:// 当触摸动作松开的时候
    //左上右下 这几个方向添加图片
    Drawable[] drawable = getCompoundDrawables();
    // 如果右边的drawable不为null,说明这个删除图标 是存在的,正在显示在组件上;点击这个 删除图标 应该是输入框中的内容清空,且 删除图片 消失
    if(drawable[2]!=null)
    {
    /*思路:
    第一步:确定这个删除图标的 位置区域范围(这个图标 是有面积,上下左右 四个边界值 不同)
    第二步:根据MotionEvent的方法 getX 和 getY 来确定 在屏幕上 你的触摸点的(x ,y)
    第三步:若在屏幕上,你的触摸点(x,y)在 删除图片的区域范围内,则 清空文本字符串 和 让删除图标 消失。
    定义是 删除图标 的左边距*/
    int left=getWidth()-getPaddingRight()-drawable[2].getIntrinsicWidth();
    //定义是 删除图标 的右边距
    int right=getWidth()-getPaddingRight();
    //定义是 删除图标 的上边距
    int top=getPaddingTop();
    //定义是 删除图标 的下边距
    int bottom=getHeight()-getPaddingTop();
    //若在 删除图片的范围内,则说明触摸了 这个删除图标
    if(event.getX()<right&&event.getX()>left&&event.getY()>top&&event.getY()<bottom)
    {
    setText("");
    }
    }
    break;
    default:
    break;
    }
    return re;}}
    1. MainActivity里的代码:
    public class MainActivity extends Activity {
    private TextView title, left_btn;
    private Button login_sign_in;
    private CheckBox login_keep_password;
    private Context context;
    private Spinner mSpinnerIdType;
    private EditTextWithClearButton login_number;
    private EditTextWithClearButton login_password;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.member_layout);
    context = getApplicationContext();
    // 获取组件
    title = (TextView) findViewById(R.id.title_txt);
    // 给组件设值
    title.setText(R.string.login_tab_title);
    //返回组件
    left_btn = (TextView) findViewById(R.id.left_btn);
    left_btn.setVisibility(View.VISIBLE);
    left_btn.setOnClickListener(mOnClick);
    //登录组件
    login_sign_in = (Button)findViewById(R.id.login_sign_in);
    login_sign_in.setOnClickListener(mOnClick);
    //证件输入框
    login_number = (EditTextWithClearButton)findViewById(R.id.login_id_number);
    //密码输入框
    login_password = (EditTextWithClearButton)findViewById(R.id.login_id_password);
    //忘记密码点击事件
    findViewById(R.id.login_forget_password).setOnClickListener(mOnClick);
    //下拉菜单组件
    mSpinnerIdType=(Spinner)findViewById(R.id.spinner_id);
    //OnTouchListener()方法,触摸事件;是获取某一个控件某一个View的点击监控。
    mSpinnerIdType.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
    //打开输入法窗口
    //InputMethodManager imm=((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE));
    return false;
    }
    });
    //自定义微调框(下拉菜单)
    //适配器  //R.array.id_types从arrays.xml文件里获取数据源
    //R.array.id_types 数据源的标识符
    //R.layout.my_simple_spinner_item 用于创建视图的布局的标识符
    ArrayAdapter<CharSequence> adapter=ArrayAdapter.createFromResource(context, R.array.id_types, 
    R.layout.my_simple_spinner_item);
    //setDropDownViewResource可以设置下拉菜单的显示方式,将该xml定义在res/layout目录下,可针对下拉菜单中的TextView进行设置
    //R.layout.my_simple_spinner_dropdown_item 定义下拉视图的布局资源
    adapter.setDropDownViewResource(R.layout.my_simple_spinner_dropdown_item);
    //给下拉菜单设值适配器
    mSpinnerIdType.setAdapter(adapter);
    //给下拉菜设值监听事件
    mSpinnerIdType.setOnItemSelectedListener(new OnItemSelectedListener(){
    //下拉菜单的选项的点击事件
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    login_password.setText("");
    }
    @Override
    public void onNothingSelected(AdapterView<?> parent) {
    }
    }); }
    //监听器
    OnClickListener mOnClick = new OnClickListener() {
    public void onClick(View v) {
    switch (v.getId()) {
    case R.id.login_sign_in:
    String name=login_number.getText().toString().trim();
    String pwd=login_password.getText().toString().trim();
    if (name.equals("dawn")&&pwd.equals("123456")) {
    User u=new User();
    //设置值
    u.setUser_name(name);
    u.setUser_pwd(pwd);
    //Intent意图,通过意图来跳转页面和传值
    Intent intent=new Intent(MainActivity.this,OtherActivity.class);
    //putExtra("A",B)中,AB为键值对,第一个参数为键名,第二个参数为键对应的值。顺便提一下,如果想取出Intent对象中的这些值,
    //需要在你的另一个Activity中用getXXXXXExtra方法,注意需要使用对应类型的方法,参数为键名
    intent.putExtra("User",u);
    //设置意图
    startActivity(intent);
    }else
    {
    Toast.makeText(context, "账号(dawn)和密码(123456)不正确,请重新输入", Toast.LENGTH_SHORT).show();
    }
    break;
    case R.id.left_btn:
    Toast.makeText(context, "返回", Toast.LENGTH_SHORT).show();
    finish();
    break;
    case R.id.login_forget_password:
    Toast.makeText(context, "忘记密码", Toast.LENGTH_SHORT).show();
    break;
    default:
    break;
    }}};}
    1. OtherActivity里的代码:
    public class OtherActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_other);
    //获得组件
    TextView result=(TextView)findViewById(R.id.tv_result);
    //获取意图
    Intent intent=getIntent();
    //通过意图获取序列化的对象
    User user=(User)intent.getSerializableExtra("User");
    //赋值
    result.setText("姓名:"+user.getUser_name()+",密码:"+user.getUser_pwd());
    } }
    1. OtherActivity里的代码:
    public class OtherActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_other);
    //获得组件
    TextView result=(TextView)findViewById(R.id.tv_result);
    //获取意图
    Intent intent=getIntent();
    //通过意图获取序列化的对象
    User user=(User)intent.getSerializableExtra("User");
    //赋值
    result.setText("姓名:"+user.getUser_name()+",密码:"+user.getUser_pwd());
    }}
    1. User.java里的代码
    /**
     * 实现了Serializable序列化
     * @author Administrator */
    public class User implements Serializable {
    private String user_name;
    private String user_pwd;
    public String getUser_name() {
    return user_name;
    }
    public void setUser_name(String user_name) {
    this.user_name = user_name;
    }
    public String getUser_pwd() {
    return user_pwd;
    }
    public void setUser_pwd(String user_pwd) {
    this.user_pwd = user_pwd;
    }}




    引导页和引导点的制作
    1. Activity_main.xml里的代码:
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="${relativePackage}.${activityClass}" >
        <!-- 这个TextView模拟一个MainActivity的XML的复杂布局 -->
        <TextView
            android:id="@+id/tv_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hello_world" />
        <!-- 引导页的XML布局   默认:引导页会覆盖在上面的TextView上面 -->
        <RelativeLayout
            android:id="@+id/index_index"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/transparent"
            android:orientation="vertical" >
            <!-- 视图滑动 -->
            <android.support.v4.view.ViewPager   
                android:id="@+id/viewPager_index"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
            <!--引导点-->
            <com.example.android09_gfbank_guidepages.PageControlView
                 android:id="@+id/pageControlView_index"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_centerHorizontal="true"
                android:layout_marginBottom="30dp"/>
            <!-- android:layout_alignParentBottom="true" 该组件与父布局底端对齐
                android:layout_centerHorizontal="true" 水平居中
                android:layout_marginBottom="30dp" 该组件下面的的空白距离-->
        </RelativeLayout>
    </RelativeLayout>
    1. Item_image_layout.xml里的代码:
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <!-- FrameLayout帧布局:先定义的位于底层,后先定义的位于上层 -->
        <FrameLayout
            android:id="@+id/start_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="visible" >
            <!-- android:visibility="visible" 控制控件的显示和隐藏 -->
            <ImageView
                android:id="@+id/image"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:contentDescription="@null" />
            <!--不加“android:contentDescription="@null" 报黄色感叹号
            这个属性必须在用户的Accessible 中的相应属性开启后才能使用。点击Accessible控件,
        android系统会自动使用人声朗读控件上android:contentDescription属性说指向的内容。
      这个属性的主要功能就是为视力有障碍的人增加对控件的解释。-->
            <TextView
                android:id="@+id/start_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal|bottom"
                android:layout_marginBottom="105dp"
                android:contentDescription="@null"
                android:text="开启财富人生"
                android:textSize="30sp"
                android:visibility="gone" />
        </FrameLayout>
    </FrameLayout>
    1. 控制引导点PageControlView.java:
    /**
     * 控制引导点*/
    public class PageControlView extends LinearLayout {
    //上下文
    private Context context;
    //设置引导点的个数
    public int count;
    //定义引导点变换的颜色(实际上是图片)
    public int[] image={R.drawable.index_page_control_u,R.drawable.index_page_control_s};;
    //定义构造器
    public PageControlView(Context context) {
    super(context);
    this.context=context;
    }


    public PageControlView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context=context;
    }
    //控制页面滑动时,引导点颜色的变换;该方法的形参currentPage 其实指向是 ViewPager的索引 position
    public void generalPageControl(int currentPage)
    {
    //清空所有组件
    this.removeAllViews();
    for (int i = 0; i < count; i++) {
    //创建ImageView对象
    ImageView imageView=new ImageView(context);
    //当传入ViewPager的position与i 相等,则让 指示点 引用一张图片(或该引导点变色)
    if(i==currentPage)
    {
    imageView.setImageResource(image[1]);
    }else
    {
    imageView.setImageResource(image[0]);
    }
    //LayoutParams相当于一个Layout的信息包,它封装了Layout的位置、高、宽等信息。假设在屏幕上一块区域是由一个Layout占领的,
    //如果将一个View添加到一个Layout中,最好告诉Layout用户期望的布局方式,也就是将一个认可的layoutParams传递进去。
    LayoutParams lp=new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
    //设置组件四周的空白,左    上   右   下
    lp.setMargins(0, 0, 10, 0);
    //给组件添加布局
    imageView.setLayoutParams(lp);
    //把view添加到Activity中
    this.addView(imageView);
    }
    }
    }
    1. 自定义CustomPagerAdapter:
    /**
     * 自定义PageAdapter*/
    public class CustomPagerAdapter extends PagerAdapter {
    private int[] images;// 放图片
    private Activity context;// 上下文
    private PageControlView page_control;
    // FrameLayout布局
    FrameLayout imageLayout;
    private TextView start_btn;
    private FrameLayout start_view;
    private ImageView imageView;
    // 构造方法传值
    public CustomPagerAdapter(Activity context, int[] images, PageControlView page_control) {
    this.context = context;
    this.images = images;
    this.page_control = page_control;
    }
    // 返回要左右滑动的view的个数
    public int getCount() {
    return images.length;
    }
    @Override //一般来说,destroyitem在viewpager移除一个item时调用。 viewpage一般都会缓冲3个item,
    //即一开始就会调用3次instantiateItem, 当向右滑动,到第3页时,第1页的item会被调用到destroyitem。
    public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
    }
    // isViewFromObject方法是用来判断pager的一个view是否和instantiateItem方法返回的object有关联
    // 可以供外面的人调用,用来判断你传入的view和那个object是等价的
    public boolean isViewFromObject(View arg0, Object arg1) {
    return arg0.equals(arg1);
    }
    // 为位置为position的item创建view;instantiateItem是初始化item用的
    public Object instantiateItem(View view, int position) {
    imageLayout = (FrameLayout)context.getLayoutInflater().inflate(R.layout.item_image_layout, null);
    imageView = (ImageView) imageLayout.findViewById(R.id.image);
    start_btn = (TextView) imageLayout.findViewById(R.id.start_btn);
    // 监听器
    start_btn.setOnClickListener(listener);
    // 当切换到 最后一个item 的时候,让start_btn 展现
    if(position==images.length-1)
    {
    start_btn.setVisibility(View.VISIBLE);
    }
    //设置每一个item的图片
    imageView.setImageResource(images[position]);
    // 把view添加到ViewPager中
    ((ViewPager) view).addView(imageLayout, 0);
    return imageLayout;
    }
    //监听事件
    OnClickListener listener = new OnClickListener() {
    public void onClick(View v) {
    penDoor();
    }
    };
    protected void penDoor() {
    Toast.makeText(context, "开门,展现里面的MainActivity", Toast.LENGTH_SHORT).show();
    }
    }
    1. MainActivity里的代码:
    /**
     * 引导页的制作 */
    public class MainActivity extends Activity {
    private TextView tv_main;
    //声明ViewPager对象
    private ViewPager viewPager;
    //声明指导页面的自定义PageControlView,PageControlView是引导页下面的引导点
    private PageControlView page_control;
    //声明适配器的对象
    private CustomPagerAdapter adapter;
    //定义引导页的 几张图片
    private int[] images={R.drawable.index_01,R.drawable.index_02,R.drawable.index_03,R.drawable.index_04};
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    tv_main=(TextView)findViewById(R.id.tv_main);
    //这个app是否第一次打开,若第一个打开则应当显示引导页。否则不显示引导页;方法getIndexFirst() 得到是否应该显示引导页。
    if (getIndexFirst()) {
    //初始化主界面的数据
    initContent();
    /*得到导引页里面的组件的对象,并且设置一些引导页的业务逻辑*/
    //获得控件对象
    viewPager=(ViewPager)findViewById(R.id.viewPager_index);
    page_control=(PageControlView)findViewById(R.id.pageControlView_index);
    //设置ViewPager当前的展示页若不设置,默认是position=0 的展示页)
    viewPager.setCurrentItem(0);
    //重新对page_control.iamge赋值
    page_control.image = new int[]{R.drawable.gray_dot,R.drawable.black_dot};
    //设置引导点的个数
    page_control.count=images.length;
    //初始化第一个点为黑色
    page_control.generalPageControl(0);
    //创建自定义适配器的对象,并传值
    adapter=new CustomPagerAdapter(this,images,page_control);
    //设置配置器
    viewPager.setAdapter(adapter);
    //调用ViewPager的item切换的监听方法,并且通过这个方法指示引导页下面的点同步改动。
    viewPager.setOnPageChangeListener(listener);
    }else
    {
    //初始化主界面的数据
    initContent();
    }
    }
    //监听事件
    OnPageChangeListener listener=new OnPageChangeListener(){
    //此方法是在状态改变的时候调用,其中arg0这个参数有三种状态(0,1,2)。arg0 ==1的时候表示正在滑动,arg0==2的时候表示滑动完毕了,
    //arg0==0的时候表示什么都没做。当页面开始滑动的时候,三种状态的变化顺序为(1,2,0)
    public void onPageScrollStateChanged(int arg0) {
    // TODO Auto-generated method stub
    }
    //当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。其中三个参数的含义分别为:arg0 :当前页面,及你点击滑动的页面,
    //arg1:当前页面偏移的百分比,arg2:当前页面偏移的像素位置   
    public void onPageScrolled(int arg0, float arg1, int arg2) {
    // TODO Auto-generated method stub
    }
    //指的是当前选择的是哪个页面
    public void onPageSelected(int position) {
    //就是通过这句代码,才能让引导页的点 和ViewPager切换
    page_control.generalPageControl(position);
    }
    };
    //模拟初始化主界面的数据
    private void initContent() {
    tv_main.setText(R.string.app_name);
    }
    //模拟是否是第一次登陆。若是第一次登陆,返回true;否则啊 false 不展示引导页
    private boolean getIndexFirst() {
    return true;

    }}


    ViewPager:功能就是可以使视图左右滑动
    package com.example.android09_viewpager;
    /**
     * ViewPager的功能就是可以使视图滑动
     */
    public class MainActivity extends Activity {
    // 声明3个view,将对应对应好的3个xml布局
    private View view01, view02, view03;
    // 声明一个集合对象来装着上view
    private List<View> listView;
    // 声明ViewPager对象
    private ViewPager viewPager;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //获取控件
    viewPager=(ViewPager)findViewById(R.id.viewPager);
    // 将xml布局转换为view对象
    // LayoutInflater它的作用类似于findViewById()。不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化
    LayoutInflater inflater = getLayoutInflater();
    // inflate()的作用就是将一个用xml定义的布局文件查找出来,注意与findViewById()的区别,inflate是加载一个布局文件,而findViewById则是从布局文件中查找一个控件
    view01 = inflater.inflate(R.layout.pager01_layout, null);
    view02 = inflater.inflate(R.layout.pager02_layout, null);
    view03 = inflater.inflate(R.layout.pager03_layout, null);
    // 将左右滑动的View添加到集合中,这样数据源就准备好了
    listView = new ArrayList<View>();
    listView.add(view01);
    listView.add(view02);
    listView.add(view03);
    // 设置适配器
    viewPager.setAdapter(pagerAdapter);
    }
    /*因为pagerAdapter是默认预加载前后一张的,所以当加载第一页时,调用了两次instantiateItem方法;第一次是加载本来的第一页,第二次是预加载第二页。当滑动到第二页时,只调用了一次instantiateItem方法;是因为本页已经在之前预加载过了,没有再调用instantiateItem方法,而是直接从ViewGroup中直接取出第二页用于显示;然后进行预加载第三页,所以这里会调用一次instantiateItem方法。接着滑动到第三页,由于第三节页也已经预加载过了,所以只是从ViewGroup取出第三页显示而不调用instantiateItem;但是由于预加载默认是前后一张,所以这时会从ViewGroup中取出第一页销毁;直到从第三页滑到第二页时才会再预加载第一页。*/
    // 对于ViewPager有一个专用的适配器PagerAdapter
    PagerAdapter pagerAdapter = new PagerAdapter() {
    // 返回要左右滑动的view的个数
    public int getCount() {
    return listView.size();
    }
    // 从当前container中删除指定位置的position的view
    //destroyitem在viewpager移除一个item时调用。 viewpage一般都会缓冲3个item,即一开始就会调用3次instantiateItem, 当向右滑动,到第3页时,第1页的item会被调用到destroyitem
    public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView(listView.get(position));
    }
    // 为位置为position的item创建view;instantiateItem是初始化item用的
    public Object instantiateItem(ViewGroup container, int position) {
    container.addView(listView.get(position));
    return listView.get(position);
    }
    //isViewFromObject方法是用来判断pager的一个view是否和instantiateItem方法返回的object有关联
    //可以供外面的人调用,用来判断你传入的view和那个object是等价的
    public boolean isViewFromObject(View arg0, Object arg1) {
    return arg0==arg1;
    }};}


    GestureDetector手势:可用于图片的滑动播放
    当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等等。
    一般情况下,我们知道View类有个View.OnTouchListener内部接口,通过重写他的onTouch(View v, MotionEvent event)方法,我们可以处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)。
    Android sdk给我们提供了GestureDetector(Gesture:手势Detector:识别)类,通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent(event)方法完成了不同手势的识别。虽然他能识别手势,但是不同的手势要怎么处理,应该是提供给程序员实现的。
    public class MainActivity extends Activity implements OnGestureListener{
    //声明手势检测器实例
    GestureDetector detector;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //创建手势检测器对象。通过GestureDetector构造器来创建对象
    //GestureDetector(Context context, OnGestureListener listener)
    //第一个参数 是上下文,第二个参数是接口 OnGestureListener对象
    detector=new GestureDetector(this, this);
    }
    //用户的手指触动Activity的时候,会触发 key、touch等的事件处理方法,现在咱们来重写Activity的OnTouchEvent方法
    @Override//重写Activity类里的onTouchEvent事件方法
    //如果MainActivity 实现OnTouchListener接口,这里重写OnTouchListener里的onTouch方法
    //public boolean onTouch(View v, MotionEvent event)
    public boolean onTouchEvent(MotionEvent event) {
    //将这个Activity上面的触碰事件交给GestureDetector手势处理类 来处理,或者说手势检测类截获了touch事件
    //这一步,必须写。否则,你的动作无法触发对应的 手势
    return detector.onTouchEvent(event);
    }
    //当触摸事件按下时触发这个方法
    @Override
    public boolean onDown(MotionEvent e) {
    Log.e("Down", "onDown");
    return false;
    }
    //当用户在屏幕上按下,而且 还未移动和松开时候 触发这个方法
    @Override
    public void onShowPress(MotionEvent e) {
    Log.e("ShowPress", "onShowPress");
    }
    //当用户在触摸屏上 轻击 时候 会触发这个方法
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
    Log.e("SingleTapUp", "onSingleTapUp");
    return false;
    }
    //当用户在屏幕上滚动时触发的方法
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    Log.e("Scroll", "onScroll");
    return false;
    }


    //用户在屏幕上长按时触动这个方法
    @Override
    public void onLongPress(MotionEvent e) {
    Log.e("LongPress", "onLongPress");
    }

    //当用户在触摸屏上“拖过...  滑动...” 时 触发这个方法。velocityX, velocityY  代表 滑动 动作在横向或 纵向上的速度
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    Log.e("Fling", " onFling");
    return false;
    }
    }
    ViewFlipper图片的自动循环播放
    1. 自动播放:
    activity_main.xml:代码
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="${relativePackage}.${activityClass}" >
    <!--页面轮换,实现左右滑动的动画效果  -->
        <ViewFlipper
            android:id="@+id/flipper"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_marginTop="10dp" >
        </ViewFlipper>
    </RelativeLayout>
    MainActivity代码:
    /**
     * ViewFlipper图片的自动循环播放,不在XML里添加图片,在java里动态添加图片
     * @author Administrator */
    public class MainActivity extends Activity {
    ViewFlipper flipper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    flipper=(ViewFlipper)findViewById(R.id.flipper);
    //自动添加图片
    flipper.addView(getImageView(R.drawable.img_1));
    flipper.addView(getImageView(R.drawable.img_2));
    flipper.addView(getImageView(R.drawable.img_3));
    flipper.addView(getImageView(R.drawable.img_4));
    //设置自动循环
    flipper.setFlipInterval(2000);//view切换的时间间隔
    //开始进行view的切换
    flipper.startFlipping();
    }
    //需要将项目中的img_1.jpg等图片通过ViewFlippter的addView动态添加,而addView的形参是view,
    //所以呢  需要写一个方法 将图片id 转化为 View
    private ImageView getImageView(int id)
    {
    ImageView imageView=new ImageView(this);
    imageView.setImageResource(id);
    return imageView;
    }
    }


    1. 滑动播放
    activity_main.xml:代码和上面的一样
    MainActivity代码:
    /**
     * ViewFlipper图片的自动循环播放,左右滑动展示图片
     * @author Administrator
     */
    public class MainActivity extends Activity implements OnTouchListener,OnGestureListener{
    //声明图片的自动循环播放
    ViewFlipper flipper;
    //声明手势
    GestureDetector detector;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //第一个参数 是上下文,第二个参数是接口 OnGestureListener对象
    detector=new GestureDetector(this,this);

    flipper=(ViewFlipper)findViewById(R.id.flipper);
    //自动添加图片
    flipper.addView(getImageView(R.drawable.img_1));
    flipper.addView(getImageView(R.drawable.img_2));
    flipper.addView(getImageView(R.drawable.img_3));
    flipper.addView(getImageView(R.drawable.img_4));
    //设置监听器
    flipper.setOnTouchListener(this);
    //允许长按住ViewFlipper,这样才能识别拖动等收拾
    flipper.setLongClickable(true);
    }

    //需要将项目中的img_1.jpg等图片通过ViewFlippter的addView动态添加,而addView的形参是view,
    //所以呢  需要写一个方法 将图片id 转化为 View
    private ImageView getImageView(int id)
    {
    ImageView imageView=new ImageView(this);
    imageView.setImageResource(id);
    return imageView;
    }


    用户的手指触动Activity的时候,会触发 key、touch等的事件处理方法,现在咱们来重写Activity的OnTouchEvent方法
    @Override // 重写OnTouchListener里的onTouch方法
    public boolean onTouch(View v, MotionEvent event) {
    // 将这个Activity上面的触碰事件交给GestureDetector手势处理类 来处理,或者说手势检测类截获了touch事件
    // 这一步,必须写。否则,你的动作无法触发对应的 手势
    return detector.onTouchEvent(event);
    }
    //当触摸事件按下时触发这个方法
    @Override
    public boolean onDown(MotionEvent e) {
    return false;
    }
    //当用户在屏幕上按下,而且 还未移动和松开时候 触发这个方法
    @Override
    public void onShowPress(MotionEvent e) {
    }
    //当用户在触摸屏上 轻击 时候 会触发这个方法
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
    return false;
    }
    //当用户在屏幕上滚动时触发的方法
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    return false;
    }
    //用户在屏幕上长按时触动这个方法
    @Override
    public void onLongPress(MotionEvent e) {
    }
    //当用户在触摸屏上“拖过...  滑动...” 时 触发这个方法。velocityX, velocityY  代表 滑动 动作在横向或 纵向上的速度
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    //设置拖动距离大于100时,图片改变
    //手指向左滑动,终点(e2)在起点(e1)的左侧,e2.getX() - e1.getX 小于 0
    if (e1.getX()-e2.getX()>100 && Math.abs(velocityX)>100) {
    //左滑显示下一张图片
    flipper.showNext();
    }else if(e2.getX()-e1.getX()>100 && Math.abs(velocityX)>100)
    {//手指向右滑动,终点(e2)在起点(e1)的右侧,e2.getX() - e1.getX 大于 0
    //右滑显示上一张图片
    flipper.showPrevious();
    }
    return false;
    }
    }


    LayoutParams的用法:LayoutParams继承于Android.View.ViewGroup.LayoutParams.
      LayoutParams相当于一个Layout的信息包,它封装了Layout的位置、高、宽等信息。假设在屏幕上一块区域是由一个Layout占领的,如果将一个View添加到一个Layout中,最好告诉Layout用户期望的布局方式,也就是将一个认可的layoutParams传递进去。
           可以这样去形容LayoutParams,在象棋的棋盘上,每个棋子都占据一个位置,也就是每个棋子都有一个位置的信息,如这个棋子在4行4列,这里的“4行4列”就是棋子的LayoutParams。


           但LayoutParams类也只是简单的描述了宽高,宽和高都可以设置成三种值:
           1,一个确定的值;
           2,FILL_PARENT,即填满(和父容器一样大小);
           3,WRAP_CONTENT,即包裹住组件就好。
    1. FrameLayout下动态设置子控件居中,动态用JAVA代码要这样实现:
    LayoutParams lp=new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
    lp.setMargins(0, 0, 10, 0);//设置组件四周的空白,左    上   右   下
    imageView.setLayoutParams(lp);//给组件添加布局
    1. RelativeLayout下动态设置子控件居中:
    RelativeLayout.LayoutParams lp=new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); 
    lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE); 
    lp.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE); 
    btn1.setLayoutParams(lp);


    IO流数据存储
    1. IO流:相对内存来说的,数据存入内存中是输入流,从内存中保存在文本文件等中是输出流。
    2. 写入和读取
    public class MainActivity extends Activity {
    //定义一个文件名,这个示例中的数据 存储和读取都是从这个文件中来操作
    final String FILE_NAME="cm.txt";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    /*//使用StringBuilder+append来拼接一个字符串
    String sb=new StringBuilder("a").append("b").append("b").toString();
    Toast.makeText(this, sb, Toast.LENGTH_SHORT).show();*/
    //得到两个按钮组件对象
    Button read=(Button)findViewById(R.id.read);
    Button write=(Button)findViewById(R.id.write);
    //得到两个文本框的对象
    final EditText edit01=(EditText)findViewById(R.id.edit01);
    final EditText edit02=(EditText)findViewById(R.id.edit02);
    //为按钮绑定监听事件
    write.setOnClickListener(new OnClickListener(){
    //点击
    public void onClick(View v) {
    write(edit01.getText().toString());
    edit01.setText("");
    }
    });
    read.setOnClickListener(new OnClickListener(){
    //点击
    public void onClick(View v) {
    edit02.setText(read());
    }
    });
    }
    private void write(String context)
    {
    try {
    //以追加的形式打开文件输出流
    //这个文件的路径  /data/data/包名/files/cm.txt
    //Context.MODE_APPEND以追加方式打开这个文件,应用程序可以向这个文件中追加内容
    FileOutputStream fos=openFileOutput(FILE_NAME,Context.MODE_APPEND);
    //将字节流FileOutputStream包装成处理流PrintStream
    PrintStream ps=new PrintStream(fos);

    ps.println(context);
    ps.close();

    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
    }
    private String read()
    {
    try {
    //打开文件输入流
    //文件的路径  /data/data/包名/files/cm.txt
    FileInputStream fis=openFileInput(FILE_NAME);
    //定义一个缓冲区
    byte[] buff=new byte[1024];
    int hasRead=0;
    StringBuilder sb=new StringBuilder("");
    //读取文件内容
    while(((hasRead=fis.read(buff))>0))
    {
    //不断的循环遍历读取这个输入流
    //将字符数据转成字符串new String(buff,0,hasRead)
    //使用StringBuilder + append 来凭借字符串
    sb.append(new String(buff,0,hasRead));
    }
    fis.close();
    return sb.toString();

    } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    return null;

    }
    }
    1. 写入数据之内容的覆盖和追加
    public class MainActivity extends Activity {
    private EditText et_userName;
    private EditText et_userPwd;
    private CheckBox cb_remember_pwd;
    private RadioGroup rg_mode;

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    et_userName = (EditText)findViewById(R.id.et_name);
    et_userPwd = (EditText)findViewById(R.id.et_password);
    //密码是否勾选框
    cb_remember_pwd = (CheckBox)findViewById(R.id.cb_remember_pwd);
    //单选框组
    rg_mode = (RadioGroup)findViewById(R.id.rg_mode);
    }

    //按钮的点击事件
    public void login(View v)
    {
    String name=et_userName.getText().toString();
    String pwd=et_userPwd.getText().toString();

    //若用户名或密码字符串,其中有一个为null 或者长度为零,则返回为true
    if(TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd))
    {
    Toast.makeText(this, "用户名和密码不能为空", Toast.LENGTH_LONG).show();
    }else
    {
    if ("cm".equals(name) && "123".equals(pwd)) {
    Toast.makeText(this, "登陆成功", Toast.LENGTH_LONG).show();
    //判断 记住用户名密码 是否勾选
    if (cb_remember_pwd.isChecked()) {
    boolean result=false;
    //获取单选框组下边的单选框的id
    int id=this.rg_mode.getCheckedRadioButtonId();
    switch (id) {
    case R.id.rb_private://私有模式,新建一个文件覆盖原文件,内容覆盖原文件内容
    result=FilePermissionService.saveInfo(this, name, pwd, 0);
    break;
    case R.id.rb_append://对原文件续写,内容追加在原内容后
    result=FilePermissionService.saveInfo(this, name, pwd, 1);
    break;
    }
    }
    }else
    {
    Toast.makeText(this, "用户名或密码不正确", Toast.LENGTH_LONG).show();
    }
    }
    }
    }
    FilePermissionService.java里写覆盖或追加
    /**
     * 保存用户名和密码到一个文件中
     * @author Administrator
     */
    public class FilePermissionService {
    // 保存用户名和密码到一个文件中
    public static boolean saveInfo(Context context, String name, String password, int mode) {
    // 文件输出流
    FileOutputStream fos = null;
    try {
    // 定义一个switch分支语句,根据传入的参数mode来判定执行哪个 写文件mode
    switch (mode) {
    case 0:// 当参数mode等0,代表文件login.txt的输入流,且模式为私有模式
    // Context.MODE_PRIVATE 若路径下没有同名文件,则新建;若有同名文件,则覆盖之前的文件。
    fos = context.openFileOutput("login.txt", context.MODE_PRIVATE);
    break;
    case 1:// 当参数mode等1,代表文件login.txt的输入流,且模式 追加模式
    // Context.MODE_APPEND 以追加方式打开这个文件,应用程序可以向这个文件中 追加内容。
    fos = context.openFileOutput("login.txt", context.MODE_APPEND);
    break;
    }
    // 使用输出流写数据
    fos.write((name + "=" + password).getBytes());
    return true;
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    return false;
    } catch (IOException e) {
    e.printStackTrace();
    return false;
    } finally {
    try {
    if (fos != null) {
    fos.close();
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }


    SharedPreferences:进行数据存储
    1. LoginServer 
    /**
     * 使用SharedPreferences来定义一个存储用户名和密码的功能模块
     * @author Administrator
     */
    public class LoginServer {
    //使用SharedPreferences来定义一个存储用户名和密码的功能模块
    public static void saveInfo(Context context,String name,String pwd)
    {
    //通过上下文Context对象的getSharedPreferences方法来得到SharedPreferences对象
    SharedPreferences sp=context.getSharedPreferences("config", Context.MODE_PRIVATE);
    //调用SharedPreferences的edit()方法得到Editor对象
    Editor editor=sp.edit();
    //使用对象editor来存储数据
    editor.putString("username", name);
    editor.putString("password", pwd);
    //最后一步,调用commit方法,数据保存成功
    editor.commit();
    }
    public static void saveInfo02(Context context)
    {
    SharedPreferences sp=context.getSharedPreferences("config", Context.MODE_PRIVATE);
    Editor editor=sp.edit();
    editor.putString("a","123");
    editor.putString("b","123");
    editor.commit();
    }
    //删除所有数据
    public static void delAllData(Context context)
    {
    SharedPreferences sp=context.getSharedPreferences("config", Context.MODE_PRIVATE);
    Editor editor=sp.edit();
    //删除所有的editor存储的数据
    editor.clear();
    editor.commit();
    }
    //删除Key键值对应的数据
    public static void delKeyData(Context context)
    {
    SharedPreferences sp=context.getSharedPreferences("config", Context.MODE_PRIVATE);
    Editor editor=sp.edit();
    //删除Key键值对应的editor里存储的数据
    editor.remove("a");
    editor.commit();//同步提交
    //editor.apply();//异步提交,2.3版本后增加的
    }
    }
    1. 存储、读取和删除
    /**
     * SharedPreferences进行数据存储 */
    public class MainActivity extends Activity {
    private EditText et_username;
    private EditText et_password;
    private CheckBox cb_rememberPwd;


    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    et_username = (EditText) findViewById(R.id.et_username);
    et_password = (EditText) findViewById(R.id.et_userpwd);
    cb_rememberPwd = (CheckBox) findViewById(R.id.cb_remember_pwd);
    SharedPreferences sp = this.getSharedPreferences("config",MODE_PRIVATE);
    // 通过对象sp来获取之前保存的数据
    et_username.setText(sp.getString("username", "默认值"));
    et_password.setText(sp.getString("password", "默认值"));
    }
    // 按钮点击事件
    public void login(View v) {
    String name = et_username.getText().toString();
    String pwd = et_password.getText().toString();


    if (TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)) {
    Toast.makeText(this, "用户名或密码不能为空", Toast.LENGTH_SHORT).show();
    } else {
    if ("cm".equals(name) && "123".equals(pwd)) {
    Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
    if (cb_rememberPwd.isChecked()) {
    LoginServer.saveInfo(this, name, pwd);
    Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show();
    }
    } else {
    Toast.makeText(this, "用户名或密码不正确", Toast.LENGTH_SHORT).show();
    }
    }
    }
    // 删除所有数据
    public void delAll(View v) {
    LoginServer.delAllData(this);
    }
    // 添加数据
    public void addData(View v) {
    LoginServer.saveInfo02(this);
    }
    // 删除Key键值对应的数据
    public void delKey(View v) {
    LoginServer.delKeyData(this);
    }
    }


    统计进入该模块或启动app的次数(类似友盟插件)
    /**
     * 统计进入该模块或启动app的次数(类似友盟插件) */
    public class MainActivity extends Activity {
    //声明SharedPreferences对象
    SharedPreferences shared;
    //程序每次启动,都会调用这个方法onCreate ,在这个方法中 先得到之前保存的count值,这个count值 表示此应用已经打开的次数。
    //然后,在对这个count值 自加1,表示当前打开的次数
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //获取SharedPreferences对象
    shared=getSharedPreferences("count",MODE_PRIVATE);
    //读取shared里面的count_key对应的value值,若“count”不存在返回0
    int count=shared.getInt("count_key", 0);
    Toast.makeText(this,"程序已经被使用了 : " + (count+1) + "次",Toast.LENGTH_SHORT).show();;
    //获取拥有存储数据的Editor对象
    Editor editor=shared.edit();
    //存储数据
    editor.putInt("count_key", ++count);
    //提交数据
    editor.commit();
    }


    文件存储—得到文件或文件夹的大小(Android12_Shared04)
    1. 定义得到大小的方法
    /*
     * 定义路径文件大小的工具类
     */
    public class FileSizeUtil {
    // 定义四个全局静态常量
    public static final int SIZETYPE_B = 1;
    public static final int SIZETYPE_KB = 2;
    public static final int SIZETYPE_MB = 3;
    public static final int SIZETYPE_GB = 4;
    // 获取指定文件的大小
    private static long getFilesSize(File file) {
    // 定义一个变量表示文件的大小
    long size = 0;
    // 声明一个输入流对象,通过这个流获取文件大小
    FileInputStream fis = null;


    try {
    /*
    * if (file.exists())// 若路径是存在的 { // 得到这个抽象路径的文件输入流对象fis fis = new
    * FileInputStream(file); // 调用方法available得到文件的大小,数据类型为int size =
    * fis.available();//当文件容量大于1.999G的时候,此方法无效 }
    */
    if (file.exists() && file.isFile()) {// 若这个抽象路径是存在的 且 是文件
    size = file.length();
    } else {
    file.createNewFile();
    Log.e("获取文件大小", "文件不存在");
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    try {
    if (fis != null)
    fis.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    return size;
    }
    // 根据文件大小的方法 来定义 文件夹的大小
    private static long getFilesSizes(File file) {
    // 定义一个变量size 表示指定路径的大小。这里的这个变量 size 还起到了临时存储的作用
    long size = 0;
    // 当这个抽象路径File表示一个文件夹的时候,首先调用方法listFiles得到一个File类型的数组,
    // 当这个抽象路径File表示一个文件,调用listFile()得到是null
    // 那么 在调用方法listFile之前,应该对这个抽象路径File做一个是文件 或是 文件夹的判断。
    File[] fList = file.listFiles();
    // for循环遍历这个File类型的数组
    for (int i = 0; i < fList.length; i++) {
    if (fList[i].isDirectory()) {// 若是文件夹
    // 使用递归方法再次遍历文件夹
    size = size + getFilesSizes(fList[i]);
    } else {
    // 若是文件,则得到文件的大小并文件大小累加
    size = size + getFilesSize(fList[i]);
    }
    }
    return size;
    }
    // 暴露给外界使用
    // 定义一个方法:得到这个路径下的文件夹或文件的大小后,转化为期望的单位B,KB,MB,GB
    public static double getSize(String filePath, int sizeType) {
    // 强目录字符串包装成抽象路径FIle
    File file = new File(filePath);
    // 定义一个表示目录大小的变量
    long blockSize = 0;
    if (file.isDirectory())// 若是文件夹
    {
    blockSize = getFilesSizes(file);
    } else// 若是文件
    {
    blockSize = getFilesSize(file);
    }
    // 格式化文件大小数据单位转换文件大小成指定的数据类型,返回值为double类型
    return formatFileSize(blockSize, sizeType);
    }
    // 格式化文件大小数据单位转换文件大小成指定的数据类型,返回值为double类型
    private static double formatFileSize(long blockSize, int sizeType) {
    // DecimalFormat是NumberFormat的一个具体的实现子类,用于格式化 十进制
    // 数字。使用DecimalFormat确保数据精确到 小数点 后两位。
    DecimalFormat df = new DecimalFormat("#.00");
    double fileSizeLong = 0;
    switch (sizeType) {
    case SIZETYPE_B:// 返回单位 为 B
    fileSizeLong = Double.valueOf(df.format((double) blockSize));
    // df.format((double)blockSize)--- 数据格式化
    // Double.valueOf()--- 将String类型的强制类型转化为double类型
    break;
    case SIZETYPE_KB:// 返回单位 为KB
    fileSizeLong = Double.parseDouble(df.format((double) blockSize / 1024));
    break;
    case SIZETYPE_MB:
    fileSizeLong = Double.valueOf(df.format((double) blockSize / (1024 * 1024)));
    break;
    case SIZETYPE_GB:
    fileSizeLong = Double.parseDouble(df.format((double) blockSize / (1024 * 1024 * 1024)));
    break;
    default:
    break;
    }
    return fileSizeLong;
    }


    // 方法重构
    private static String formatFileSize(long blockSize) {
    // DecimalFormat是NumberFormat的一个具体的实现子类,用于格式化 十进制
    // 数字。使用DecimalFormat确保数据精确到 小数点 后两位。
    DecimalFormat df = new DecimalFormat("#.00");
    String fileSizeString  = "";
    String wrongSize="0B";
    if (blockSize==0) {
    return wrongSize;
    }
    if(blockSize < 1024){
    fileSizeString = df.format((double)blockSize) + "B";
    }else if(blockSize < 1024*1024){
    fileSizeString = df.format((double)blockSize/1024) + "KB";
    }else if(blockSize < 1024*1024*1024){
    fileSizeString = df.format((double)blockSize/(1024*1024)) + "MB";
    }else{
    fileSizeString = df.format((double)blockSize/(1024*1024*1024)) + "GB";
    }
    return fileSizeString;
    }


    // 调用这个方法 自定计算指定文件或文件夹的大小,返回的数据 自动匹配单位 B KB MB GB
    public static String getAutoFileOrFilesSize(String filePath) {
    // 强目录字符串包装成抽象路径FIle
    File file = new File(filePath);
    // 定义一个表示目录大小的变量
    long blockSize = 0;
    if (file.isDirectory())// 若是文件夹
    {
    blockSize = getFilesSizes(file);
    } else// 若是文件
    {
    blockSize = getFilesSize(file);
    }
    // 格式化文件大小数据单位,根据数字大小 单位分别为 B KB MB GB,返回值类型为String
    return formatFileSize(blockSize);
    }
    }


    打电话和发短信(Android13_PhoneAndShortMessage)
    1.自定义dialog控件


    用Bitmap保存图片到内部存储和从内部存储获取图片(Android14_BitmapPic)
    1. 保存图片到内部存储和从内部存储获取图片(GetDirUtil)
    public class GetDirUtil {
    // 得到/data/data/包名/app_XXX 下的一张图片的bitmap
    public static Bitmap loadImageFromDir(Context c, String filename) {
    try {
    // 将 目录+文件名 包装成一个抽象路径
    File file = new File(getDir(c), filename);
    // 根据 抽象路径f 生成一个IO
    InputStream is = new FileInputStream(file);
    // 将一个IO流转化为 Bitmap
    Bitmap bmp = BitmapFactory.decodeStream(is);
    return bmp;
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
    return null;
    }


    private static String getDir(Context c) {
    // 定义存储目录data/data/包名/app_my_dir
    File file = c.getDir("my_dir", Context.MODE_PRIVATE);
    String path = file.getPath();
    return path;
    }


    // /data/data/包名/app_my_dir----c.getDir("my_dir", Context.MODE_PRIVATE)


    /**
    * 保存图片在内部存储中
    */
    public static void saveFile(Context c, Bitmap bmp, String fileName) {
    try {
    // 将 目录+文件名 包装成一个抽象路径
    File myFile = new File(getDir(c), fileName);
    if (!myFile.exists())// myFile.exists()存在这个路径
    {
    // 路径不存在会创建
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myFile));
    //质量压缩方法,把压缩后的数据存放到bos流中
    //第一个参数是图片压缩后的格式;第二个参数是压缩率(100表示不压缩),图片形状大小不变,清晰度和所占空间改变;第三个参数是流
    bmp.compress(Bitmap.CompressFormat.JPEG, 80, bos);

    bos.flush();
    bos.close();
    } else {
    Log.e("dir--", fileName + "已经存在了,我不再重新创建");
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    1. 通过Bitmap得到项目资源下的图片并保存在内部存储中
    public class MainActivity extends Activity {
    //内部存储下文件名
    final String fileName = "user_01.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //把图片保存在内部存储中
    copyPicToIns();
    }
    //把图片保存在内部存储中
    private void copyPicToIns() {
    // 调用上下文的getResoueces方法得到 系统资源对象Resource
    //.png、.9.png、.jpg文件,它们被编译进以下的Drawable资源子类型中:要获得这种类型的一个资源,可以 使用Resource.getDrawable(id)
    //为了获取资源类型,使用mContext.getResources().getDrawable(R.drawable.imageId)
    Resources res=getResources();
    //通过BitmapFactory类 将图片资源R.drawable.user 转化为bitmp
    Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.user);
    // 保存图片至 内部存储路径中
    GetDirUtil.saveFile(this, bmp, fileName);
    }
    //点击按钮显示图片
    public void getPic(View v)
    {
    //获取/data/data/包名/app_XXX 下的一张图片
    Bitmap bmp=GetDirUtil.loadImageFromDir(this, fileName);
    //得到控件
    ImageView image = (ImageView)findViewById(R.id.image);
    //图片绑定在控件上显示
    image.setImageBitmap(bmp);
    }
    }


    Sdcard外部存储--其实也是文件存储
    1. LoginService向sdcard中读数据写数据的工具类
    /**
     * 向sdcard中 读数据 写数据 的工具类 */
    public class LoginService {
    /**
    * 向sdcard中写数据
    */
    public static boolean saveInfo(Context context, String name, String pwd) {
    try {
    // 得到SDCARD的状态 是否加载 是否可用 是否卸载.....
    // Environment是一个提供访问环境变量的接口类,常使用Environment类去获取外部存储目录,在访问外部存储之前一定要先判断外部存储是否已经是可使用(已挂载&可使用)状态,
    String state = Environment.getExternalStorageState();
    // Environment.MEDIA_MOUNTED---返回值 "mounted"。若SDCARD的状态值等于 "mounted"
    // 则说明SDCARD已经准备好了,可以用了
    if (Environment.MEDIA_MOUNTED.equals(state)) {
    // Environment.getExternalStorageDirectory()得到的是抽象路径
    // 存储地址:抽象路径+文件名
    File file = new File(Environment.getExternalStorageDirectory(), "info.txt");
    // 通过抽象路径 得到输出流
    FileOutputStream fos = new FileOutputStream(file);
    // 输出流 写 数据
    fos.write((name + "=" + pwd).getBytes());
    fos.flush();
    fos.close();
    return true;
    } else {
    Toast.makeText(context, "sdcard不可用", Toast.LENGTH_SHORT).show();
    return false;
    }
    } catch (Exception e) {
    e.printStackTrace();
    Toast.makeText(context, "SDCARD异常", Toast.LENGTH_SHORT).show();
    return false;
    }
    }
    /**
    * 从sdcard中读数据
    */
    public static HashMap<String,String> getInfo(Context context)
    {
    try {
    //得到文件info.txt的抽象路径
    File file=new File(Environment.getExternalStorageDirectory()+"info.txt");
    //创建文件输入流
    FileInputStream fis= new FileInputStream(file);

    //字符流包装 文件输入流,再  缓冲流 包装字符流
    BufferedReader br=new BufferedReader(new InputStreamReader(fis));
    //读一行,根据“=” 划分String类型的数组
    String[] result=br.readLine().split("=");
    HashMap<String,String> hm=new HashMap<String,String>();
    hm.put("name", result[0]);
    hm.put("pwd", result[1]);
    br.close();
    fis.close();
    return hm;
    } catch (Exception e) {
    e.printStackTrace();
    Toast.makeText(context, "无法读取数据", Toast.LENGTH_SHORT).show();
    }
    return null;
    }
    }
    1. 存储和获得数据
    /**
     * 外部存储:sdcard
     */
    public class MainActivity extends Activity {


    private EditText et_username;
    private EditText et_password;
    private CheckBox cb_remember_psw;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    this.et_username = (EditText) this.findViewById(R.id.et_username);
    this.et_password = (EditText) this.findViewById(R.id.et_password);
    this.cb_remember_psw = (CheckBox) this.findViewById(R.id.cb_remember_psw);
    // 获取已经保存的数据
    HashMap<String, String> info = LoginService.getInfo(getBaseContext());
    if (info != null) {
    this.et_username.setText(info.get("name"));
    this.et_password.setText(info.get("pwd"));
    }
    }


    // 响应按钮的响应事件
    public void login(View v) {
    String name=et_username.getText().toString().trim();
    String pwd=et_password.getText().toString().trim();
    if (TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)) {
    Toast.makeText(this, "用户名和密码都不能为空", Toast.LENGTH_SHORT).show();
    }else
    {
    //模拟 用户登陆 成功
    if ("cm".equals(name) && "123".equals(pwd)) {
    Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();

    //checkbox 是否被勾选
    if(cb_remember_psw.isChecked())
    {
    //保存数据
    boolean result=LoginService.saveInfo(this, name, pwd);
    if (result) {
    Toast.makeText(this, "数据保存成功", Toast.LENGTH_SHORT).show();
    }
    }
    }else{
    Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show();
    }
    }

    }
    }


    Handler(Android16_Handler)
    1. 什么是Handler:主线程和子线程之间的信使
    2. Handler用什么用:
    Android 中主线程也叫 UI 线程,那么从名字上我们也知道主线程主要是用来创建、更新 UI 的,而其他耗时操作,比如网络访问,或者文件处理,多媒体处理等都需要在子线程中操作,之所以在子线程中操作是为了保证 UI 的流畅程度,手机显示的刷新频率是 60Hz,也就是一秒钟刷新 60 次,每16.67 毫秒刷新一次,为了不丢帧,那么主线程处理代码最好不要超过 16 毫秒。当子线程处理完数据后,为了防止 UI 处理逻辑的混乱,Android 只允许主线程修改 UI,那么这时候就需要 Handler来充当子线程和主线程之间的桥梁了。
    我们通常将 Handler 声明在 Activity 中,然后重写 Handler 中的 handleMessage 方法,当子线程调用 handler.sendMessage()方法后 handleMessage 方法就会在主线程中执行。
    这里面除了 Handler、Message 外还有隐藏的 Looper 和 MessageQueue 对象。
    在主线程中 Android 默认已经调用了 Looper.preper()方法,调用该方法的目的是在 Looper 中创建 MessageQueue 成员变量并把 Looper 对象绑定到当前线程中。当调用 Handler 的sendMessage(对象)方法的时候就将 Message 对象添加到了 Looper 创建的 MessageQueue队列中,同时给 Message 指定了 target 对象,其实这个 target 对象就是 Handler 对象。主线程默认执行了 Looper.looper ()方法,该方法从 Looper 的成员变量 MessageQueue 中取出 Message,然后调用 Message 的 target 对象的 handleMessage()方法。这样就完成了整个消息机制。
    1. 案例1
    public class MainActivity extends Activity {
    final static int BITMAP_UI = 0;
    static final int EXCEPTION = 1;
    private ImageView iv_beauty;
    private EditText et_path;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    this.iv_beauty = (ImageView) this.findViewById(R.id.iv_beauty);
    this.et_path = (EditText) this.findViewById(R.id.et_path);
    }
    // 主线程创建消息处理器
    Handler handler=new Handler(){
    // 消息处理时 调用,并处理这个消息
    public void handleMessage(Message msg)
    {
    if(msg.what==BITMAP_UI)
    {
    // 获取消息对象,位图bitmap
    Bitmap map=(Bitmap)msg.obj;
    //在UI线程中更新UI
    iv_beauty.setImageBitmap(map);
    }else  //else if(msg.what==EXECPTION)
    {
    Toast.makeText(getApplicationContext(),"图片获取失败", Toast.LENGTH_SHORT).show();
    }
    }
    };
    //按钮
    public void watch(View v)
    {
    final String path=et_path.getText().toString().trim();
    if(TextUtils.isEmpty(path))
    {
    Toast.makeText(this, "按毛啊", Toast.LENGTH_SHORT).show();
    }else {
    new Thread(){
    public void run()
    {
    try {
    URL url=new URL(path);
    //HttpURLConnection网络连接;要开发与Internet连接的程序,最基础的还是使用HttpURLConnection
    HttpURLConnection connection=(HttpURLConnection)url.openConnection();
    //设置请求方式
    connection.setRequestMethod("GET");
    //设置超时时间
    connection.setConnectTimeout(10000);
    //服务器返回 请求 状态值
    int code=connection.getResponseCode();
    if(code==200)
    {
    //获取流
    InputStream is=connection.getInputStream();
    //把流转换为位图
    Bitmap bmp=BitmapFactory.decodeStream(is);
    // 告诉主线程一个消息,帮我更新 UI, 内容:bitmap
    Message msg=new Message();
    // 消息的代号,是一个int类型
    msg.what=BITMAP_UI;
    msg.obj=bmp;
    // 利用handler发送Message
    handler.sendMessage(msg);
    }
    } catch (MalformedURLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }.start();
    }
    }
    }
    1. 案例2—TimerTask计时器
    public class MainActivity extends Activity {
    // 定义 周期性显示的图片的id 数组
    int[] images = new int[] { R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d };
    // 定义变量 当前图片的id值
    private int currentImageId;
    // 显示图片的ImageView
    private ImageView show;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    show = (ImageView) findViewById(R.id.show);
    // 定义一个计时器,让这个计时器周期性的执行指定任务
    // TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务。
    // 第一个参数是 TimerTask 类,在包:import Java.util.TimerTask.使用者要继承该类,并实现 public void run() 方法;
    // 第二个参数"0"的意思是:(0就表示无延迟),当你调用该方法后,该方法必然会调用 TimerTask 类 TimerTask 类 中的
    // run() 方法,
    // 这个参数就是这两者之间的差值,转换成汉语的意思就是说,用户调用 schedule() 方法后,要等待这么长的时间才可以第一次执行
    // run() 方法;
    // 第三个参数意思是:第一次调用之后,从第二次开始每隔多长的时间调用一次 run()方法
    new Timer().schedule(new TimerTask() {
    @Override
    public void run() {
    // 发送空消息(在子线程中)
    myHandler.sendEmptyMessage(0x123);
    }
    }, 1000, 3000);// 调用方法后延迟1秒后调用图片,每隔3秒显示下一张图片
    }
    // 在主线程中创建一个Handler对象,用于接收子线程的通知
    Handler myHandler = new Handler() {
    public void handleMessage(Message msg) {
    // 如果这个消息是本程序的那个模块发送的
    if (msg.what == 0x123) {
    // 定义一个变量i,循环的表示出 数组imageIds中每个元素的索引
    int i = currentImageId++ % images.length;
    // 在主线程中,动态的显示图片
    show.setImageResource(images[i]);
    }
    }
    };
    }


    AsyncHttpClient异步请求网络数据(Android17_AsyncHttpClient)
    1. Android开源框架AsyncHttpClient (android-async-http)使用
    android-async-http 开源框架可以使我们轻松地获取网络数据或者向服务器发送数据,最关键的是,它是异步框架,在底层使用线程池处理并发请求,效率很高,使用又特别简单。
    * 通过上面3个简单的方法看出 使用开源框架 get或post请求服务器的步骤非常简单。
    * 1.创建异步请求AsyncHttpClient对象
    * 2.封装请求参数(有就封,没就不封装)
    * 3.get 或 post 请求,这个方法中一般包括 请求的url地址、参数、处理返回结果的handler
    * 4.在成功请求的 回调方法里面,根据status 状态响应吗 head 响应头信息 responseBody响应内容的字节 数组,再进行相应操作
    1. 使用AsyncHttpClient 异步请求传输数据和下载
    public class MainActivity extends Activity {
    private TextView text01, text02;
    private EditText et_username, et_password;
    private ImageView image;
    private String str_username;
    private String str_password;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    text01 = (TextView) findViewById(R.id.text01);
    text02 = (TextView) findViewById(R.id.text02);
    et_username = (EditText) findViewById(R.id.et_username);
    et_password = (EditText) findViewById(R.id.et_password);
    image = (ImageView) findViewById(R.id.image);
    }


    public void get01(View v) {
    // 创建异步请求的对象(相当于 HttpClient)
    AsyncHttpClient client = new AsyncHttpClient();
    String url = "http://www.sina.com";
    // 然后 调用get或者 post来请求服务器端、这个方法的调用 就直接在UI线程中,第一个参数 是
    // URL,第二个参数是AsyncHttpResponseHandler对象
    // ,这个对象就是接受请求结果的,一般咱们习惯使用匿名内部类的方式来创建这个对象
    client.get(url, new AsyncHttpResponseHandler() {
    // 重写父类中的几个方法。一般都会重写onSuccess 和 onFailure


    // 可以在这里进行一些前置的 操作,比如开启 加载对话框
    @Override
    public void onStart() {
    }


    // 与服务器交互过程中,可以在这里进行 显示进度条
    @Override
    public void onProgress(int bytesWritten, int totalSize) {
    super.onProgress(bytesWritten, totalSize);
    }


    // 如果网络请求成功了,会回调这个方法。
    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
    // statusCode(此时是200)
    // headers 头部请求信息
    // responseBody 服务器成功返回的数据
    text01.setText("statusCode=" + statusCode + "\r\nheaders = " + headers);
    text02.setText("responseBody=" + new String(responseBody));
    }


    // 网络请求失败
    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
    text01.setText("请求失败了,错误码 = " + statusCode);
    text02.setText("responseBody = " + new String(responseBody));
    }


    @Override
    public void onRetry() {
    // TODO Auto-generated method stub
    super.onRetry();
    }


    });
    }


    // 使用get,通过RequestParams来携带参数,
    public void get02(View v) {
    str_username = this.et_username.getText().toString().trim();
    str_password = this.et_password.getText().toString().trim();
    // 创建异步请求对象
    AsyncHttpClient client = new AsyncHttpClient();
    // 网址
    String url = "http://www.sina.com";
    // RequestParams对象封装参数
    RequestParams params = new RequestParams();
    // "username"---从哪里来的?与服务器端约定好的 一个KEY值,服务器端程序员 就是靠 这个KEY来得到你的用户名
    params.put("username", str_username);
    params.put("password", str_password);
    client.get(url, params, new AsyncHttpResponseHandler() {


    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
    text01.setText("statusCode = " + statusCode + "\r\nheaders = " + headers);
    text02.setText("responseBody = " + new String(responseBody));
    }


    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
    text01.setText("请求失败了,错误码 = " + statusCode);
    text02.setText("responseBody = " + new String(responseBody));
    }


    });
    }


    // 同样可以使用post,通过RequestParams来携带参数
    public void post01(View v) {
    str_username = this.et_username.getText().toString().trim();
    str_password = this.et_password.getText().toString().trim();
    // 创建异步请求对象
    AsyncHttpClient client = new AsyncHttpClient();
    String url = "http://www.sina.com";
    // RequestParams对象
    RequestParams params = new RequestParams();
    params.put("username", str_username);
    params.put("password", str_password);
    client.post(url, params, new AsyncHttpResponseHandler() {
    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
    text01.setText("statusCode = " + statusCode + "\r\nheaders = " + headers);
    text02.setText("responseBody = " + new String(responseBody));
    }


    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
    text01.setText("请求失败了,错误码 = " + statusCode);
    text02.setText("responseBody = " + new String(responseBody));
    }
    });
    }


    /*
    * 通过上面3个简单的方法看出 使用开源框架 get或post请求服务器的步骤 非常简单。
    * 1.创建异步请求AsyncHttpClient对象
    * 2.封装请求参数(有就封,没就不封装)
    * 3.get 或 post 请求,这个方法中一般包括 请求的url地址、参数、处理返回结果的handler
    * 4.在成功请求的 回调方法里面,根据status 状态响应吗 head 响应头信息 responseBody响应内容的字节 数组,再进行相应操作

    * AsyncHttpClient进行网络交互的时候,还可以携带Cookie,若各位以后再工作中 涉及到了cookie的时候,
    * 可以去AsyncHttpClient官网 http:loopj.com/android-async-http/ 查询相关的 demo

    * 除此之外,还可以向服务器端 上传一个文件吧。 这个参数 常用的是 File对象 或者 IO流
    */
    // 参数为File对象,上传文件 File形式
    public void upload_01(View v) {
    // 判断外部存储是否在状态(可用)
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    // 确定本地中 需要上传的文件的路径
    File file = new File(Environment.getExternalStorageDirectory(), "2.txt");
    // 文件上传的网址
    String url = "http://www.sina.com";


    if (!file.exists())// 文件不存在
    {
    // 创建文件
    try {
    file.createNewFile();
    Toast.makeText(getApplicationContext(), "文件创建成功", Toast.LENGTH_SHORT).show();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }


    // 先判断 本地文件文件是否存在
    if (file.exists() && file.length() > 0) {
    // 创建异步请求对象
    AsyncHttpClient client = new AsyncHttpClient();
    // 设置 参数---文件形式
    RequestParams params = new RequestParams();
    try {
    params.put("file_http", file);
    } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    client.post(url, params, new AsyncHttpResponseHandler() {
    // 文件上传成功时 回调这个方法
    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
    Toast.makeText(getApplicationContext(), "文件上传成功了", Toast.LENGTH_SHORT).show();
    }


    // 文件上传失败时 回调这个方法
    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
    Toast.makeText(getApplicationContext(), "文件上传失败了!错误码=" + statusCode, Toast.LENGTH_SHORT).show();
    }
    });
    } else {
    Toast.makeText(getApplicationContext(), "本地文件 的 路径找不到或文件为空", Toast.LENGTH_SHORT).show();
    }
    }
    }


    // 将一个本地文件的抽象路径转化为IO流 ,然后上传;首先 在工程目录assets中放入一张图片 1.png,然后 将此图片转化为 输入流
    // 再以流的形式将文件上传入服务器
    public void upload_02(View v) {
    // 文件上传的网址
    final String url = "http://www.baidu.com";


    try {
    /*
    * assets文件夹里面的文件都是保持原始的文件格式,需要用AssetManager以字节流的形式读取文件。 1.
    * 先在Activity里面调用getAssets() 来获取AssetManager引用。 2.
    * 再用AssetManager的open(String fileName, int accessMode)
    * 方法则指定读取的文件以及访问模式就能得到输入流InputStream。 3. 然后就是用已经open file
    * 的inputStream读取文件,读取完成后记得inputStream.close() 。
    * 4.调用AssetManager.close() 关闭AssetManager。
    * 需要注意的是,来自Resources和Assets 中的文件只可以读取而不能进行写的操作
    */
    // InputStream is = this.getResources().getAssets().open("a.jpg");
    // InputStream is = getResources().getAssets().open("a.jpg");
    InputStream is = getAssets().open("a.jpg");


    // 上传文件
    if (is != null) {
    // 创建异步请求对象
    AsyncHttpClient client = new AsyncHttpClient();
    // 设置 参数---文件形式
    RequestParams params = new RequestParams();
    // 第一个参数 -- 约定好的一个key; 第二参数-- 需要上传文件的输入流;第三个参数 -- 为这个流 命名
    params.put("io_http", is, "a.jpg");


    client.post(url, params, new AsyncHttpResponseHandler() {
    // 文件上传成功时 回调这个方法
    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
    Toast.makeText(getApplicationContext(), "文件上传成功了", Toast.LENGTH_SHORT).show();
    }


    // 文件上传失败时 回调这个方法
    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
    Toast.makeText(getApplicationContext(), "文件上传失败了!错误码=" + statusCode, Toast.LENGTH_SHORT).show();
    }


    });
    } else {
    Toast.makeText(getApplicationContext(), "文件IO为null", Toast.LENGTH_SHORT).show();
    }


    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }


    // 除了上传,还有下载!!! 从百度手机助手上 下载 唯品会app
    public void download(View v) {
    final String DOWN_URL = "http://p.gdown.baidu.com/335968baaf3fd2e53e86ea63059c89c2f858fb97c917484548d6b5586ed137a437abce04";
    downLoadAPP(DOWN_URL, null, fileHandler);
    }
    // 下载
    private void downLoadAPP(String url, RequestParams param, FileAsyncHttpResponseHandler file) {
    // 创建异步请求对象
    AsyncHttpClient client = new AsyncHttpClient();
    client.get(url, param, file);
    }


    // 文件路径
    String app_my = Environment.getExternalStorageDirectory() + File.separator + "weipinhui.apk";
    File app_file = new File(app_my);


    // FileAsyncHttpResponseHandler是 AsyncHttpResponseHandler 子类,可用于下载功能
    FileAsyncHttpResponseHandler fileHandler = new FileAsyncHttpResponseHandler(app_file) {
    // 文件下载成功时 回调这个方法
    @Override
    public void onSuccess(int statusCode, File file) {
    Toast.makeText(getApplicationContext(), "文件下载成功了" + statusCode, Toast.LENGTH_SHORT).show();
    }
    // 文件上传失败时 回调这个方法
    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error){
    Toast.makeText(getApplicationContext(), "文件下载失败了!错误码=" + statusCode, Toast.LENGTH_SHORT).show();
    }
    };
    }
    1. 阿萨




    Fragment
    1) Fragment的产生与介:http://blog.csdn.net/lmj623565791/article/details/37992017网址里有详解
    Android 官方推荐 : DialogFragment 创建对话框(http://blog.csdn.net/lmj623565791/article/details/37815413)
    Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视。针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后拷贝一份,修改布局以适应平板神马超级大屏的。难道无法做到一个App可以同时适应手机和平板么,当然了,必须有啊。Fragment的出现就是为了解决这样的问题。你可以把Fragment当成Activity的一个界面的一个组成部分,甚至Activity的界面可以完全有不同的Fragment组成,更帅气的是Fragment拥有自己的生命周期和接收、处理用户的事件,这样就不必在Activity写一堆控件的事件处理的代码了。更为重要的是,你可以动态的添加、替换和移除某个Fragment。
    2、Fragment的生命周期

    Fragment必须是依存与Activity而存在的,因此Activity的生命周期会直接影响到Fragment的生命周期。官网这张图很好的说明了两者生命周期的关系:


    可以看到Fragment比Activity多了几个额外的生命周期回调方法:
    onAttach(Activity)
    当Fragment与Activity发生关联时调用。
    onCreateView(LayoutInflater, ViewGroup,Bundle)
    创建该Fragment的视图
    onActivityCreated(Bundle)
    当Activity的onCreate方法返回时调用
    onDestoryView()
    与onCreateView想对应,当该Fragment的视图被移除时调用
    onDetach()
    与onAttach相对应,当Fragment与Activity关联被取消时调用
    注意:除了onCreateView,其他的所有方法如果你重写了,必须调用父类对于该方法的实现,
    3、静态的使用Fragment(Android23_Fragment01)
    嘿嘿,终于到使用的时刻了~~
    这是使用Fragment最简单的一种方式,把Fragment当成普通的控件,直接写在Activity的布局文件中。步骤:
    1、继承Fragment,重写onCreateView决定Fragemnt的布局
    2、在Activity中声明此Fragment,就当和普通的View一样
    下面展示一个例子(我使用2个Fragment作为Activity的布局,一个Fragment用于标题布局,一个Fragment用于内容布局):

    是不是把Fragment当成普通的View一样声明在Activity的布局文件中,然后所有控件的事件处理等代码都由各自的Fragment去处理,瞬间觉得Activity好干净有木有~~代码的可读性、复用性以及可维护性是不是瞬间提升了~~~下面看下效果图:


    4、动态的使用Fragment(Android23_Fragment02)


    上面已经演示了,最简单的使用Fragment的方式~下面介绍如何动态的添加、更新、以及删除Fragment

    为了动态使用Fragment,我们修改一下Actvity的布局文件,中间使用一个FrameLayout,下面添加四个按钮~~~嘿嘿~~不是微信的按钮- -!


    5、Fragment家族常用的API
    Fragment常用的三个类:
    android.app.Fragment 主要用于定义Fragment
    android.app.FragmentManager 主要用于在Activity中操作Fragment
    android.app.FragmentTransaction 保证一些列Fragment操作的原子性,熟悉事务这个词,一定能明白~
    a、获取FragmentManage的方式:
    getFragmentManager() // v4中,getSupportFragmentManager
    b、主要的操作都是FragmentTransaction的方法
    FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
    transaction.add() 
    往Activity中添加一个Fragment
    transaction.remove() 
    从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁。
    transaction.replace()
    使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体~
    transaction.hide()
    隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
    transaction.show()
    显示之前隐藏的Fragment
    detach()
    会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。
    attach()
    重建view视图,附加到UI上并显示。
    transatcion.commit()//提交一个事务
    注意:常用Fragment的哥们,可能会经常遇到这样Activity状态不一致:State loss这样的错误。主要是因为:commit方法一定要在Activity.onSaveInstance()之前调用。
    上述,基本是操作Fragment的所有的方式了,在一个事务开启到提交可以进行多个的添加、移除、替换等操作。
    值得注意的是:如果你喜欢使用Fragment,一定要清楚这些方法,哪个会销毁视图,哪个会销毁实例,哪个仅仅只是隐藏,这样才能更好的使用它们。
    a、比如:我在FragmentA中的EditText填了一些数据,当切换到FragmentB时,如果希望会到A还能看到数据,则适合你的就是hide和show;也就是说,希望保留用户操作的面板,你可以使用hide和show,当然了不要使劲在那new实例,进行下非null判断。
    b、再比如:我不希望保留用户操作,你可以使用remove(),然后add();或者使用replace()这个和remove,add是相同的效果。
    c、remove和detach有一点细微的区别,在不考虑回退栈的情况下,remove会销毁整个Fragment实例,而detach则只是销毁其视图结构,实例并不会被销毁。那么二者怎么取舍使用呢?如果你的当前Activity一直存在,那么在不希望保留用户操作的时候,你可以优先使用detach。


    Android Volley完全解析(一),初识Volley的基本用法(Android29_RequestQueueFromVolley)


    1. Volley简介
    我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据。Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient,几乎在任何项目的代码中我们都能看到这两个类的身影,使用率非常高。
    不过HttpURLConnection和HttpClient的用法还是稍微有些复杂的,如果不进行适当封装的话,很容易就会写出不少重复代码。于是乎,一些Android网络通信框架也就应运而生,比如说AsyncHttpClient,它把HTTP所有的通信细节全部封装在了内部,我们只需要简单调用几行代码就可以完成通信操作了。再比如Universal-Image-Loader,它使得在界面上显示网络图片的操作变得极度简单,开发者不用关心如何从网络上获取图片,也不用关心开启线程、回收图片资源等细节,Universal-Image-Loader已经把一切都做好了。
    Android开发团队也是意识到了有必要将HTTP的通信操作再进行简单化,于是在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。
    下图所示的这些应用都是属于数据量不大,但网络通信频繁的,因此非常适合使用Volley。
     
    2. 下载Volley
    介绍了这么多理论的东西,下面我们就准备开始进行实战了,首先需要将Volley的jar包准备好,如果你的电脑上装有Git,可以使用如下命令下载Volley的源码:
    git clone https://android.googlesource.com/platform/frameworks/volley
    下载完成后将它导入到你的Eclipse工程里,然后再导出一个jar包就可以了。如果你的电脑上没有Git,那么也可以直接使用我导出好的jar包,下载地址是:http://download.csdn.net/detail/sinyu890807/7152015 。
    新建一个Android项目,将volley.jar文件复制到libs目录下,这样准备工作就算是做好了。
    3. StringRequest的用法
    前面已经说过,Volley的用法非常简单,那么我们就从最基本的HTTP通信开始学习吧,即发起一条HTTP请求,然后接收HTTP响应。首先需要获取到一个RequestQueue对象,可以调用如下方法获取到:
    RequestQueue mQueue = Volley.newRequestQueue(context);
    注意这里拿到的RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。
    接下来为了要发出一条HTTP请求,我们还需要创建一个StringRequest对象,如下所示:
    StringRequest stringRequest = new StringRequest("http://www.baidu.com",  
                            new Response.Listener<String>() {  
                                @Override  
                                public void onResponse(String response) {  
                                    Log.d("TAG", response);  
                                }  
                            }, new Response.ErrorListener() {  
                                @Override  
                                public void onErrorResponse(VolleyError error) {  
                                    Log.e("TAG", error.getMessage(), error);  
                                }  
                            });  
    可以看到,这里new出了一个StringRequest对象,StringRequest的构造函数需要传入三个参数,第一个参数就是目标服务器的URL地址,第二个参数是服务器响应成功的回调,第三个参数是服务器响应失败的回调。其中,目标服务器地址我们填写的是百度的首页,然后在响应成功的回调里打印出服务器返回的内容,在响应失败的回调里打印出失败的详细信息。
    最后,将这个StringRequest对象添加到RequestQueue里面就可以了,如下所示:
    mQueue.add(stringRequest); 
    另外,由于Volley是要访问网络的,因此不要忘记在你的AndroidManifest.xml中添加如下权限:
    <uses-permission android:name="android.permission.INTERNET" /> 
    好了,就是这么简单,如果你现在运行一下程序,并发出这样一条HTTP请求,就会看到LogCat中会打印出如下图所示的数据。
     
    没错,百度返回给我们的就是这样一长串的HTML代码,虽然我们看起来会有些吃力,但是浏览器却可以轻松地对这段HTML代码进行解析,然后将百度的首页展现出来。
    这样的话,一个最基本的HTTP发送与响应的功能就完成了。你会发现根本还没写几行代码就轻易实现了这个功能,主要就是进行了以下三步操作:
    1. 创建一个RequestQueue对象。
    2. 创建一个StringRequest对象。
    3. 将StringRequest对象添加到RequestQueue里面。
    不过大家都知道,HTTP的请求类型通常有两种,GET和POST,刚才我们使用的明显是一个GET请求,那么如果想要发出一条POST请求应该怎么做呢?StringRequest中还提供了另外一种四个参数的构造函数,其中第一个参数就是指定请求类型的,我们可以使用如下方式进行指定:
    StringRequest stringRequest = new StringRequest(Method.POST, url,  listener, errorListener); 
    可是这只是指定了HTTP请求方式是POST,那么我们要提交给服务器的参数又该怎么设置呢?很遗憾,StringRequest中并没有提供设置POST参数的方法,但是当发出POST请求的时候,Volley会尝试调用StringRequest的父类——Request中的getParams()方法来获取POST参数,那么解决方法自然也就有了,我们只需要在StringRequest的匿名类中重写getParams()方法,在这里设置POST参数就可以了,代码如下所示:
    StringRequest stringRequest = new StringRequest(Method.POST, url,  listener, errorListener) {  
        @Override  
        protected Map<String, String> getParams() throws AuthFailureError {  
            Map<String, String> map = new HashMap<String, String>();  
            map.put("params1", "value1");  
            map.put("params2", "value2");  
            return map;  
        }  
    };  


    你可能会说,每次都这样用起来岂不是很累?连个设置POST参数的方法都没有。但是不要忘记,Volley是开源的,只要你愿意,你可以自由地在里面添加和修改任何的方法,轻松就能定制出一个属于你自己的Volley版本。
    4. JsonRequest的用法
    学完了最基本的StringRequest的用法,我们再来进阶学习一下JsonRequest的用法。类似于StringRequest,JsonRequest也是继承自Request类的,不过由于JsonRequest是一个抽象类,因此我们无法直接创建它的实例,那么只能从它的子类入手了。JsonRequest有两个直接的子类,JsonObjectRequest和JsonArrayRequest,从名字上你应该能就看出它们的区别了吧?一个是用于请求一段JSON数据的,一个是用于请求一段JSON数组的。
    至于它们的用法也基本上没有什么特殊之处,先new出一个JsonObjectRequest对象,如下所示:
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://m.weather.com.cn/data/101010100.html", null,  
            new Response.Listener<JSONObject>() {  
                @Override  
                public void onResponse(JSONObject response) {  
                    Log.d("TAG", response.toString());  
                }  
            }, new Response.ErrorListener() {  
                @Override  
                public void onErrorResponse(VolleyError error) {  
                    Log.e("TAG", error.getMessage(), error);  
                }  
            });  
    可以看到,这里我们填写的URL地址是http://m.weather.com.cn/data/101010100.html,这是中国天气网提供的一个查询天气信息的接口,响应的数据就是以JSON格式返回的,然后我们在onResponse()方法中将返回的数据打印出来。
    最后再将这个JsonObjectRequest对象添加到RequestQueue里就可以了,如下所示:
    mQueue.add(jsonObjectRequest);  
    这样当HTTP通信完成之后,服务器响应的天气信息就会回调到onResponse()方法中,并打印出来。现在运行一下程序,发出这样一条HTTP请求,就会看到LogCat中会打印出如下图所示的数据。
     
    由此可以看出,服务器返回给我们的数据确实是JSON格式的,并且onResponse()方法中携带的参数也正是一个JSONObject对象,之后只需要从JSONObject对象取出我们想要得到的那部分数据就可以了。
    你应该发现了吧,JsonObjectRequest的用法和StringRequest的用法基本上是完全一样的,Volley的易用之处也在这里体现出来了,会了一种就可以让你举一反三,因此关于JsonArrayRequest的用法相信已经不需要我再去讲解了吧。






    Gson :Google 提供的用来在 Java 对象和 JSON 数据之间进行映射的 Java 类库。可以将一个 JSON 字符串转成一个 Java 对象,或者反过来。Gson解析json数据。
    实体类:
    public class Student {  
        private int id;  
        private String name;  
        private Date birthDay;  
        public int getId() {  
            return id;  
        }  
        public void setId(int id) {  
            this.id = id;  
        }  
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
        public Date getBirthDay() {  
            return birthDay;  
        }  
        public void setBirthDay(Date birthDay) {  
            this.birthDay = birthDay;  
        }   
        public String toString() {  
            return "Student [birthDay=" + birthDay + ", id=" + id + ", name="  
                    + name + "]";  
        }  
    }  


    测试类:
    import java.util.ArrayList;  
    import java.util.Date;  
    import java.util.List;  
      
    import com.google.gson.Gson;  
    import com.google.gson.reflect.TypeToken;  
    public class GsonTest1 {  
        public static void main(String[] args) {  
            Gson gson = new Gson();  
            Student student1 = new Student();  
            student1.setId(1);  
            student1.setName("李坤");  
            student1.setBirthDay(new Date());  
      
            // //  
            System.out.println("----------简单对象之间的转化-------------");  
            // 简单的bean转为json  
            String s1 = gson.toJson(student1);  
            System.out.println("简单Bean转化为Json===" + s1);  
      
            // json转为简单Bean  
            Student student = gson.fromJson(s1, Student.class);  
            System.out.println("Json转为简单Bean===" + student);  
            // 结果:  
            // 简单Bean转化为Json==={"id":1,"name":"李坤","birthDay":"Jun 22, 2012 8:27:52 AM"}  
            // Json转为简单Bean===Student [birthDay=Fri Jun 22 08:27:52 CST 2012, id=1,  
            // name=李坤]  
            // //  
            Student student2 = new Student();  
            student2.setId(2);  
            student2.setName("曹贵生");  
            student2.setBirthDay(new Date());  
      
            Student student3 = new Student();  
            student3.setId(3);  
            student3.setName("柳波");  
            student3.setBirthDay(new Date());  
      
            List<Student> list = new ArrayList<Student>();  
            list.add(student1);  
            list.add(student2);  
            list.add(student3);  
      
            System.out.println("----------带泛型的List之间的转化-------------");  
            // 带泛型的list转化为json  
            String s2 = gson.toJson(list);  
            System.out.println("带泛型的list转化为json==" + s2);  
      
            // json转为带泛型的list  
            List<Student> retList = gson.fromJson(s2,  
                    new TypeToken<List<Student>>() {  
                    }.getType());  
            for (Student stu : retList) {  
                System.out.println(stu);  
            }  
      
            // 结果:  
            // 带泛型的list转化为json==[{"id":1,"name":"李坤","birthDay":"Jun 22, 2012 8:28:52 AM"},{"id":2,"name":"曹贵生","birthDay":"Jun 22, 2012 8:28:52 AM"},{"id":3,"name":"柳波","birthDay":"Jun 22, 2012 8:28:52 AM"}]  
            // Student [birthDay=Fri Jun 22 08:28:52 CST 2012, id=1, name=李坤]  
            // Student [birthDay=Fri Jun 22 08:28:52 CST 2012, id=2, name=曹贵生]  
            // Student [birthDay=Fri Jun 22 08:28:52 CST 2012, id=3, name=柳波]  
      
        }  
    }  


    执行结果:
    ----------简单对象之间的转化-------------  
    简单Bean转化为Json==={"id":1,"name":"李坤","birthDay":"Jun 22, 2012 9:10:31 PM"}  
    Json转为简单Bean===Student [birthDay=Fri Jun 22 21:10:31 CST 2012, id=1, name=李坤]  
    ----------带泛型的List之间的转化-------------  
    带泛型的list转化为json==[{"id":1,"name":"李坤","birthDay":"Jun 22, 2012 9:10:31 PM"},{"id":2,"name":"曹贵生","birthDay":"Jun 22, 2012 9:10:31 PM"},{"id":3,"name":"柳波","birthDay":"Jun 22, 2012 9:10:31 PM"}]  
    Student [birthDay=Fri Jun 22 21:10:31 CST 2012, id=1, name=李坤]  
    Student [birthDay=Fri Jun 22 21:10:31 CST 2012, id=2, name=曹贵生]  
    Student [birthDay=Fri Jun 22 21:10:31 CST 2012, id=3, name=柳波]  






    Xml之Pull解析和xml存储(Android24_XML_Pull)
    1. xml文件(books.xml)
    <?xml version="1.0" encoding="UTF-8"?> 
    <books>
        <book id="1">
            <name>鬼吹灯</name>
            <price>36</price>
        </book>
        <book id="2">
            <name>JAVA秘籍</name>
            <price>56</price>
        </book>
        <book id="3">
            <name>Android宝典</name>
            <price>66</price>
        </book>
    </books> 
    1. 解析和保存的工具类
    public class BookMgr {
    public static final String BOOKS="books";
    public static final String BOOK="book";
    public static final String NAME="name";
    public static final String PRICE="price";
    public static final String ID="id";


    /** 解析xml文件
    * @param is :输入流
    * @return ArrayList <HashMap<String, Object>> 
    */
    public static ArrayList<HashMap<String, Object>> parserXML(InputStream is) throws Exception{
    //取得一个xml解析器
    XmlPullParser parser=Xml.newPullParser();
    //设置要解析的内容
    parser.setInput(is, "UTF-8");
    //获取事件类型
    int event=parser.getEventType();
    ArrayList<HashMap<String,Object>> data=null;
    HashMap<String, Object> map=null;
    //当还没到文档的尾部时
    while(event!=XmlPullParser.END_DOCUMENT){
    switch (event) {
    case XmlPullParser.START_TAG://比较开始标签
    String name=parser.getName();//获取标签名
    if(BOOKS.equals(name)){
    //new 一个ArrayList
    data=new ArrayList<HashMap<String,Object>>();
    }else if(BOOK.equals(name)){
    //new 一个map
    map=new HashMap<String, Object>();
    //往map中添加值
    map.put(ID, parser.getAttributeValue(0));
    }else if(NAME.equals(name)||PRICE.equals(name)){
    map.put(name, parser.nextText());
    }
    break;
    case XmlPullParser.END_TAG:
    if(BOOK.equals(parser.getName())){
    //把map添加到list中
    data.add(map);
    }


    default:
    break;
    }
    //开始下一个解析动作,并且获取解析动作的类型
    event=parser.next();
    }
    //关闭输入流
    is.close();
    return data;
    }


    /**
    * 把数据存在.xml文件中
    * @param data  :输入的数据列表
    * @param outstream  :把输入的列表数据转换为输出流,进行输出
    */
    public static void exportXml
    (ArrayList<HashMap<String, Object>> inputdata, OutputStream outstream) throws Exception {
    //获取xml构建器
    XmlSerializer serializer=Xml.newSerializer();
    //设置要输出到哪里去,格式是什么
    serializer.setOutput(outstream, "UTF-8");
    //写xml开始 节点
    serializer.startDocument("UTF-8", true);
    //写books开始标签
    serializer.startTag(null, BOOKS);
    //for 循环,遍历出所有的 book ,写到xml中
    for(HashMap<String, Object> map:inputdata){
    //写book开始标签
    serializer.startTag(null, BOOK);
    //写 book属性
    serializer.attribute(null, ID, map.get(ID).toString());
    //写name开始标签
    serializer.startTag(null, NAME);
    serializer.text(map.get(NAME).toString());
    //写name结束标签
    serializer.endTag(null, NAME);
    //写price开始标签
    serializer.startTag(null, PRICE);
    //写price值
    serializer.text(map.get(PRICE).toString());
    //写price结束标签
    serializer.endTag(null, PRICE);
    //写book结束标签
    serializer.endTag(null, BOOK);
    }
    //写books结束标签
    serializer.endTag(null, BOOKS);
    //写xml结束节点
    serializer.endDocument();
    outstream.close();
    }
    }
    1. Activity中实现
    /**
     * XML之Pull解析
     * @author Administrator
     *
     */
    public class PullActivity extends Activity {
    ArrayList<HashMap<String,Object>> data;


        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_pull);
            //每一项的item的样子  ,初始化的数据
            ListView bookList=(ListView) findViewById(R.id.book_list);
            
            //传参数
            InputStream is=getClassLoader().getResourceAsStream("books.xml");
            try {
            //数据从books.xml解析中来
    data=BookMgr.parserXML(is);
    } catch (Exception e) {
    e.printStackTrace();
    }
            //给适配器装配数据
            SimpleAdapter simpleAdapter=new SimpleAdapter(this, data, 
            R.layout.book_item,
            new String[]{BookMgr.NAME,BookMgr.PRICE},
            new int[]{R.id.book_name,R.id.book_price});
            //绑定适配器
            bookList.setAdapter(simpleAdapter);
            
        }
        
        //把解析到的数据保存到sdcard中
        public void exportXML(View v){
        //把数据输出到xml文件中
        //定义一个输出流,写入到sdcard中
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
       
        File file1=new File(Environment.getExternalStorageDirectory(), "ff");
        //创建多个目录
        file1.mkdirs();
    //    File rootFile=Environment.getExternalStorageDirectory();
        File file=new File(file1, "books.xml");
        try {
    BookMgr.exportXml(data,new FileOutputStream(file));

    catch (Exception e) {
    e.printStackTrace();
    }
        }
       
        }
    }


    自定义拍照之SurfaceView(Android25_customPhone)
    1. SurfaceView介绍:SurfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器
    详解地址:http://www.360doc.com/content/13/0103/14/7724936_257842268.shtml
    1. 布局
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <!-- SurfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器 -->
        <SurfaceView 
            android:id="@+id/surfaceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
        <TextView
            android:id="@+id/takePhoto"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="10dp"
            android:background="#cccccc"
            android:padding="10dp"
            android:text="拍照" />
    </RelativeLayout>
    1. 代码
    /**
     * 自定义拍照 SurfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器;
     * Camera.Parameters:相机的服务设置。使相机参数生效,应用程序必须调用setparameters(相机参数。)。
     */
    @SuppressLint("NewApi")
    public class MainActivity extends Activity implements OnClickListener {
    private Camera camera;
    // 相机的服务设置
    private Camera.Parameters parameters;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.takePhoto).setOnClickListener(this);
    // surfaceView是在一个新起的单独线程中可以重新绘制画面,当使用surfaceView
    // 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。
    // 但这也带来了另外一个问题,就是事件同步
    SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
    // 设置SurfaceView分辨率
    surfaceView.getHolder().setFixedSize(176, 144);
    // 保持屏幕常亮
    surfaceView.getHolder().setKeepScreenOn(true);
    // 为SurfaceView添加一个回调函数
    surfaceView.getHolder().addCallback(new SurfaceViewCallback());
    }


    @Override
    public void onClick(View v) {
    switch (v.getId()) {
    case R.id.takePhoto:// 拍照
    camera.takePicture(null, null, new PictureCallback() {


    @Override // 第一个参数就是图片数据。
    public void onPictureTaken(byte[] data, Camera camera) {
    // 把数据保存到sd卡中
    saveSD(data);
    }
    });
    break;
    }
    }


    // 把数据保存到sd卡中
    protected void saveSD(byte[] data) {
    String fileName = System.currentTimeMillis() + ".jpg";
    File file = new File(Environment.getExternalStorageDirectory() + "/files/");
    if (!file.exists()) {
    file.mkdirs();
    }
    File jpgFile = new File(file, fileName);


    try {
    // 文件输出流
    FileOutputStream fos = new FileOutputStream(jpgFile);
    // 写入sd卡
    fos.write(data);
    // 关闭输入流
    fos.close();
    } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }


    /**
    * SurfaceView的回调函数
    */
    private class SurfaceViewCallback implements Callback {
    // SurfaceView创建时调用
    @Override
    public void surfaceCreated(SurfaceHolder holder) {


    try {
    // 打开摄像头
    camera = Camera.open();
    // 设置SurfaceView显示Camera
    camera.setPreviewDisplay(holder);
    // 设置拍照方向
    camera.setDisplayOrientation(getPreviewDegree());
    // 开始预览
    camera.startPreview();
    // 在自定义相机的代码中,调用
    // camera.takePicture(null,rawCallback,jpegCallback); 方法完成拍照时会发现
    // 无论系统的音量时震动、静音还是有声音都无法关闭自定义相机的拍照声音。
    // camera.takePicture(null,rawCallback,jpegCallback);
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }


    // SurfaceView拍照状态改变时调用
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    // 获取camera的各项参数
    parameters = camera.getParameters();
    // 图片格式
    parameters.setPictureFormat(PixelFormat.JPEG);
    // 设置预览大小
    parameters.setPreviewSize(width, height);
    // 设置每秒显示的帧数
    parameters.setPreviewFpsRange(4, 6);
    // 设置图片保存尺寸
    parameters.setPictureSize(width, height);
    // 设置图片质量
    parameters.setJpegQuality(100);
    }


    // SurfaceView销毁时调用
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    if (camera != null) {
    // 释放照相机
    camera.release();
    camera = null;
    }
    }
    }


    // 根据activity方向获取carame的方法
    private int getPreviewDegree() {
    // 获取屏幕方向
    int rotation = getWindowManager().getDefaultDisplay().getRotation();
    int degree = 0;
    // 根据手机屏幕的方向,计算照相机的方法
    switch (rotation) {
    case Surface.ROTATION_0:
    degree = 90;
    break;
    case Surface.ROTATION_90:
    degree = 0;
    break;
    case Surface.ROTATION_180:
    degree = 270;
    break;
    case Surface.ROTATION_270:
    degree = 180;
    break;
    }
    return degree;
    }
    }




    拍照之调用本机的拍照软件(Android25_photoUri)
    1. 代码:
    **
     * 拍照
     */
    public class MainActivity extends Activity implements OnClickListener {


    //图片保存路径
    private Uri photoUri;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    findViewById(R.id.takePhoto).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
    switch (v.getId()) {
    case R.id.takePhoto:
    //使用前,判断sd卡是否存在
    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
    {
    Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    //键值对管理类,使用ContentValues存储图片路径,可以获取图片的原图
    ContentValues values=new ContentValues();
    // 插入图片路径到数据库
    photoUri=getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    //把图片路径存入photoUri:content://media/external/images/media/375
    intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, photoUri);
    startActivityForResult(intent, 1);
    }else
    {
    Toast.makeText(getApplicationContext(), "sd卡不存在", Toast.LENGTH_SHORT).show();
    }
    break;
    }
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    //获取图片绝对路径 picPath:/storage/emulated/0/DCIM/Camera/1464849143598.jpg
    if(requestCode==Activity.RESULT_OK)
    {
    //图片在数据库中的列名
    String[] projection={MediaStore.Images.Media.DATA};
    //游标,读取数据时,数据的位置信息
    Cursor cursor=getContentResolver().query(photoUri, projection, null, null, null);
    String picPath="";
    if(resultCode==1)
    {
    if (data==null) {
    //使用之前,判断data是不是为空,在有些手机会出现错误
    Toast.makeText(getApplicationContext(), "选择图片出错", Toast.LENGTH_SHORT).show();
    finish();
    }
    if(cursor!=null)
    {
    // 根据列名,获取查询数据的下标
    int columnIndex=cursor.getColumnIndexOrThrow(projection[0]);
    //使用游标时,必须把游标移动到最前面
    cursor.moveToFirst();
    picPath=cursor.getString(columnIndex);
    cursor.close();
    }
    }
    }
    }
    }


    音频播放之SoundPool(Android25_SoundPool)
    SoundPool —— 适合短促且对反应速度比较高的情况(游戏音效或按键声等)
    1. 详情地址:http://blog.csdn.net/qduningning/article/details/8680575
    2. 代码
    /**
     * 音频播放:SoundPool */
    public class MainActivity extends Activity implements OnClickListener {


    private SoundPool player;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    findViewById(R.id.play).setOnClickListener(this);
    findViewById(R.id.pause).setOnClickListener(this);
    findViewById(R.id.stopPlayer).setOnClickListener(this);
    第一个参数:播放几个音频文件
    // 第二个:声音类型
    // 第三个:声音品质
    player = new SoundPool(2, AudioManager.STREAM_MUSIC, 100);
    player.load(this, R.raw.a_sos, 0);
    player.load(this, R.raw.beep, 1);


    }


    @Override
    public void onClick(View v) {
    switch (v.getId()) {
    case R.id.play://开始播放
    player.play(1, 0.5f, 0.5f, 0, 0, 1f);
    player.play(2, 0.5f, 0.5f, 0, 0, 1f);
    break;
    case R.id.pause://暂停
    player.pause(1);
    player.pause(2);
    //继续播放
    //player.resume(2);
    break;
    case R.id.stopPlayer://停止播放
    player.stop(1);
    player.stop(2);
    //释放资源
    player.release();
    break;
    default:
    break;
    }
    }
    }


    拍照完后显示显示照片在界面上(Android26_CameraAndPhoto)

    1. 展示:


    从网络上获取图片(Android26_CompressImage)




    图片加载之 LruCache图片缓存技术(Android26_PicLruCache)
    1. LruCache:图片缓存之内存缓存技术.内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了快速访问的方法。 其中最核心的类是LruCache (此类在android-support-v4的包中提供) 。这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。 它有一个特点,当缓存的图片达到了预先设定的值的时候,那么近期使用次数最少的图片就会被回收掉。
    步骤:(1)要先设置缓存图片的内存大小,我这里设置为手机内存的1/4, 手机内存的获取方式:
    int MAXMEMONRY = (int)(Runtime.getRuntime() .maxMemory() / 1024);
    (2)LruCache里面的键值对分别是URL和对应的图片 (3)重写了一个叫做sizeOf的方法,返回的是图片数量。
    1. 代码
    //图片缓存
    public class MainActivity extends Activity {
    // 图片网址
    private String url = "http://g.hiphotos.baidu.com/image/h%3D200/sign=9d57666cf8039245beb5e60fb795a4a8/4b90f603738da977678b168ab451f8198718e3ef.jpg";
    // 内存类
    private LruCache<String, Bitmap> mLruCache;
    // 图片保存的文件夹
    private String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/files/";
    private ImageView pic1, pic2, pic3;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    pic1 = (ImageView) findViewById(R.id.pic1);
    pic2 = (ImageView) findViewById(R.id.pic2);
    pic3 = (ImageView) findViewById(R.id.pic3);


    // 初始化内存设置
    initLruCache();
    // 从网络获取数据
    getNetImage();


    // pic1的监听器
    pic1.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    // 加载内存中的图片
    if (getCacheBitmap(url) != null) {
    pic2.setImageBitmap(getCacheBitmap(url));
    }
    }
    });
    pic2.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    //加载sd卡中的图片
    if (readSD(url) != null) {
    pic3.setImageBitmap(readSD(url));
    }
    }
    });


    }


    // 读取sd卡图片
    protected Bitmap readSD(String url) {
    Bitmap bitmap = null;
    String imageSDPath = path + url.substring(url.lastIndexOf("/") + 1, url.length()).toLowerCase();
    File file = new File(imageSDPath);
    // 判断文件是否存在
    if (!file.exists()) {
    return null;
    }
    bitmap = BitmapFactory.decodeFile(imageSDPath);
    if (bitmap != null || bitmap.toString().length() > 5) {
    return bitmap;
    } else {
    return null;
    }
    }


    // 获取内存中的bitmap
    protected Bitmap getCacheBitmap(String key) {
    return mLruCache.get(key);
    }


    // 从网络获取数据
    private void getNetImage() {
    new Thread() {
    public void run() {
    HttpClient httpClient = new DefaultHttpClient();
    HttpGet get = new HttpGet(url);
    try {
    HttpResponse response = httpClient.execute(get);
    if (response.getStatusLine().getStatusCode() == 200) {
    // 获取返回结果的实体类
    HttpEntity httpEntity = response.getEntity();
    InputStream is = httpEntity.getContent();
    Bitmap bmp = BitmapFactory.decodeStream(is);
    handler.obtainMessage(1, bmp).sendToTarget();
    }
    } catch (Exception e) {
    e.printStackTrace();
    }


    }
    }.start();
    }


    // 主线程
    private Handler handler = new Handler() {
    public void handleMessage(Message msg) {
    switch (msg.what) {
    case 1:
    Bitmap bmp = (Bitmap) msg.obj;
    // 保存到内存中
    addCache(url, bmp);
    // 保存到sd卡中
    saveSD(url, bmp);
    pic1.setImageBitmap(bmp);
    break;
    }
    }
    };


    // 初始化内存设置
    private void initLruCache() {
    // 获取程序可用的最大内存
    int maxMemory = (int) Runtime.getRuntime().maxMemory();
    // 设置缓存图片的内存大小
    int cacheSize = maxMemory / 4;
    // 实例化内存类
    mLruCache = new LruCache<String, Bitmap>(cacheSize);
    }


    // 保存bitmap到sd卡
    protected void saveSD(String url, Bitmap bmp) {
    try {
    final String fileName = url.substring(url.lastIndexOf("/") + 1, url.length()).toLowerCase();
    File file = new File(path + fileName);
    // 判断sd卡是否存在
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    // 判断文件夹是否存在
    File mm = new File(path);
    if (!mm.exists()) {
    mm.mkdirs();
    }
    // 保存bitmap到sd卡
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
    // 把bitmap写入文件中
    bmp.compress(Bitmap.CompressFormat.JPEG, 100, bos);
    // 清空缓存
    bos.flush();
    bos.close();
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    // 把图片添加到内存
    protected void addCache(String url, Bitmap bmp) {
    if (getCacheBitmap(url) == null) {
    if (bmp != null) {
    mLruCache.put(url, bmp);
    }
    }
    }
    }


    通过线程池加载图片(Android26_ThreadPool)
    1. 线程池:线程池是预先创建线程的一种技术。线程池在还没有任务到来之前,创建一定数量的线程,放入空闲队列中。这些线程都是处于睡眠状态,即均为启动,不消耗CPU,而只是占用较小的内存空间。当请求到来之后,缓冲池给这次请求分配一个空闲线程,把请求传入此线程中运行,进行处理。当预先创建的线程都处于运行状态,即预制线程不够,线程池可以自由创建一定数量的新线程,用于处理更多的请求。当系统比较闲的时候,也可以通过移除一部分一直处于停用状态的线程。
    2. 通过线程池获取图片
    /**
     * 获取图片,线程池
     */
    public class ThreadPoolImageLoader {
    // 创建线程池,参数:有多少个线程可以同时运行
    private ExecutorService executorService = Executors.newFixedThreadPool(3);
    private Handler handler=new Handler();

    //加载网络图片
    public void loadImage(final String url,final Callback callback)
    {
    //Runnable:新开一个线程
    executorService.submit(new Runnable(){
    @Override
    public void run() {
    Drawable drawable=loadImageUrl(url);
    //讲drawable转换成bitmap
    BitmapDrawable bd=(BitmapDrawable)drawable;
    final Bitmap bmp=bd.getBitmap();
    //Runnable:不会新开一个线程;把线程内的数据传递到主线程
    handler.post(new Runnable(){
    @Override
    public void run() {
    callback.result(bmp);
    }
    });
    }
    });
    }
    //从网络上下载图片
    private Drawable loadImageUrl(String url)
    {
    try {
    //获取输入流
    InputStream is=new URL(url).openStream();
    //将输入流转换为drawable
    return Drawable.createFromStream(is, "image.png");
    } catch (Exception e) {
    return null;
    }
    }
    interface Callback{
    void result(Bitmap bitmap);
    }
    }


    1. MainActivity
    /**
     * 通过线程池加载图片 */
    public class MainActivity extends Activity {
    private String url = "http://g.hiphotos.baidu.com/image/h%3D200/sign=9d57666cf8039245beb5e60fb795a4a8/4b90f603738da977678b168ab451f8198718e3ef.jpg";
    private ImageView pic1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    pic1 =(ImageView)findViewById(R.id.pic1);
    //实例化对象
    ThreadPoolImageLoader tpoolImage=new ThreadPoolImageLoader();
    tpoolImage.loadImage(url, new Callback(){
    @Override
    public void result(Bitmap bitmap) {
    pic1.setImageBitmap(bitmap);
    }
    });
    L.i("ss");
    }
    }


    AIDL:为使应用程序之间能够彼此通信,Android提供了IPC (Inter Process Communication,进程间通信)的一种独特实现: AIDL (Android Interface Definition Language, Android接口定义语言)。
    AIDL是IPC的一个轻量级实现,用了对于Java开发者来说很熟悉的语法。Android也提供了一个工具,可以自动创建Stub(类构架,类骨架)。当我们需要在应用间通信时,我们需要按以下几步走:
    1. 定义一个AIDL接口
    2. 为远程服务(Service)实现对应Stub
    3. 将服务“暴露”给客户程序使用
    用例: HelloSumAIDL
    AIDL的语法很类似Java的接口(Interface),只需要定义方法的签名。
    AIDL支持的数据类型与Java接口支持的数据类型有些不同
    1. 所有基础类型(int, char, 等)
    2. String,List,Map,CharSequence等类
    3. 其他AIDL接口类型
    4. 所有Parcelable的类
    阿魏啊

    JNI:JNI是JAVA标准平台中的一个重要功能,它弥补了JAVA的与平台无关这一重大优点的不足,在JAVA实现跨平台的同时,也能与其它语言(如C、C++)的动态库进行交互,给其它语言发挥优势的机会。JNI提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。

    有了JAVA标准平台的支持,使JNI模式更加易于实现和使用。在此总结了下面这个知识图:


    Android中系统日期时间的获取
    import    java.text.SimpleDateFormat;       
           
    SimpleDateFormat    formatter    =   new    SimpleDateFormat    ("yyyy年MM月dd日    HH:mm:ss     ");       
    Date    curDate    =   new    Date(System.currentTimeMillis());//获取当前时间       
    String    str    =    formatter.format(curDate);       
     
    可以获取当前的年月时分,也可以分开写:
    [java] view plain copy print?
    SimpleDateFormat    sDateFormat    =   new    SimpleDateFormat("yyyy-MM-dd    hh:mm:ss");       
    String    date    =    sDateFormat.format(new    java.util.Date());    
     
    如果想获取当前的年月,则可以这样写(只获取时间或秒种一样):
    Java代码
    [java] view plain copy print?
    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM");    
    String date=sdf.format(new <a href="http://lib.csdn.net/base/17" class='replace_word' title="Java EE知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Java</a>.util.Date());    
    当然还有就是可以指定时区的时间(待):
    [java] view plain copy print?
    df=DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL,Locale.CHINA);  
    System.out.println(df.format(new Date()));  
     
     
    如何获取Android系统时间是24小时制还是12小时制
           
    ContentResolver cv = this.getContentResolver();  
           String strTimeFormat = <a href="http://lib.csdn.net/base/15" class='replace_word' title="Android知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Android</a>.provider.Settings.System.getString(cv,  
                                              android.provider.Settings.System.TIME_12_24);  
            
           if(strTimeFormat.equals("24"))  
          {  
                  Log.i("activity","24");  
           }  


    利用Calendar获取
    Calendar c = Calendar.getInstance();  
    取得系统日期:year = c.get(Calendar.YEAR)  
                   month = c.get(Calendar.MONTH)  
                   day = c.get(Calendar.DAY_OF_MONTH)  
    取得系统时间:hour = c.get(Calendar.HOUR_OF_DAY);  
                      minute = c.get(Calendar.MINUTE)  
                      int second=c.get(Calendar.SECOND);
    利用Time获取
    Time t=new Time(); // or Time t=new Time("GMT+8"); 加上Time Zone资料。  
    t.setToNow(); // 取得系统时间。  
    int year = t.year;  
    int month = t.month;  
    int date = t.monthDay;  
    int hour = t.hour; // 0-23  
    int minute = t.minute;  
    int second = t.second;  


    唯一不足是取出时间只有24小时模式.


    自定义ListView让一个页面可以同时展示几个ListView(Android28_WorkListView)
    1. 自定义ListView:
    /**
     * 重新测量Listview的宽度和高度 */
    public class MyListView extends ListView {

    public MyListView(Context context) {
    super(context);
    }


    public MyListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    }


    public MyListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    }
    //重新测量listview的宽度和高度
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 重新测量gridview的宽度和高度
    int height=MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, height);
    }
    }
    1. Xml
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:scrollbars="vertical" >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" >
            <!-- ListView组件 -->
            <!-- 用自定义的listView使整个界面可以滑动,不然只会本身的ListView可以滑动 -->
            <com.cm.android28_worklistview.MyListView
                android:id="@+id/mylist1"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />
            <com.cm.android28_worklistview.MyListView
                android:id="@+id/mylist2"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />
            <com.cm.android28_worklistview.MyListView
                android:id="@+id/mylist3"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </ScrollView>
    1. MainActivity
    public class MainActivity extends Activity {
    // 定义信息
    private int[] images={R.drawable.jingjing,R.drawable.ruodan,R.drawable.yifei};
    private String[] names = { "刘静静", "刘洛丹", "胡一菲" };
    private String[] years = { "33岁", "29岁", "28岁" };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ArrayList<HashMap<String,String>> listItem01=new ArrayList<HashMap<String,String>>();
    //把信息保存在list集合中
    for (int i = 0; i < names.length; i++) {
    HashMap<String,String> map01=new HashMap<String, String>();
    //把数据放在Map集合中
    map01.put("name", names[i]);
    map01.put("year", years[i]);
    //把数据加入到List集合中
    listItem01.add(map01);
    }
    ArrayList<HashMap<String,Object>> listItem02=new ArrayList<HashMap<String,Object>>();
    for (int i = 0; i < names.length; i++) {
    HashMap<String,Object> map02=new HashMap<String, Object>();
    //把数据放在Map集合中
    map02.put("image",images[i]);
    map02.put("name", names[i]);
    map02.put("year", years[i]);
    //把数据加入到List集合中
    listItem02.add(map02);
    }
    // 获得ListView组件
    ListView list01 = (ListView) findViewById(R.id.mylist1);
    ListView list02 = (ListView) findViewById(R.id.mylist2);
    ListView list03 = (ListView) findViewById(R.id.mylist3);
    // 适配器
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_single_choice, names);
    list01.setAdapter(adapter);
    //适配器
    String [] from={"name","year"};
    int[] to={R.id.names,R.id.years};
    SimpleAdapter simpleAdapter=new SimpleAdapter(this, listItem01, R.layout.rl02_layout, from, to);
    //设置适配器
    list02.setAdapter(simpleAdapter);
    //自定义适配器
    MyCustomAdapter customAdapter=new MyCustomAdapter(this, listItem02);
    list03.setAdapter(customAdapter);
    }

    }


    图片加载框架ImageLoader(Android29_ImageLoaderConfiguration)
    1. Universal-Image-Loader这个开源框架又来给我们造福了,它是一个图片加载框架,主要强大在于可以用于网络等图片源的加载,并且有多重缓存机制。 多线程的图像加载的可能性的宽调谐对ImageLoader的配置(线程池的大小,HTTP选项,内存和光盘高速缓存,显示图像,以及其他)的图像的可能性中的缓存存储器和/或设备的文件器系统(或SD卡)
    2. 图片的异步加载和双缓存
    /*
     *DisplayImageOptions 图片的异步加载和双缓存
     * ImageLoaderConfiguration 设置缓存 */
    public class MainActivity extends Activity {
    private String url2 = "http://att.x2.hiapk.com/album/201203/30/134620xxxftxszc0apaiff.jpg";
    private ImageView pic;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    pic = (ImageView) findViewById(R.id.pic);
    // ImageLoader配置信息,图片的异步加载和双缓存
    DisplayImageOptions options = new DisplayImageOptions.Builder()
    .cacheInMemory(true)// 设置内存缓存
    .cacheOnDisc(true)// 设置sd卡缓存
    .build();
    //设置缓存
    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).defaultDisplayImageOptions(options)
    .diskCacheSize(200 * 1024 * 1024)// sd缓存大小
    .discCacheFileCount(200)// sd卡缓存数量
    .memoryCacheSize(50 * 1024 * 1024)// 内存大小
    .writeDebugLogs()// 日志信息
    .build();
    // 初始化ImageLoader
    ImageLoader.getInstance().init(config);
    //ImageLoader加载图片
    ImageLoader.getInstance().displayImage(url2, pic);
    }
    }


    OkHttp:网络访问(Android29_oKHttp)
    现在Android网络方面的第三方库很多,volley,Retrofit,OKHttp等,各有各自的特点,这边博客就来简单介绍下如何使用OKHttp。
    梗概
    OKHttp是一款高效的HTTP客户端,支持连接同一地址的链接共享同一个socket,通过连接池来减小响应延迟,还有透明的GZIP压缩,请求缓存等优势
    详情地址:http://blog.csdn.net/lmj623565791/article/details/47911083
    一、概述
    最近在群里听到各种讨论okhttp的话题,可见okhttp的口碑相当好了。再加上Google貌似在6.0版本里面删除了HttpClient相关API,对于这个行为不做评价。为了更好的在应对网络访问,学习下okhttp还是蛮必要的,本篇博客首先介绍okhttp的简单使用,主要包含:
    一般的get请求
    一般的post请求
    基于Http的文件上传
    文件下载
    加载图片
    支持请求回调,直接返回对象、对象集合
    支持session的保持
    最后会对上述几个功能进行封装,完整的封装类的地址见:https://github.com/hongyangAndroid/okhttp-utils
    二、使用教程
    (一)Http Get
    对了网络加载库,那么最常见的肯定就是http get请求了,比如获取一个网页的内容。
    (二) Http Post 携带参数
    看来上面的简单的get请求,基本上整个的用法也就掌握了,比如post携带参数,也仅仅是Request的构造的不同。
    三、封装
    由于按照上述的代码,写多个请求肯定包含大量的重复代码,所以我希望封装后的代码调用是这样的:
    四、整合Gson
    很多人提出项目中使用时,服务端返回的是Json字符串,希望客户端回调可以直接拿到对象,于是整合进入了Gson,完善该功能。


    Sensor传感器、感应器(Android29_Sensor)
    1. Sensor Type
          重力感应/加速度传感器 (G-Sensor)
          光感应   (Light-Sensor) 
          温度感应
          方向感应
          磁场、
          临近性
    2.如何实现Sensor编程
         a.获取系统服务(SENSOR_SERVICE)返回一个SensorManager 对象
               sensormanager = (SensorManager)getSystemSeriver(SENSOR_SERVICE);
         b.通过SensorManager对象获取相应的Sensor类型的对象
               sensorObject = sensormanager.getDefaultSensor(sensor Type);
         c.声明一个SensorEventListener 对象用于侦听Sensor 事件,并重载onSensorChanged方法
                SensorEventListener sensorListener = new SensorEventListener(){
                 };
         d.注册相应的SensorService
                 sensormanager.registerListener(sensorListener, sensorObject, Sensor TYPE);
        e.销毁相应的SensorService
                sensormanager.unregisterListener(sensorListener, sensorObject);
     
        f: SensorListener 接口是传感器应用程序的中心。它包括两个必需方法:
              onSensorChanged(int sensor,float values[]) 方法在传感器值更改时调用。
              该方法只对受此应用程序监视的传感器调用(更多内容见下文)。该方法的参数包括:一个整数,指示更改的传感器;一个浮点值数组,表示传感器数据本身。有些传感器只提供一个数据值,另一些则提供三个浮点值。方向和加速表传感器都提供三个数据值。
          当传感器的准确性更改时,将调用 onAccuracyChanged(int sensor,int accuracy) 方法。参数包括两个整数:一个表示传感器,另一个表示该传感器新的准确值。
    3. 检测手机又哪些传感器
    /**
     * 检测手机又哪些传感器
     */
    public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //获取传感器服务
    SensorManager sensorManager=(SensorManager)getSystemService(Context.SENSOR_SERVICE);
    //获取所有传感器列表
    List<Sensor> list=sensorManager.getSensorList(Sensor.TYPE_ALL);
    for (int i = 0; i <list.size(); i++) {
    Log.e("阿萨德", list.get(i).getName());
    }
    }
    }
    3. 震动传感器
    a. 一个检测手机摇晃的监听器
    /**
     * 一个检测手机摇晃的监听器 *
     */
    public class ShakeListener implements SensorEventListener {
    // 获取传感器服务
    private SensorManager sensorManager;
    private Context context;
    // 传感器
    private Sensor sensor;
    // 重力感应监听器 ,接口
    private OnShakeListener listener;
    // 手机上一个位置时重力感应坐标
    private float x1 = 0;
    private float y1 = 0;
    private float z1 = 0;
    private long time;
    private long interval_time;
    public ShakeListener(Context context) {
    this.context = context;
    }
    public void setListener(OnShakeListener listener) {
    this.listener = listener;
    }
    public void start() {
    // 获取传感服务器
    sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
    // 获取加速传感器
    sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    // 注册传感器,第三个参数:反应速率,根据情况设定
    sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
    }
    public void stop() {
    // 注销传感器
    sensorManager.unregisterListener(this);
    }
    // 加速传感器感应获取数据变化的调用
    @Override
    public void onSensorChanged(SensorEvent event) {
    // 获取当前时间
    long curr = System.currentTimeMillis();
    // 判断时间间隔是否大于10秒
    interval_time = curr - time;
    if (interval_time < 100) {
    return;
    }
    // 当前时间给time
    time = curr;
    // xyz坐标
    float x = event.values[0];
    float y = event.values[1];
    float z = event.values[2];
    // 摇一摇的速度
    double speed = Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1) - (z - z1) * (z - z1)) / interval_time
    * 1000;
    Log.e("阿萨德", "speed:" + speed);
    // 达到速度阀值,发出提示
    if (speed > 200) {
    listener.onShake();
    }
    x1 = x;
    y1 = y;
    z1 = z;

    }
    // 传感器精度改变时调用
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    // TODO Auto-generated method stub
    }
    public interface OnShakeListener {
    void onShake();
    }
    }
    a. 震动
    /**
     * Sensor 传感器、感应器
     */
    public class MainActivity2 extends Activity {
    private ShakeListener shake;
    // 震动器
    private Vibrator vibrator;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // 获取震动的服务
    vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
    shake = new ShakeListener(this);
    shake.setListener(new OnShakeListener() {


    @Override
    public void onShake() {
    /*Vibrator.vibrate()方法:
    只有1个参数的时候,第一个参数用来指定振动的毫秒数。
    要传递2个参数的时候,第1个参数用来指定振动时间的样本,第2个参数用来指定是否需要循环。 
    振动时间的样本是指振动时间和等待时间的交互指定的数组。
    ※下面的例子,在程序起动后等待3秒后,振动1秒,再等待2秒后,振动5秒,再等待3秒后,振动1秒
    long[] pattern = {3000, 1000, 2000, 5000, 3000, 1000}; // OFF/ON/OFF/ON…
      vibrator.vibrate(pattern, -1);*/
    vibrator.vibrate(1000);
    // 异步延时
    new Handler().postDelayed(new Runnable() {


    @Override
    public void run() {
    // 取消震动
    vibrator.cancel();
    }
    }, 1000);
    }
    });
    shake.start();
    }
    @Override
    protected void onDestroy() {
    super.onDestroy();
    shake.stop();
    }
    }


    地图的制作
    1. 百度地图:Android30_BaiMap
    2. 高德地图:Android30_GaoDeMap
    3.
    BroadcastReceiver广播接收器
    1. 广播的两种注册:动态注册广播和静态注册广播(Android31_BroadcastReceive01)
    a. MainActovity中动态注册
    public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //方法一:动态注册广播;方法二:在清单文件中静态注册广播
    /*//动态注册 广播
    IntentFilter filter=new IntentFilter();
    filter.addAction("com.cn.ABC");
    //将 广播接受者 和 广播标识 绑定了
    registerReceiver(new MyReceiver(), filter);*/
    }

    public void tvClick(View v)
    {
    //定义广播Intent  然后将这个intent发出去
    Intent intent =new Intent();
    //setAction里面的参数"com.cn.ABC" 就是广播匹配BroadcastReceiver的标识
    intent.setAction("com.cn.ABC");
    //携带了参数
    intent.putExtra("AABB", "你们问我,软件外包是什么。我解释了几句还没明白,随想了一下,包工头知道吧?顿悟");
    //发送广播
    sendBroadcast(intent);
    }
    }
    a. 清单文件中静态注册:
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.cn.broadcastreceive"
        android:versionCode="1"
        android:versionName="1.0" >
        <uses-sdk
            android:minSdkVersion="8"
            android:targetSdkVersion="23" />
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <!-- 方法二:在清单文件中静态注册广播 -->
             <!--在清单文件中 注册这个组件 并且定义 广播标识  -->
            <receiver android:name = ".MyReceiver">
                <intent-filter>
                    <action android:name="com.cn.ABC" />
                </intent-filter>
            </receiver>
        </application>
    </manifest>
    a. 接收广播
    /**
     * 接收广播
     * @author Administrator
     *
     */
    public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    Toast.makeText(context, "广播的匹配标识action为" + intent.getAction()+ "; 携带的数据:" +
    intent.getStringExtra("AABB"), Toast.LENGTH_LONG).show();
    }
    }
    2. 广播的优先级(Android31_BroadcastReceive02)
    a. MainActivity
    public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    }
    public void tvClick(View v){
    //定义广播Intent  然后将这个intent发出去
    Intent intent=new Intent();
    //setAction里面的参数"com.cn.BROADCAST" 就是广播匹配BroadcastReceiver的标识
    intent.setAction("com.cn.BROADCAST");
    //携带了参数
    intent.putExtra("broadcast", "更快 更强 更好");
    //发送有序广播
    sendOrderedBroadcast(intent,null);
    }
    }
    a. myReceriver01
    /**
     * Bundle类用作携带数据,它类似于Map,用于存放key-value名值对形式的值。相对于Map,它提供了各种常用类型的putXxx()/getXxx()方法,如:putString()/getString()和putInt()/getInt(),putXxx()用于往Bundle对象放入数据,getXxx()方法用于从Bundle对象里获取数据。Bundle的内部实际上是使用了HashMap类型的变量来存放putXxx()方法放入的值
     */
    public class myReceriver01 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    Toast.makeText(context, "广播的匹配标识action为" + intent.getAction()+ "; 携带的数据:" +
    intent.getStringExtra("broadcast"), Toast.LENGTH_LONG).show();
    Bundle bundle=new Bundle();
    bundle.putString("first", "我叫牛破天,我牛气冲天");
    //将bundle放入广播中
    setResultExtras(bundle);
    }
    }
    a. myReceriver02
    public class myReceriver02 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    Bundle bundle=getResultExtras(true);
    String first=bundle.getString("first","妞妞,我还小");

    Toast.makeText(context, "上一个广播接收者 赋的值:" + first, Toast.LENGTH_LONG).show();
    }
    }
    a. 清单文件设置优先级
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.cm.broadcastreceive"
        android:versionCode="1"
        android:versionName="1.0" >
        <uses-sdk
            android:minSdkVersion="12"
            android:targetSdkVersion="23" />
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />


                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <!-- 定义广播接收器 -->
            <receiver android:name="myReceriver01">
                <!-- android:priority设置优先级,设置越大,优先级越高 -->
                <intent-filter android:priority="100">
                    <action android:name="com.cn.BROADCAST" />
                </intent-filter>
            </receiver>
          
             <receiver android:name="myReceriver02">
                <!-- android:priority设置优先级,设置越大,优先级越高 -->
                <intent-filter android:priority="2">
                    <action android:name="com.cn.BROADCAST" />
                </intent-filter>
            </receiver>
        </application>
    </manifest>


    SQLite数据库(Android34_SQLite)
    1. SQLite数据库 只能存储适量的数据 SQLite数据库 就是一个方便操作的可以读写数据的文件
    SQLite数据库 支持哪些操作方式:
    a.支持绝大部分的SQL92语法  和  SQL语句来操作 SQLite数据库
    b.Android系统的SDK在SQL语句的基础上封装了 一些常用API 增删改查....
    1. SQLiteDatabase数据库的操作类
    SQLiteDatabase  openDatabse(path, SQLiteDatabase.CursorFactory,int flag)
    SQLiteDatabase  openOrCreateDatabse(path, SQLiteDatabase.CursorFactory,int flag)   打开或者创建(如果不存在)path所代表的SQLite数据库
    SQLiteDatabase  openOrCreateDatabse(File, SQLiteDatabase.CursorFactory,int flag)  


    String path = getFileDir() + “/mydb.db3” 
    1. SQL语言
    四大类:
    数据查询语言DQL  select<字段名表>子句  from<表>子句  where<查询条件>子句 
    数据操纵语句DML  insert  update   delete
    数据定义语言DDL  create table mytable
    数据控制语言DCL..................................
    使用SQL语句来操作 SQLite数据库,通过 SQLiteDatabase对象的方法execSQL(sql语句)
    execSQL(String sql)---sql 语句 。没有占位符
    execSQL(string sql, Object[] object)  执行带有占位符的sql语句


    insert into 表名 values (值01, 值02...)
    Insert into 表名 (列1,列2...) valsues (值01, 值02...))
    rawQuery(Strint sql,String[] str)  执行带有占位符的sq语句   返回值类型为Cursor对象  JDBC  ResultSet
    Cursor对象  getXxx 得到这行的指定列的数据
    1. 使用Android系统提供的api操作SQLite数据库
    SQLiteDatabase里面的简单操作数据库的方法
    1、使用insert方法插入记录
    SQLiteDatabase的insert方法的签名为long insert(String table,String nullColumnHack,ContentValues values),这个插入方法的参数说明如下:
    table:代表想插入数据的表名。
    nullColumnHack:代表强行插入null值的数据列的列名。
    values:代表一行记录的数据。
    insert方法插入的一行记录使用ContentValues存放,ContentValues类似于Map,它提供了put(String key,Xxx value)(其中key为数据列的列名)方法用于存入数据、getAsXxx(String key)方法用于取出数据。
    例如如下语句:
    ContentValues values=new ContentValues();
    values.put("name","孙悟空"):
    values.put("age",500);
    //返回新添记录的行号,该行号是一个内部直,与主键id无关,发生错误返回-1
    long rowid=db.insert("person_inf",null,values);
    2、使用update方法更新数据
    SQLiteDatabase的update方法签名为update(String table,ContentValues values,String whereClause,String[] whereArgs),这个更新方法的参数说明如下:
    table:代表想要更新数据的表名。
    values:代表想要更新的数据。
    whereClause:满足该whereClause子句的记录将会被更新。
    whereArgs:用于为whereArgs子句传递参数。
    例如我们想要更新person_inf表中所有主键大于20的人的人名,可调用如下方法:
    ContentValues values=new ContentValues();
    //存放更新后的人名
    values.put("name","新人名");
    int result=db.update("person_inf",values,"_id>?",new Integer[]{20});
    3、使用delete方法删除记录
    SQLiteDatabase的delete方法签名为delete(String table,String whereClause,String[] whereArgs),这个删除的参数说明如下:
    table:代表想删除数据的表名。
    whereClause:满足该whereClause子句的记录将会被删除。
    whereArgs:用于为whereArgs子句传入参数。
    删除person_inf表中所有人名以孙开头的记录
    int result=db.delete("person_inf","person_name like ?",new String[]{"孙_"});
    4、使用query方法查询记录
    SQLiteDatabase的query方法签名为Cursor query(boolean distinct,String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy,String limit),这个query方法的参数说明如下。
    distinct:指定是否去除重复记录。
    table:执行查询数据的表名。
    columns:要查询出来的列名。
    selection:查询条件子句。
    selectionArgs:用于为selection子句中占位符传入参数值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
    groupBy:用于控制分组。
    having:用于对分组进行过滤。
    orderBy:用于对记录进行排序。
    limit:用于进行分页。
    例如查询出person_inf表中人名以孙开头的数据
    Cursor cursor=db.query("person_inf",new String[]{"_id,name,age"},"name like ?",new String []{"孙%"},null,null,"personid desc","5,10");
    cursor.close();
    1. 查询数据db.query()和db.rawQuery(sql, selectionArgs)的区别
    Cursor cursor = db.rawQuery("select name from *** where id=?", new String[]{"1"});
    Cursor cursor = db.query("***", new String[]{"name"}, "id=?", new String[]{"1"}, null, null, null);
    上面是两个分别是query和rawQuery的查询语句,主要区别是rawQuery是直接使用SQL语句进行查询的,也就是第一个参数字符串,在字符串内的“?”会被后面的String[]数组逐一对换掉;而query函数是Android自己封装的查询API.
    而后者query对比前者来讲就有一个好处,前者rawQuery你在写入SQL语句的时候,有可能写错了或者写漏了什么单词拼写错误的时候他会出错,而后者相对来讲出错的机率就比较小
    1. 创建表和添加数据
    public class MainActivity extends Activity {
    // 声明数据库对象
    SQLiteDatabase db;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // 在路径getFilesDir()+"/mydb.db"
    String path = this.getFilesDir() + "/mydb.db";
    //创建数据库
    db = SQLiteDatabase.openOrCreateDatabase(path, null);


    // user_info表存在就删除该表
    db.execSQL("DROP TABLE IF EXISTS user_info");


    // 定义建表的Sql语句,没有占位符
    String sql = "create table user_info(user_id integer primary key,"
    + "user_name varchar(255),user_pass varchar(255))";
    // 数据库最小执行SQL语句
    db.execSQL(sql);


    /*// 向表中插入数据
    String sql_insert = "insert into user_info(user_id,user_name,user_pass)"
    + " values(null,'haha','123456')";
    // 数据库对象执行SQL插入语句
    db.execSQL(sql_insert);*/

    String name="haha";
    String pass="12345";
    //带占位符的sql语句
    String sqlz="insert into user_info values(null,?,?)";
    //执行语句
    db.execSQL(sqlz, new String[]{name,pass});


    }
    }
    1. 创建数据库、插入数据和展现数据
    public class MainActivity2 extends Activity implements OnClickListener {


    // 声明数据库对象
    SQLiteDatabase db;
    Button bn ;
    ListView listView;
    EditText name,pass;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);

    listView = (ListView)findViewById(R.id.showsql);
    bn = (Button)findViewById(R.id.btn);
    bn.setOnClickListener(this);
    name = (EditText)findViewById(R.id.name);
    pass = (EditText)findViewById(R.id.pass);


    //创建或打开数据库
    db = SQLiteDatabase.openOrCreateDatabase(this.getFilesDir().getPath() + "/mydb.db3", null);
    }


    @Override
    public void onClick(View v) {
    switch (v.getId()) {
    case R.id.btn:
    String et_name = name.getText().toString();//若不输入内容  得到是长度为0的空字符串
    String et_pass = pass.getText().toString();
    try {
    /*创建数据表不应该放在这,当第二次插入数据是会报错,说创建了表
    * // 执行DDL语句创建数据表 的 表结构
    db.execSQL("create table users_info(user_id integer primary key autoincrement,"
    + "user_name varchar(50),user_pass varchar(255))");*/
    // 执行insert语句 插入数据;使用带 占位符的 sql语句
    db.execSQL("insert into users_info values(null,?,?)", new String[] { et_name, et_pass });
    // 执行 查询
    Cursor cursor=db.rawQuery("select * from users_info", null);
    // 通过listView展现数据库中的数据
    initListView(cursor);
    } catch (Exception e) {
    // 执行DDL语句创建数据表 的 表结构
    db.execSQL("create table users_info(_id integer primary key autoincrement,"
    + "user_name varchar(50),user_pass varchar(255))");
    // 执行insert语句 插入数据;使用带 占位符的 sql语句
    db.execSQL("insert into users_info values(null,?,?)", new String[] { et_name, et_pass });

    // 执行 查询
    Cursor cursor = db.rawQuery("select * from users_info", null);
    // 通过listView展现数据库中的数据
    initListView(cursor);
    }
    break;
    }
    }
    // 通过listView展现数据库中的数据
    private void initListView(Cursor cursor) {
    // SDK中已经提供了专门适用于cursor数据形式的适配器了SimpleCursorAdapter
    //SimpleCursorAdapter(context, layout, c, from, to, flags) flags在这里是用来标识当数据发生改变调用onContentChanged()的时候是否通知ContentProvider数据改变。对应有两个常数:CursorAdapter.FLAG_AUTO_REQUERY和CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER。
    //前者在api11后不推荐使用,就不在叙述。后者的作用是在 Cursor 上注册一个内容监测器,并在其发出通知时调用 onContentChanged() 方法。如果无需监听ContentProvider的改变,或者,在CursorAdapter中使用了CursorLoader(他会为你注册一个内容监测器),则可以传0。
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item_layout, cursor,
    new String[] { "user_name", "user_pass" }, new int[] { R.id.tv_name, R.id.tv_pass },
    CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
    listView.setAdapter(adapter);
    }


    @Override
    protected void onDestroy() {
    super.onDestroy();
    // 退出程序的时候 应该关闭物理资源 SQLiteDatabase
    if (db != null && db.isOpen()) {
    db.close();
    }
    }
    }


    Cursor游标(光标):遍历读取数据库中的数据
    1. Cursor知识点
    使用过 SQLite数据库的童鞋对 Cursor 应该不陌生,加深自己和大家对Android 中使用 Cursor 的理解。
    关于 Cursor
    在你理解和使用 Android Cursor 的时候你必须先知道关于 Cursor 的几件事情:
    Cursor 是每行的集合。使用 moveToFirst() 定位第一行。你必须知道每一列的名称。你必须知道每一列的数据类型。Cursor 是一个随机的数据源。所有的数据都是通过下标取得。
    关于 Cursor 的重要方法:
    ·close()——关闭游标,释放资源
    ·copyStringToBuffer(int columnIndex, CharArrayBuffer buffer)——在缓冲区中检索请求的列的文本,将将其存储
    ·getColumnCount()——返回所有列的总数
    ·getColumnIndex(String columnName)——返回指定列的名称,如果不存在返回-1
    ·getColumnIndexOrThrow(String columnName)——从零开始返回指定列名称,如果不存在将抛出IllegalArgumentException 异常。
    ·getColumnName(int columnIndex)——从给定的索引返回列名
    ·getColumnNames()——返回一个字符串数组的列名
    ·getCount()——返回Cursor 中的行数
    ·moveToFirst()——移动光标到第一行
    ·moveToLast()——移动光标到最后一行
    ·moveToNext()——移动光标到下一行
    ·moveToPosition(int position)——移动光标到一个绝对的位置
    ·moveToPrevious()——移动光标到上一行
    下面来看看一小段代码: 
    if (cur.moveToFirst() == false){ //为空的Cursor
         return;
    }
     
    访问 Cursor 的下标获得其中的数据
    int nameColumnIndex = cur.getColumnIndex(People.NAME);
    String name = cur.getString(nameColumnIndex);
    现在让我们看看如何循环 Cursor 取出我们需要的数据
    while(cur.moveToNext()) {
        //光标移动成功
       String email = cursor.getString(cursor.getColumnIndex(RuiXin.EMAIL));
       startManagingCursor(cursor);  //查找后关闭游标 
       //把数据取出
    }


    当cur.moveToNext() 为假时将跳出循环,即 Cursor 数据循环完毕。
    如果你喜欢用 for 循环而不想用While 循环可以使用Google 提供的几下方法:
    ·isBeforeFirst()——返回游标是否指向之前第一行的位置
    ·isAfterLast()——返回游标是否指向第最后一行的位置
    ·isClosed()——如果返回 true 即表示该游戏标己关闭
    有了以上的方法,可以如此取出数据
    for(cur.moveToFirst();!cur.isAfterLast();cur.moveToNext())
    {
        int nameColumn = cur.getColumnIndex(People.NAME);
        int phoneColumn = cur.getColumnIndex(People.NUMBER);
        String name = cur.getString(nameColumn);
        String phoneNumber = cur.getString(phoneColumn);
    }
    Tip:在Android 查询数据是通过Cursor 类来实现的。当我们使用 SQLiteDatabase.query()方法时,就会得到Cursor对象, Cursor所指向的就是每一条数据。
    Cursor 位于 android.database.Cursor类,可见出它的设计是基于数据库服务产生的。
    以上转自:http://www.2cto.com/kf/201109/103163.html
     
    另:Activity.startManagingCursor方法:
    将获得的Cursor对象交与Activity管理,这样Cursor对象的生命周期便能与当前的Activity自动同步,省去了自己对Cursor的管理。
    1.这个方法使用的前提是:游标结果集里有很多的数据记录。
    所以,在使用之前,先对Cursor是否为null进行判断,如果Cursor != null,再使用此方法
    2.如果使用这个方法,最后也要用stopManagingCursor()来把它停止掉,以免出现错误。
    3.使用这个方法的目的是把获取的Cursor对象交给Activity管理,这样Cursor的生命周期便能和Activity自动同步,省去自己手动管理。


    1. 代码:
    // 执行 查询
    Cursor cursor = db.rawQuery("select * from users_info", null);
    // 通过listView展现数据库中的数据
    initListView(cursor);
    // 通过listView展现数据库中的数据
    private void initListView(Cursor cursor) {
    // SDK中已经提供了专门适用于cursor数据形式的适配器了SimpleCursorAdapter
    //SimpleCursorAdapter(context, layout, c, from, to, flags) flags在这里是用来标识当数据发生改变调用onContentChanged()的时候是否通知ContentProvider数据改变。对应有两个常数:CursorAdapter.FLAG_AUTO_REQUERY和CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER。前者在api11后不推荐使用,就不在叙述。后者的作用是在 Cursor 上注册一个内容监测器,并在其发出通知时调用 onContentChanged() 方法。
    如果无需监听ContentProvider的改变,或者,在CursorAdapter中使用了CursorLoader(他会为你注册一个内容监测器),则可以传0。
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item_layout, cursor,
    new String[] { "user_name", "user_pass" }, new int[] { R.id.tv_name, R.id.tv_pass },
    CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
    listView.setAdapter(adapter);
    }
    @Override
    protected void onDestroy() {
    super.onDestroy();
    // 退出程序的时候 应该关闭物理资源 SQLiteDatabase
    if (db != null && db.isOpen()) {
    db.close();
    Cursor.close();
    }
    }
    1. 数据库增删查改操作(Android33_Banggo\src\com\dawn\banggo\config\sql)
    /**
     * 数据库增删查改操作
     */
    public class SQLHolder {
    /**
    * 添加数据
    */
    public void addCard(Context context,ProductBean bean)
    {
    SQLHelp db=new SQLHelp(context);
    //数据库操作类,获取数据库写的权限
    SQLiteDatabase sDatabase=db.getWritableDatabase();
    //获取游标,读数据库
    Cursor cursor=sDatabase.query("card", new String[]{"productId", "count"}, null, null, null,null,null);
    //判断是否存在准备添加的productId
    boolean isExist=false;
    //添加到购物车的数量
    int count=0;
    try {
    while (cursor.moveToNext()) {
    //cursor.getInt(0):查询条件是int,查的值是productId
    //cursor.getInt(1):查询条件是int,查的值是count
    if (bean.getProductId()==cursor.getInt(0)) {
    isExist=true;
    count=cursor.getInt(1);
    count++;
    }
    }
    } catch (Exception e) {}

    if (isExist) {
    //更新数据库
    upDateCard(context,bean.getProductId(),count);
    }else {
    //添加操作
    //ContentValues类和Hashtable比较类似,它也是负责存储一些名值对,但是它存储的名值对当中的名是一个String类型,而值都是基本类型。
    //ContentValues 和HashTable类似都是一种存储的机制 但是两者最大的区别就在于,contenvalues Key只能是String类型,values
    //只能存储基本类型的数据,像string,int之类的,不能存储对象,而HashTable却可以存储对象。ContentValues 常用在数据库中的操作。
    ContentValues values=new ContentValues();
    //添加列的参数
    values.put("productId", bean.getProductId());
    values.put("productImage", bean.getProductImage());
    values.put("productName", bean.getProductName());
    values.put("productPrice1", bean.getProductPrice1());
    values.put("productPrice2", bean.getProductPrice2());
    values.put("count", 1);
    //插入数据库
    sDatabase.insert("card", null, values);
    }
    //关闭cursor和数据库
    cursor.close();
    sDatabase.close();

    }
    /**
    * 更新数据库
    */
    public void upDateCard(Context context,int productId, int count)
    {
    SQLHelp db=new SQLHelp(context);
    //获取数据库写的权限
    SQLiteDatabase sDatabase=db.getWritableDatabase();
    //添加操作
    ContentValues values=new ContentValues();
    //添加列的参数
    values.put("count", count);
    //更新数据库
    sDatabase.update("card", values, "productId="+productId, null);

    sDatabase.close();
    }

    /**
    * 删除
    */
    public void deleteCard(Context context,int productId)
    {
    SQLHelp db = new SQLHelp(context);
    //获取数据库写的权限
    SQLiteDatabase sDatabase = db.getWritableDatabase();
    sDatabase.delete("card", "productId=" + productId, null);
    sDatabase.close();
    }

    /**
    * 查询数据库
    */
    public List<ProductBean> getCards(Context context){
    SQLHelp db = new SQLHelp(context);
    //获取数据库写的权限
    SQLiteDatabase sDatabase = db.getWritableDatabase();
    //读数据库
    Cursor cursor=sDatabase.query("card", new String[]{"productId", "productImage","productName",
    "productPrice1","productPrice2","count"}, null, null, null, null, null);
    List<ProductBean> list=new ArrayList<ProductBean>();
    try {
    while(cursor.moveToNext())
    {
    ProductBean bean=new ProductBean();
    bean.setProductId(cursor.getInt(0));
    bean.setProductImage(cursor.getString(1));
    bean.setProductName(cursor.getString(2));
    bean.setProductPrice1(cursor.getFloat(3));
    bean.setProductPrice2(cursor.getFloat(4));
    bean.setCount(cursor.getInt(5));
    list.add(bean);
    }
    } catch (Exception e) {}
    cursor.close();
    sDatabase.close();

    return list;
    }
    }
    1. As
    2.
    Android三种基本的加载网络图片方式(Android36_ThreeLoadPic)
    Android三种基本的加载网络图片方式,包括普通加载网络方式、用ImageLoader加载图片、用Volley加载图片。
    1. [代码]普通加载网络方式     
    public class NormalLoadPictrue {
         
        private String uri;
        private ImageView imageView;
        private byte[] picByte;
         
        public void getPicture(String uri,ImageView imageView){
            this.uri = uri;
            this.imageView = imageView;
            new Thread(runnable).start();
        }
         
        @SuppressLint("HandlerLeak")
        Handler handle = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == 1) {
                    if (picByte != null) {
                        Bitmap bitmap = BitmapFactory.decodeByteArray(picByte, 0, picByte.length);
                        imageView.setImageBitmap(bitmap);
                    }
                }
            }
        };
     
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(uri);
                    HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setReadTimeout(10000);
                     
                    if (conn.getResponseCode() == 200) {
                        InputStream fis =  conn.getInputStream();
                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
                        byte[] bytes = new byte[1024];
                        int length = -1;
                        while ((length = fis.read(bytes)) != -1) {
                            bos.write(bytes, 0, length);
                        }
                        picByte = bos.toByteArray();
                        bos.close();
                        fis.close();
                         
                        Message message = new Message();
                        message.what = 1;
                        handle.sendMessage(message);
                    }
                     
                     
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
         
    }

    2. [代码]用ImageLoader加载图片     

    public class ImageLoaderPicture {

        private DisplayImageOptions options;
         public ImageLoaderPicture(Context context) {
             ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
                    .threadPriority(Thread.NORM_PRIORITY - 2)
            .denyCacheImageMultipleSizesInMemory()
            .discCacheFileNameGenerator(new Md5FileNameGenerator())
            .tasksProcessingOrder(QueueProcessingType.LIFO).enableLogging() 
            .memoryCache(new WeakMemoryCache())                                 
            .build();
            ImageLoader.getInstance().init(config);
             
            options = new DisplayImageOptions.Builder()
            .showStubImage(0)
            .showImageForEmptyUri(0)
            .showImageOnFail(0)
            .cacheInMemory().cacheOnDisc()
            .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
            .bitmapConfig(android.graphics.Bitmap.Config.RGB_565)
            .build();
        }
     
        public DisplayImageOptions getOptions() {
            return options;
        }
     
        public void setOptions(DisplayImageOptions options) {
            this.options = options;
        }
         
    }

    3. [代码]用Volley加载图片

    public class VolleyLoadPicture {

        private ImageLoader mImageLoader = null;
        private BitmapCache mBitmapCache;
         
        private ImageListener one_listener;
         
        public VolleyLoadPicture(Context context,ImageView imageView){
            one_listener = ImageLoader.getImageListener(imageView, 0, 0);
             
            RequestQueue mRequestQueue = Volley.newRequestQueue(context);
            mBitmapCache = new BitmapCache();
            mImageLoader = new ImageLoader(mRequestQueue, mBitmapCache);
        }
     
        public ImageLoader getmImageLoader() {
            return mImageLoader;
        }
     
        public void setmImageLoader(ImageLoader mImageLoader) {
            this.mImageLoader = mImageLoader;
        }
     
        public ImageListener getOne_listener() {
            return one_listener;
        }
     
        public void setOne_listener(ImageListener one_listener) {
            this.one_listener = one_listener;
        }
         
        class BitmapCache implements ImageCache {
            private LruCache<String, Bitmap> mCache;
            private int sizeValue;
             
            public BitmapCache() {
                int maxSize = 10 * 1024 * 1024;
                mCache = new LruCache<String, Bitmap>(maxSize) {
                    @Override
                    protected int sizeOf(String key, Bitmap value) {
                        sizeValue = value.getRowBytes() * value.getHeight();
                        return sizeValue;
                    }
                     
                };
            }
     
            @Override
            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }
     
            @Override
            public void putBitmap(String url, Bitmap bitmap) {
                mCache.put(url, bitmap);
            }
        }
         
     
    }

    4. [代码]Activity     

    public class MainActivity extends Activity {

        private ImageView imageView001,imageView002,imageView003;
         
       public static final String picUrl = "http://img.quwenjiemi.com/2014/0701/thumb_420_234_20140701112917406.jpg";
        //public static final String picUrl = "http://192.168.1.181:8081/AndroidSerivces/house.jpg";
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            imageView001 = (ImageView)findViewById(R.id.imageView001);
            imageView002 = (ImageView)findViewById(R.id.imageView002);
            imageView003 = (ImageView)findViewById(R.id.imageView003);
             
            //用普通方法加载图片
            new NormalLoadPictrue().getPicture(picUrl,imageView001);
             
            //用ImageLoader加载图片
            ImageLoader.getInstance().displayImage(picUrl, imageView002,new ImageLoaderPicture(this).getOptions(),new SimpleImageLoadingListener());
             
            //用Volley加载图片
            VolleyLoadPicture vlp = new VolleyLoadPicture(this, imageView003);
            vlp.getmImageLoader().get(picUrl, vlp.getOne_listener());
        } 
     }
    5. [代码]布局文件     
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity" >
     
        <RelativeLayout 
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="10dp">
         
        <TextView 
            android:id="@+id/textView001"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="1.用普通方法的加载图片"/>
         
        <ImageView 
            android:id="@+id/imageView001"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/textView001"/>
         
        <TextView 
            android:id="@+id/textView002"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/imageView001"
             android:text="2.用Android-Universal-Image-Loader加载图片"/>
         
        <ImageView 
            android:id="@+id/imageView002"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
             android:layout_below="@+id/textView002"/>
         
        <TextView 
            android:id="@+id/textView003"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/imageView002"
            android:text="3.用Volley加载图片"/>
         
        <ImageView 
            android:id="@+id/imageView003"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/textView003"/>
         
        </RelativeLayout>
     
    </ScrollView>




    支付宝申请流程(Android_ZhiFuBao)
    1. 申请流程:
    注册支付宝账号??进行实名认证??提交审核资料??审核通过
    备注:申请通过后会获得:合作者身份 ID(PID),该 ID 在项目配置中需要用到
    开发流程:
    第一步:
    下载 API 开发文档后,即可获取官方 Demo,该 Demo 中需要将审核通过后获取的 PID 替换,并且输入支付宝收
    款账户即可。这里非常简单,就不过多叙述。
    第二步:
    官方 Api 开发文档中,存在一个 openssl 的文件夹,该文件夹主要是用于生成支付宝所需要用到的公钥以及私钥。
    打开该文件夹可以看到详细的生成方式,根据提示生成公钥及私钥,请注意,密钥需要经过 pkcs8 二次加密。
    第三步:
    将生成的公钥和私钥配置到 Demo 中。
    1. 在项目中配置公钥和私钥
    // 商户PID
    public static final String PARTNER = "";
    // 商户收款账号
    public static final String SELLER = "";
    // 商户私钥,pkcs8格式
    public static final String RSA_PRIVATE = "";
    // 支付宝公钥
    public static final String RSA_PUBLIC = "";
    private static final int SDK_PAY_FLAG = 1;
    1. As
    第三方登录和分享(MyShareThings01)
    1. 流程
    下面的是具体流程:
    1、你们需要支持用户注册
    2、你们需要在应用登录的时候提供第三方平台的图标
    3、用户点击第三方平台图标以后,你们尝试判断用户是否已经授权
    4、如果用户授权,获取他的唯一识别符,比方说WeiboDb里面的weiboId这个字段
    5、如果用户没有授权,引导用户授权,授权成功后也可以获取weibo  Id
    6、然后用这个唯一识别符登录你们的系统,如果用户已经注册,则应该让用户登录到你们的系统,流程结束
    7、如果你们的系统发现用户没有注册,引导用户进入你们应用的注册页面,并通过share sdk的showuser方法获取用户资料,自动帮助用户完成注册资料的填写,然后等待用户确认
    8、如果用户确认了注册信息,你们的应用就根据他的信息完成这注册操作,如果操作成功,则应该让用户登录到你们的系统,流程结束
    1. 在Android中 实现分享功能通常有四种方式:
    方式一:使用Android自带的分享功能,通过Intent找出手机中所有的社交app
    这种方式的优点就是实现比较简单,不需要引入第三方sdk,缺点就是需要安装社交app之后才能分享,其实我觉得这个也是合理的,试想如果一个人的手机中没有安装新浪微博,那么意味着他肯定不玩微博,所以不能分享也无所谓
    //分享文本
    Intent sendIntent = new Intent();
    sendIntent.setAction(Intent.ACTION_SEND);
    sendIntent.putExtra(Intent.EXTRA_TEXT, 我用手机测试分享内容);
    sendIntent.setType(text/plain);
    startActivity(Intent.createChooser(sendIntent, 我是弹出框的标题));

    弹出界面如下:


    不同人手机这个节目肯定是不一样的,因为有些人喜欢玩微博,只装了微博,没有微信。如果一个人不玩社交app,那么这个Dialog里面至少有一个是短信和蓝牙之类的,因为这些每个手机都有。 
    方式二:使用ShareSDK实现,ShareSDK是一款功能非常强大的第三方提供的专门用于分享等功能的sdk,使用也很简单,但是需要引入一些sdk,这里我就不举例了,研究一些ShareSDK提供的demo就可以实现,优点是简单,功能强大,并且不需要安装社交app
    方式三:使用社交开放平台提供的sdk,有点事简单,但是需要安装社交app
    方式四:使用社交平台提供的api接口,通过调用这些api接口实现分享和登陆,使用这种不需要安装社交app。(http://www.2cto.com/kf/201408/328127.html)


    1. 登录和分享(http://www.apkbus.com/android-125666-1-1.html):另存在登录和分享word文档中
    2. a
    3.
    简单实现ListView顶部悬浮效果(sticky)
    1. 代码:
    public class StickListView extends Activity {
    private ListView lv;
    private LinearLayout invis;
    private String[] strs;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_sticky);
    invis = (LinearLayout) findViewById(R.id.invis);


    strs = new String[100];


    for (int i = 0; i <100; i++) {
    strs[i] = "data-----" + i;
    }
    lv = (ListView) findViewById(R.id.lv);
    View header = View.inflate(this, R.layout.stick_header, null);//头部内容
    lv.addHeaderView(header);//添加头部
    lv.addHeaderView(View.inflate(this, R.layout.stick_action, null));//ListView条目中的悬浮部分 添加到头部
    lv.setAdapter(new ArrayAdapter<String>(this,
    android.R.layout.simple_list_item_1, strs));
    lv.setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
    if (firstVisibleItem >= 1) {
    invis.setVisibility(View.VISIBLE);
    } else {
    invis.setVisibility(View.GONE);
    }
    }
    });
    }
    }
    1. 展示
     


    WebService获取天气预报(WebServiceDemo)
    1. 什么是WebService
    简单的理解:通常我们所说的WebService都是远程的某个服务器对外公开了某种服务,或者理解为对外公开了某个功能或者方法,而我们可以通过编程来调用该服务以获得我们需要的信息。例如:www.webxml.com.cn对外公开了手机号码归属地查询服务,我们只需要在调用该服务时传入一个手机号段(号码),就能立即获取该号段的归属地信息。
    更通俗的理解:通过使用WebService,我们能够像调用本地方法一样去调用远程服务器上的方法。我们并不需要关心远程的那个方法是Java写的,还是PHP或C#写的;我们并不需要关心远程的方法是基于Unix平台,还是Windows平台,也就是说WebService与平台和语言无关。
          
    说到WebSerivce,就必须要知道SOAP和WSDL,它们到底和WebSerice有着怎么的关系?上面已经提到,Web Services是建立在HTTP、SOAP、WSDL等通用协议的基础之上。

    1. 第三页的天气显示不出来,可能是接口问题


    自定义listView控件左滑删除Item(CustomListView-DeleteItem)
    1. MyListView
    /**
     * 自定义listView,删除Item
     */
    public class MyListView extends ListView {
    private LayoutInflater inflater;
    /**
    * 手指按下的x,y坐标,以及移动以后的x,y坐标
    */
    private int xDown;
    private int yDown;
    private int xMove;
    private int yMove;
    private boolean isRightSliding;
    private boolean isLeftSliding;
    // 滑动的最小距离
    private int touchSlop;
    // PopWindow弹窗
    private PopupWindow popupWindow;
    private int popWindowWidth;
    private int popWindowHeight;
    private Button delButton;
    private int mCurrentViewPosition;
    private View mCurrentView;
    // 回调接口
    private DeleteItemListener deleteItemListener;


    /**
    * 初始化操作
    */
    public MyListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    inflater = LayoutInflater.from(context);
    touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    View view = inflater.inflate(R.layout.delete_item, null);
    delButton = (Button) view.findViewById(R.id.id_item_btn);
    popupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT,
    LinearLayout.LayoutParams.WRAP_CONTENT);
    popupWindow.getContentView().measure(0, 0);
    popWindowWidth = popupWindow.getContentView().getMeasuredWidth();
    popWindowHeight = popupWindow.getContentView().getMeasuredHeight();
    }


    //dispatchTouchEvent是处理触摸事件分发,事件(多数情况)是从Activity的dispatchTouchEvent开始的。执行
    //super.dispatchTouchEvent(ev),事件向下分发。
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
    int action = event.getAction();
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (action) {
    case MotionEvent.ACTION_DOWN:
    xDown = x;
    yDown = y;
    if (popupWindow.isShowing()) {
    dismissPopWindow();
    }
    mCurrentViewPosition = pointToPosition(xDown, yDown);
    View view = getChildAt(mCurrentViewPosition - getFirstVisiblePosition());
    mCurrentView = view;
    break;
    case MotionEvent.ACTION_MOVE:
    xMove = x;
    yMove = y;
    int offsetX = xDown - xMove;
    int offsetY = yDown - yMove;
    if (xMove < xDown && Math.abs(offsetX) > touchSlop && Math.abs(offsetY) < touchSlop) {
    isLeftSliding = true;
    } else if (xMove > xDown && Math.abs(offsetX) > touchSlop && Math.abs(offsetY) < touchSlop) {
    isRightSliding = true;
    }
    break;
    }
    return super.dispatchTouchEvent(event);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {


    int action = event.getAction();
    if (isLeftSliding) {
    switch (action) {
    case MotionEvent.ACTION_DOWN:
    break;
    case MotionEvent.ACTION_MOVE:
    int location[] = new int[2];
    mCurrentView.getLocationOnScreen(location);
    popupWindow.setAnimationStyle(R.style.popwindow_delete_btn_anim_style); // 设置弹窗的动画效果
    popupWindow.update();
    popupWindow.showAtLocation(mCurrentView, Gravity.LEFT | Gravity.TOP,
    location[0] + mCurrentView.getWidth(),
    location[1] + mCurrentView.getHeight() / 2 - popWindowHeight / 2);
    delButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    if (deleteItemListener != null) {
    deleteItemListener.DeleteItem(mCurrentViewPosition);
    popupWindow.dismiss();
    }
    }
    });
    break;
    case MotionEvent.ACTION_UP:
    isLeftSliding = false;
    break;
    }
    // 防止与Item点击事件冲突
    return true;
    } else if (isRightSliding) {
    switch (action) {
    case MotionEvent.ACTION_DOWN:
    break;
    case MotionEvent.ACTION_MOVE:
    if (popupWindow.isShowing()) {
    dismissPopWindow();
    }
    break;
    case MotionEvent.ACTION_UP:
    isRightSliding = false;
    break;
    }
    return true;
    }
    return super.onTouchEvent(event);
    }


    public void setDeleteItemListener(DeleteItemListener listener) {
    deleteItemListener = listener;
    }


    // 回调接口
    public interface DeleteItemListener {
    void DeleteItem(int position);
    }


    private void dismissPopWindow() {
    if (popupWindow != null && popupWindow.isShowing()) {
    popupWindow.dismiss();
    }
    }

    }


    展开全文
  • Android 基础知识(一)体系架构

    千次阅读 2018-08-23 19:25:43
    初学Android不久,总结一下杂七杂八的东西,难免说错或者说的不清楚有歧义,希望路过的大佬、中佬、小佬以及和我一样的小白能多多提点。 体系架构(略有了解即可) 这是两张网络上的有关Android体系架构的...

    初学Android不久,总结一下杂七杂八的东西,难免说错或者说的不清楚有歧义,希望路过的大佬、中佬、小佬以及和我一样的小白能多多提点。

    体系架构(略有了解即可)

    旧版
    新版
    这是两张网络上的有关Android体系架构的图片,上面那张看起来就很老的图片是2014年以前的一个架构显示,下面那个看起来就很棒棒的图片是我从一个博客(Android系统架构与系统源码目录)里面找到的,以下有关体系架构的部分内容也摘自其中。

    这两张图片的大部分内容都是一致的,变得最大的就是Android Runtime这个部分。2014那一年的谷歌IO大会发生了很多事情,比如说发布了UI设计上的Material Design风格,比如说可穿戴设备Android Wear,还有就是对运行时虚拟机的更改。Dalvik是KitKat(Android 4.4)之前的虚拟机,因为最开始的时候手机设备比较辣鸡,啥特么都不行,电池不行、内存不行、处理器不行,Dalvik就是为此设计的。而在2014年谷歌IO大会上“悄悄地”( • ̀ω•́ )✧改了虚拟机,新虚拟机叫ART虚拟机。

    ART模式的原理,是在用户安装应用时就进行预编译操作,将原本在程序运行中的编译动作提前到应用安装时,所以无疑会加快程序在运行中的响应速度。与几乎所有的提升速度所带来的代价差不多,空间开销大了,不过后来的手机无论从哪个方面都完爆之前的手机(单说内存就是几十倍的差距),于是乎为了获得之前两倍的速度(两倍是官方给出的说法)….Dalvik扑街了….在Android 4.4里将ART设置为开发者选项,在Android 5.0里面ART成为默认,Dalvik退出历史舞台。下面就是分层讲述每个层都干嘛的,请将重点放在应用框架层和系统运行库层,其他几层不是不重要…而是现在看了也白搭,说的扎心点就是你刚开始根本看不懂。


    应用层

    系统内置的应用程序以及非系统级的应用程序都是属于应用层。负责与用户进行直接交互,通常都是用Java进行开发的。

    应用框架层(Java Framework)

    应用框架层为开发人员提供了可以开发应用程序所需要的API,我们平常开发应用程序都是调用的这一层所提供的API,当然也包括系统的应用。这一层的是由Java代码编写的,可以称为Java Framework。下面来看这一层所提供的主要的组件

    • Activity Manager(活动管理器) 管理各个应用程序生命周期以及通常的导航回退功能
    • Location Manager(位置管理器) 提供地理位置以及定位功能服务
    • Package Manager(包管理器) 管理所有安装在Android系统中的应用程序
    • Notification Manager(通知管理器) 使得应用程序可以在状态栏中显示自定义的提示信息
    • Resource Manager(资源管理器) 提供应用程序使用的各种非代码资源,如本地化字符串、图片、布局文件、颜色文件等
    • Telephony Manager(电话管理器) 管理所有的移动设备功能
    • Window Manager(窗口管理器) 管理所有开启的窗口程序
    • Content Providers(内容提供器) 使得不同应用程序之间可以共享数据
    • View System(视图系统) 构建应用程序的基本组件

    系统运行库层(Native)

    系统运行库层分为两部分,分别是C/C++程序库和Android运行时库。下面分别来介绍它们。

    1.C/C++程序库

    C/C++程序库能被Android系统中的不同组件所使用,并通过应用程序框架为开发者提供服务,主要的C/C++程序库如下:

    • OpenGL ES 3D绘图函数库
    • Libc 从BSD继承来的标准C系统函数库,专门为基于嵌入式Linux的设备定制
    • Media Framework 多媒体库,支持多种常用的音频、视频格式录制和回放。
    • SQLite 轻型的关系型数据库引擎
    • SGL 底层的2D图形渲染引擎
    • SSL 安全套接层,是为网络通信提供安全及数据完整性的一种安全协议
    • FreeType 可移植的字体引擎,它提供统一的接口来访问多种字体格式文件

    2.Android运行时库

    运行时库又分为核心库和ART(5.0系统之后,Dalvik虚拟机被ART取代)。核心库提供了Java语言核心库的大多数功能,这样开发者可以使用Java语言来编写Android应用。相较于JVM,Dalvik虚拟机是专门为移动设备定制的,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。而替代Dalvik虚拟机的ART 的机制与Dalvik 不同。在Dalvik下,应用每次运行的时候,字节码都需要通过即时编译器转换为机器码,这会拖慢应用的运行效率,而在ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。

    硬件抽象层(HAL)

    硬件抽象层是位于操作系统内核与硬件电路之间的接口层,其目的在于将硬件抽象化,为了保护硬件厂商的知识产权,它隐藏了特定平台的硬件接口细节,为操作系统提供虚拟硬件平台,使其具有硬件无关性,可在多种平台上进行移植。 从软硬件测试的角度来看,软硬件的测试工作都可分别基于硬件抽象层来完成,使得软硬件测试工作的并行进行成为可能。通俗来讲,就是将控制硬件的动作放在硬件抽象层中。

    Linux内核层

    Android 的核心系统服务基于Linux 内核,在此基础上添加了部分Android专用的驱动。系统的安全性、内存管理、进程管理、网络协议栈和驱动模型等都依赖于该内核。

    展开全文
  • 最新Android基础入门教程目录(完结版)

    万次阅读 多人点赞 2018-03-29 19:17:14
    第一章:环境搭建与开发相关(已完结 10/10)https://blog.csdn.net/coder_pig/article/details/50000773Android基础入门教程——1.1 背景相关与系统架构分析Android基础入门教程——1.2 开发环境搭建Android基础入门...


    第一章:环境搭建与开发相关(已完结 10/10)

    https://blog.csdn.net/coder_pig/article/details/50000773



    第二章:Android UI(User Interface)详解(已完结 40/40)


    六大布局

    常用基本UI控件

    Adapter类的控件

    信息提示类控件

    菜单相关


    第三章:事件处理机制(已完结 8/8)



    第四章:Android四大组件与Intent(已完结 12/12)


    Activity(活动)

    Service(服务)

    BroadcastReceiver(广播接受者)

    ContentProvider(内容提供者)

    Intent(意图)


    第五章:Fragment(碎片)(已完结 6/6)



    第六章:Android数据存储(已完结 4/4)


    Android基础入门教程——6.1 数据存储与访问之——文件存储读写 
    Android基础入门教程——6.2 数据存储与访问之——SharedPreferences保存用户偏好参数 
    Android基础入门教程——6.3.1 数据存储与访问之——初见SQLite数据库 
    Android基础入门教程——6.3.2 数据存储与访问之——又见SQLite数据库


    第七章:Android网络编程(已完结 20/20)


    Http协议相关

    XML与Json解析

    文件上传与下载

    WebService调用

    WebView浏览器编程

    Socket网络编程


    第八章:Android绘图与动画(已完结 27/27)


    Drawable

    Bitmap与BitmapFactory

    绘图API:Paint,Canvas,Path

    动画:帧动画,补间动画,属性动画


    第九章:Android多媒体API调用(已完结 4/4)



    第十章:系统服务以及一些小玩意(已完结 14/14)


    https://blog.csdn.net/coder_pig/article/details/50000773https://blog.csdn.net/coder_pig/article/details/50000773
    展开全文
  • Android应用开发进阶与实践

    千人学习 2019-12-02 09:35:56
    本课程是Android应用开发的进阶篇,以实践为主,学习本课程要求学习者首先掌握Java基础,Android开发基础,此课程在此基础上进一步探索,此课程不适合没有Java和Android基础的人员。
  • Android一词最早是出现在法国作家维里耶德利尔·亚当1986年发表的《未来夏娃》这部科幻小说中,作者利尔·亚当将外表像人类的机器起名为Android,这就是Android小人名字的由来。Android的Logo是由伊琳娜-布洛克设计...

    在这里插入图片描述
    什么是Android

    Android一词最早是出现在法国作家维里耶德利尔·亚当1986年发表的《未来夏娃》这部科幻小说中,作者利尔·亚当将外表像人类的机器起名为Android,这就是Android小人名字的由来。Android的Logo是由伊琳娜-布洛克设计的,设计灵感来源于男女厕所门上的图形符号,外加头上两根天线。

    Android 发展史

    1、AndroidBeta(阿童木)2008年8月18日发布(内测版)

    添加一些新的开发工具,例如Eclipse layout布局支持预览,支持编辑9-patch图像等
    2、 Android1.0 (发条机器人): 2008年9月23日发布(内测版)

    首款Android 设备the T-Mobile G1搭载Androd1.0,内置了Android Market beta
    3、 Android1.5 Cupcake(纸杯蛋糕)2009年4月30日发布;

    拍摄/播放影片,并支持上传到Youtube
    支持立体声蓝牙耳机,同时改善自动配对性能
    最新的采用WebKit技术的浏览器,支持复制/贴上和页面中搜索
    GPS性能大大提高
    提供屏幕虚拟键盘
    主屏幕增加音乐播放器和相框widgets
    应用程序自动随着手机旋转
    短信、Gmail、日暦,浏览器的用户接口大幅改进,如Gmail可以批量删除邮件
    相机启动速度加快,拍摄图片可以直接上传到Picasa
    来电照片显示
    4、Android1.6 Donut (甜甜圈)2009年9月15日发布。

    重新设计的Android Market手势
    支持支持CDMA网络
    文字转语音系统(Text-to-Speech)
    快速搜索框
    全新的拍照接口
    查看应用程序耗电
    支持虚拟私人网络(VPN)
    支持更多的屏幕分辨率
    支持OpenCore2媒体引擎
    新增面向视觉或听觉困难人群的易用性插件
    5、Android2.0 Eclair (松饼)2009年10月26日发布。

    优化硬件速度
    "Car Home"程序
    支持更多的屏幕分辨率
    改良的用户界面
    新的浏览器的用户接口和支持HTML5
    新的联系人名单
    更好的白色/黑色背景比率
    改进Google Maps3、1、2
    支持Microsoft Exchange
    支持内置相机闪光灯
    支持数码变焦
    改进的虚拟键盘
    支持蓝牙2、1
    支持动态桌面的设计
    6、Android2.2Froyo(冻酸奶)2010年5月20日发布。

    完整的Chrome浏览器
    全新的手机风景模式
    全新的文件管理器
    文本输入选项的改进
    一个明确的升级方法
    Android Key Lime Pie精简版
    具有开关切换的用户界面
    全新的电源管理系统
    更为轻便的主题模式
    全新的锁屏页面
    全新的时钟界面
    7、Android2.3 Gingerbread (姜饼)2011年2月2日发布。

    优化针对平板
    全新设计的UI增强网页浏览功能
    n-app purchases功能
    8、Android3.1 Honeycomb (蜂巢)2011年5月11日发布

    Honeycomb 蜂巢(改进3、0BUG)
    经过优化的Gmail电子邮箱;
    全面支持GoogleMaps
    将Android手机系统跟平板系统再次合并从而方便开发者
    任务管理器可滚动,支持USB 输入设备(键盘、鼠标等)
    支持 Google TV、可以支持XBOX 360无线手柄
    widget支持的变化,能更加容易的定制屏幕widget插件
    9、Android3.2 Honeycomb (蜂巢)2011年7月13日发布

    支持7英寸设备
    引入了应用显示缩放功能.
    10、Android4.0 Ice Cream “冰激凌三明治”2011年10月19日发布

    蓝色主题
    接近于桌面版的Chrome Lite浏览器,有离线阅读,同步Chrome书签,新的标签样式等
    截图功能
    更强大的图片编辑功能
    自带照片应用堪比Instagram,可以加滤镜、加相框,进行360度全景拍摄,照片还能根据地点来排序
    Gmail加入手势、离线搜索功能,UI更强大
    新功能People:以联系人照片为核心,界面偏重滑动而非点击,集成了Twitter、Linkedin、Google+等通讯工具。有望支持用户自定义添加第三方服务
    新增流量管理工具,可具体查看每个应用产生的流量
    正在运行的程序可以像电脑一样的互相切换
    人脸识别功能
    系统优化、速度更快
    支持虚拟按键,手机可以不再拥有任何按键
    专为3D优化的驱动
    平板电脑和智能手机通用
    11、Android 4.1 Jelly Bean(果冻豆)2012年6月28日发布。

    更快、更流畅、更灵敏
    增强通知栏
    全新搜索
    桌面插件自动调整大小
    加强无障碍操作
    语言和输入法扩展
    新的输入类型和功能
    新的连接类型
    新的媒体功能
    浏览器增强
    Google服务增强
    12、Android 4.2 Jelly Bean(果冻豆) 2012年10月30日发布。

    完整的Chrome浏览器
    全新的手机风景模式
    全新的文件管理器
    文本输入选项的改进
    一个明确的升级方法
    Android Key Lime Pie精简版
    具有开关切换的用户界面
    全新的电源管理系统
    更为轻便的主题模式
    全新的锁屏页面
    全新的时钟界面
    13、Android 4.3 Jelly Bean(果冻豆)2013年7月25日发布。

    用户账户配制
    拨号盘联系人自动补全
    OpenGL 3.0
    蓝牙低耗电技术
    WIFI关闭后保持位置功能其它特性
    新的相机应用UI
    新的开发者工具
    通过邮件分享截屏时,日期和时间会自动加入进去
    14、Android 4.4 KitKat(奇巧) 2013年9月4日发布。

    拨号盘联系人自动补全
    优化了RenderScript计算和图像显示,取代OpenCL
    支持两种编译模式
    Android 4.4 KitKat针对RAM占用进行了优化,甚至可以在一些仅有512MB RAM的老款手机上流畅运行
    新图标、锁屏、启动动画和配色方案
    新的拨号和智能来电显示
    加强主动式语音功能
    集成Hangouts IM软件
    全屏模式
    支持Emoji键盘
    轻松访问在线存储
    无线打印
    屏幕录像功能
    内置字幕管理功能
    计步器应用
    低功耗音频和定位模式
    新的接触式支付系统
    新的蓝牙配置文件和红外兼容性
    15、Android 5.0 Lollipop(棒棒糖) 2014年6月26日发布。

    系统使用一种新的Material Design 设计风格
    Android 5.0 将会加入更多的健身功能
    整合碎片化
    支持64位处理器
    使用ART虚拟机
    16、Android 6.0 Marshmallow(棉花糖) 2015大会已于5月28日发布。

    锁屏下语音搜索
    指纹识别,Android 6.0则在系统层面加入指纹识别,能提供原生指纹识别API
    更完善的应用权限管理,Android 6.0进一步强化应用权限管理,应用权限管理也成为系统级的功能
    Doze电量管理。手机会在一段时间未检测到移动时,让应用休眠清杀后台进程减少
    Now on Tap功能。Now on Tap功能是和Google搜索紧密结合的功能,它可以让谷歌从任何应用中进行搜索。例如,在微信中聊天的时候提到餐馆,那么就可以在不跳转的情况下进行谷歌搜索。
    App Links
    17、Android7.0 Nougat 牛轧糖 2016年5月18日发布。

    多窗口支持,用户可以在一个屏幕上打开两个应用
    通知增强功能,可以在通知界面快速回复短信,通知消息归拢(同一应用的多条通知提示消息归拢为一项,点击该项即可展开此前的全部通知,允许用户对每个通知执行单独操作。)
    添加了即时 (JIT) 编译器,提升运行时性能,节省存储空间,加快应用安装更新和系统更新速度
    随时随地低电耗模式,只要屏幕关闭了一段时间,且设备未插入电源,低电耗模式就会对应用使用熟悉的 CPU 和网络限制
    后台优化,弃用一些较旧的模式,比如删除了三个常用的隐式广播: CONNECTIVITY_ACTION(网络发生改变)、ACTION_NEW_PICTURE(照相)、ACTION_NEW_VIDEO (录像)这些广播一次会唤醒多个应用的后台进程
    推荐使用 SurfaceView 代替 TextureView,以实现省电
    添加新的3D 渲染 API Vulkan。Vulkan 是完全从零开始设计,以最小化驱动器中的 CPU 开销,并能让您的应用更直接地控制 GPU 操作。Vulkan 还允许多个线程同时执行工作,如命令缓冲区构建,以获得更好的并行化
    添加号码屏幕功能,同一个电话以及短信都可以屏幕
    来点过滤:Android 7.0 允许默认的手机应用过滤来电
    Android 7.0 引入更多表情符号和表情符号相关功能,包括肤色表情符号和支持变量选择符
    Android 7.0 添加了框架接口和对 OpenGL ES 3.2 的平台支持
    Android 7.0 引入密钥认证,这是一个新的安全工具,可帮助您确保设备的硬件支持的密钥库中存储的密钥对适当保护您的应用使用的敏感信息
    面向 Android 7.0 的应用仅信任系统提供的证书,且不再信任用户添加的证书颁发机构 (CA)。如果面向 Android N 的应用希望信任用户添加的 CA,则应使用网络安全性配置以指定信任用户 CA 的方式
    引入一项新的应用签名方案 APK Signature Scheme v2,它能提供更快的应用安装时间和更多针对未授权 APK 文件更改的保护
    作用域目录访问:应用可以使用新的 API 请求访问特定的外部存储目录,包括可移动媒体上的目录,如 SD 卡。新 API 大大简化了应用访问标准外部存储目录的方式,如 Pictures 目录
    添加了新的 VR 模式的平台支持和优化,以使开发者能为用户打造高质量移动 VR 体验
    18、Android8.0 Oreo(Android O)

    通知中心变化
    整体更加简洁
    PinnedShortcuts,类似苹果的3DTouch
    自适应图标
    后台进程限制
    未知来源应用安装限制
    TensorFlowLite
    分屏功能,分屏画中画功能得到了强化
    新加了通知功能Notification Dots
    自动保存密码
    GooglePlayProtect,这个功能主要用于GooglePlay中
    应用加速,大部分应用的启动速度将会快上一倍
    字体优化
    新增了符合Unicode 10标准的表情符号
    19、Android 9.0 pie(开心果冰淇淋) 2018年 8 月 7 日发布

    全面屏的全面支持
    通知栏的多种通知
    多摄像头的更多画面
    GPS定位之外的WiFi定位
    网络还有神经网络
    Material Design迎来2.0时代
    数字化健康
    自适应功能
    API等级

    API等级1:Android 1.0

    API等级2:Android 1.1 Petit Four

    API等级3:Android 1.5 Cupcake

    API等级4:Android 1.6 Donut

    API等级5:Android 2.0 Éclair

    API等级6:Android 2.0.1 Éclair

    API等级7:Android 2.1 Éclair

    API等级8:Android 2.2 - 2.2.3 Froyo

    API等级9:Android 2.3 - 2.3.2 Gingerbread

    API等级10:Android 2.3.3-2.3.7 Gingerbread

    API等级11:Android 3.0 Honeycomb

    API等级12:Android 3.1 Honeycomb

    API等级13:Android 3.2 Honeycomb

    API等级14:Android 4.0 - 4.0.2 Ice Cream Sandwich

    API等级15:Android 4.0.3 - 4.0.4 Ice Cream Sandwich

    API等级16:Android 4.1 Jelly Bean

    API等级17:Android 4.2 Jelly Bean

    API等级18:Android 4.3 Jelly Bean

    API等级19:Android 4.4 KitKat

    API等级20:Android 4.4W

    API等级21:Android 5.0 Lollipop

    API等级22:Android 5.1 Lollipop

    API等级23:Android 6.0 Marshmallow

    API等级24:Android 7.0 Nougat

    API等级25:Android 7.1 Nougat

    API等级26:Android 8.0 Oreo

    API等级27:Android 8.1 Oreo

    API等级28:Android 9.0 Pie

    本Android开发系列教程将不定期更新发布,敬请期待!

    展开全文
  • Android基础--------Android常用控件介绍及使用

    万次阅读 多人点赞 2018-06-04 16:34:31
    Android常用控件介绍及使用 控件 TextView 显示文字,相当于Panel ImageView 显示图片 EditText 输入框,可编辑,可设置软键盘方式 Button 按钮,可附带图片 CheckBox 复选框 RadioButton 单选按钮...
  • Android基础介绍

    2018-09-01 11:02:59
    一.Android发展史  2003年10月,Andy Rubin等人一起创办了Android公司。05年8月被谷歌收购,此时公司才成立22个月,08年推出Android第一个版本。但在此之后,发展就收到了重重阻挠。乔布斯自始至终觉得Android是...
  • Android基础总结(精华完整版)

    千次阅读 2013-08-26 21:25:31
    1. 前言 1.1. 什么是3G、4G Ÿ 第三代移动通信技术(3rd - Generation),速率一般在几百Kbps,较之前的2G和2.5G在数据传输速度上有很大提升。 Ÿ 第四代移动通信技术(4th - Generation),速度可达到...
  • 1.Android基础入门

    2020-09-14 21:39:03
    Android简介 1. 通信技术 1G :指最初的模拟,仅限语音的蜂窝电话标准。类似于简单的无线电台,只能进行通话,并且通话是锁定在一定频率上的,这个频率就是手机号码。这种标准的缺点是很容易被窃听。 2G :指第二...
  • android基础--系统控件

    2018-11-06 16:00:17
    1.文本框TextViewTextView 1.1通过代码呈现 public class TextViewActivity extends Activity {  @Overrideprotected  void onCreate(Bundle savedInstanceState) ... setContentView(R.lay...
  • 2015年最新Android基础入门教程目录(完结版)

    万次阅读 多人点赞 2015-12-21 20:44:26
    2015年最新Android基础入门教程目录(完结版) 前言: 关于《2015年最新Android基础入门教程目录》终于在今天落下了帷幕,全套教程 共148节已编写完毕,附上目录,关于教程的由来,笔者的情况和自学心得,资源分享 ...
  • 记得在上一节Android基础入门教程——8.4.2 Android动画合集之补间动画为Fragment 设置过渡动画的时候,说过,App包和V4包下的Fragment调用setCustomAnimations()对应的 动画类型是不一样的,v4包下的是Animation...
  • Android基础入门教程——1.7 界面原型设计标签(空格分隔): Android基础入门教程本节引言:引用锤子科技视觉设计总监——罗子雄在重庆TEDx活动上说的一小段话: 每当我们看到一些美妙的设计的时候,很多人心里面...
  • Android基础入门教程——2.3.1 TextView(文本框)详解

    万次阅读 多人点赞 2015-07-22 09:04:25
    Android基础入门教程——2.3.1 TextView(文本框)详解标签(空格分隔): Android基础入门教程本节引言: 学习完Android中的六大布局,从本节开始我们来一个个讲解Android中的UI控件,本节给大家带来的UI控件是:...
  • Android 面试题总结之Android 基础(五)

    千次阅读 多人点赞 2016-06-14 13:10:00
    Android 面试题总结之Android 基础(ListView)(五) 前几篇面试总结中,主要讲了Android 的四大组件的相关知识点,希望在大家日常工作中有所帮助,那么在本节中主要是Android 必不可少的ListView 的相关知识点。...
  • Android基础入门教程——3.1.1 基于监听的事件处理机制标签(空格分隔): Android基础入门教程本节引言: 第二章我们学习的是Android的UI控件,我们可以利用这些控件构成一个精美的界面,但是仅仅是界面而已;下...
  • Android基础入门教程——7.4 Android调用WebService标签(空格分隔): Android基础入门教程本节引言: 经过前面的学习,数据请求,数据解析,文件上传下载等,应该满足大家与服务器交互的基本 需求了,而本节给...
  • 从本节开始我们来探究Android中的动画,毕竟在APP中添加上一些动画,会让我们的应用变得 很炫,比如最简单的关开Activity,当然自定义控件动画肯定必不可少啦~而Android中的动画 分为三大类,逐帧动画(Frame)以及...
  • Android基础入门教程——8.3.2 绘图类实战示例标签(空格分隔): Android基础入门教程本节引言: 前两节我们学了Bitmap和一些基本的绘图API的属性以及常用的方法,但心里总觉得有点 不踏实,总得写点什么加深下...
1 2 3 4 5 ... 20
收藏数 286,960
精华内容 114,784
关键字:

android基础