第一天


1、LinearLayout,线性布局
vertically :垂直,纵向
horizontally:水平,横向

a:方向,默认横向
android:orientation="horizontal"
horizontal,在水平方向上一个挨着一个
vertical,在垂直方向上一个挨着一个

b:控件的宽,高
android:layout_width="fill_parent":宽
android:layout_height="fill_parent":高

fill_parent/match_parent:匹配父控件
wrap_content:包裹内容物
固定值:100dp

c:单位
dp:表示非文字大小的尺寸
sp:设置文字大小

d:设置背景颜色 或 背景图片
android:background="#ff0000"
android:background="#f00"

使用RGB三原色设置背景颜色
ARGB,A:alpha,带透明度的三原色
Color.rbg();
Color.arbg();

完全透明:#00~~~
完全不透明:#ff~~~

设置背景图片:
android:background="@drawable/img001"
@drawable/img001:访问图片的资源文件

e:边距
内边距:控件内部,内容与边框的距离
android:padding:四个方向
paddingleft,rigth,top,bottom

外边距:控件之间的距离
android:layout_margin:四个方向
layout_marginLeft,right,top,bottom

f:
android:gravity:设置View中内容的位置
1).设置在布局节点(LinearLayout),指定布局中控件的位置
2).设置在控件中(Button,TextView……),指定控件中文字的位置
android:gravity="right|bottom",右下角

android:layout_gravity:控件相对于容器的位置,使用在控件中
在横向布局中,设置为right失效
在纵向布局中,设置bottom失效

g:
android:weight:设置权重,在横向或纵向上,控件占用空间的比例
默认权重为0

在横向布局中,设置android:layout_width="0dp"
在纵向布局中,设置android:layout_height="0dp"

h:
android:id,设置控件的id,给控件起个名字,可以在应用中使用名字获得该控件
android:id="@+id/mTextView",
可以理解为:在R文件中新增控件,名为mTextView

通过id获得控件
mTextView = (TextView) findViewById(R.id.mTextView);


2,FrameLayout:帧布局
在屏幕的某个区域可以添加多个控件,最近(最后)添加的显示在最上方

重点:
id
width
height

边距:padding,margin

weight:权重

gravity
layout_gravity




RelativeLayout相对布局

a:控件与布局之间的对齐方式,值为true
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"

android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"

b:兄弟控件之间的相对位置,值为另外一个控件的id,不能设置第一个控件的左方和上方
android:layout_above="@id/tv1"
android:layout_below="@id/tv1"
android:layout_toLeftOf="@id/tv1"
android:layout_toRightOf="@id/tv1"


c:兄弟控件之间的对齐方式,值为另外一个控件的id
android:layout_alignLeft="@id/tv1"
android:layout_alignRight="@id/tv1"
android:layout_alignTop="@id/tv1"
android:layout_alignBottom="@id/tv1"

d:基准线对齐,本控件文字的底边与目标控件文字的底边对齐
android:layout_alignBaseLine




第二天
复习:
1、LinearLayout,线性布局
android:orientation
horizontal
vertical

2、
android:layout_width
android:layout_height

fill_parent,match_parent
wrap_content
固定值:100dp

3、background,背景颜色 和 背景图片
RGB
ARGB

@drawable/img

4、边距:
内边距:padding
外边距:margin

5、gravity:
layout_gravity:

6.weight:权重,默认0
水平布局,layout_width="0dp"
垂直布局,layout_height="0dp"

7.FrameLayout,帧布局

本课内容:
1、RelativeLayout,相对布局

参考文档

2、GridLayout,网格布局
与线性布局类似,需要指定控件的方向
android:orientation= horizontal 或 vertical

指定行数和列数
android:rowCount="5":行数
android:columnCount="4":列数

合并单元格
android:layout_rowSpan="2",跨行合并
android:layout_columnSpan="2",跨列合并

合并之后应该进行填充
android:layout_gravity="fill_vertical",fill,fill_horiaontal

网格中的单元格可以通过索引访问,索引从0开始

指定控件在网格中显示的位置
android:layout_row="0"
android:layout_column="3"

3.TextView:用于显示文本

android:text="@string/textView":设置文本内容
android:textSize="30sp":大小
android:textColor="#f00":颜色
android:textStyle="bold|italic":样式

android:autoLink="web",设置链接,phone,email,map,all

android:singleLine="true":单行显示,默认在末尾加...

android:marqueeRepeatLimit="marquee_forever",设置滚动的次数,
android:focusable="true",是否获得焦点
android:focusableInTouchMode="true",以触摸的形式获得焦点

4.EditText:用于输入文本,获得光标时,显示不同的软键盘
是TextView的子类

android:hint:设置提示
android:inputType:设置输入的类型,弹出的软键盘不同

5、Button
添加按钮的单击事件
a:创建子类(内部类),实现android.view.View.OnClickListener接口,重写onClick方法
b:匿名内部类
c:在布局文件中,Button标签添加onClick属性,属性值为方法名
该方法声明要求:
public void 方法名(view v){}

多个按钮处理单击事件
a:实现android.view.View.OnClickListener接口,重写方法
1).创建子类
2).MainActivity实现接口
b:在Button标签中添加onClick属性,设置方法名

switch判断具体的按钮

6、Toast,吐司
// 1.上下文;2.显示文本;3.显示的时间
Toast.makeText(this, "button1", Toast.LENGTH_LONG).show();
注:一定要有show()方法

7、查看logCat日志信息
verbose:啰嗦的,琐碎的,冗长的
Log.v(),级别最低的一个,显示全部信息
debug:显示调试信息
Log.d()
info:显示重要的调试信息,异常
Log.i()
warn:显示警告信息
Log.w()
error:显示错误信息
Log.e()

8.RadioButton,单选按钮
保证单选按钮互斥访问,成为单选按钮,需要使用RadioGroup

默认选中:android:checked="true"

单击事件
a:在RadioButton标签中添加onClick属性
b:给RadioGroup注册监听,实现接口android.widget.RadioGroup.OnCheckedChangeListener

c: 获得选中的RadioButton的id
int id = rg.getCheckedRadioButtonId();

预习:
checkBox
ImageView








第三天

复习:
1、RelativeLayout,相对布局
16个属性

7个相对于布局
4个兄弟节点之间的相对位置
4个兄弟节点之间的对齐方式
1个基准线对齐

2.GridLayout,网格布局
方向,android:orientation

行数,rowcount
列数,columnCount

跨行合并,rowSpan
跨列合并,columnSpan
layout_gravity=“fill”

通过索引访问单元格,0起始
layout_row
layout_column

3.TextView

4.EditText,可编辑的
hint
inputType

5.Button,
单击事件,
a:OnClickListener
b:onClick="send"

public void send(View v){}

6.RadioButton
RadioGroup保证可单选

事件
a:RadioButton,onclick
b:RadioGroup,设置监听,onCheckedChangeListener


i18n: internationalization,国际化
本课内容:
1、CheckBox
事件
a:在CheckBox标签中添加onClick属性
b:使用onCheckedChangeListener

2.ImageView,显示图片

android:src="@drawable/bg04",指定显示的图片资源

三个属性搭配使用,调整图片的宽高,保证图片的宽高比例
android:adjustViewBounds="true",是否调整ImageView的边界来保持宽高比例
android:maxWidth="100dp",最大宽度
android:maxHeight="300dp",最大高度

android:cropToPadding="true",是否截取图片指定的区域使用空白来替代
android:scrollX="15dp",x轴方向截取
android:scrollY="17dp",y轴方向截取
//反向截取
android:scrollX="-15dp",x轴方向截取
android:scrollY="-17dp",y轴方向截取

android:tint="#f00",使用指定的颜色渲染图片
android:alpha="0.5f",设置透明度


android:scaleType="",设置裁剪的类型

matrix:保持图片原大小显示,从左上角开始显示

fitStart:保持横纵比例缩放图片,并将图片放到ImageView的左上角

fitEnd:保持横纵比例缩放图片,并将图片放到ImageView的右下角

fitCenter:保持横纵比例缩放图片,并将图片放到ImageView的中间

fitXY:横向,纵向独立缩放图片,适应Imageview的大小,不保持原来图片的比例,填充ImageView

center:不进行任何缩放,将图片放到ImageView的中央,如果图片大于ImageView,截取中间部分显示

centerCrop:保持横纵比例缩放图片,使图片覆盖ImageView,以图片和ImageView的中心为基准点,进行缩放,直到图片最小的某方向等于ImageView的某边(某一方向的长宽等于ImageView,另一方向大于ImageView),进行截取

centerInside:保持横纵比例缩放图片,使ImageView能完全显示图片,以图片和ImageView的中心为基准点,进行缩放,显示图片内容,如果图片小于ImageView,不进行缩放,居中显示;如果图片大于Imageview,进行缩放,居中显示


3、AutoCompleteTextView

控件
适配器(adapter:ArrayAdapter,SimpleAdapter,BaseAdapter……)
数据源

适配器作用:实现数据源和控件的关联





第四天
复习:
1.CheckBox
事件
a:onClick
b:onCheckedChangeListener

2.ImageView
src="@drawable/bg"
iv.setImageResource(resId);

scaleType
tint
alpha

3.ToggleButton Switch

4.AutoCompleteTextView

适配器:ArrayAdapter,数据源是集合或数组


本课内容:
1、Spinner:下拉列表

在布局文件中,Spinner标签添加属性,与字符串数组资源关联
android:entries="@array/planets_array"(关联的资源是res文件夹下的values文件夹中string中的string_array)

给Spinner添加事件,实现接口是OnItemSelectedListener
注意:注册监听器

代码详见案例。

2、解析xml文件,首先在res下创建xml文件夹,放置xml文件

xml解析获得标签属性值:parser.getAttributeValue(null,"cityname")//null:固定值;cityname:属性的名字
3、ArrayAdapter,数据源是集合或数组

更新适配器:adapter.notifyDataSetChanged();
4、获取当前时间
安卓控件
http://www.cnblogs.com/menlsh/archive/2013/02/23/2923867.html
方法一
Calendar c = Calendar.getInstance();
取得系统日期:year = c.get(Calendar.YEAR)
month = c.grt(Calendar.MONTH)
day = c.get(Calendar.DAY_OF_MONTH)
取得系统时间:hour = c.get(Calendar.HOUR_OF_DAY);
minute = c.get(Calendar.MINUTE)


方法二
TextView myTextView = (TextView)findViewById(R.id.myTextView);
Time time = new Time("GMT+8");
time.setToNow();
int year = time.year;
int month = time.month;
int day = time.monthDay;
int minute = time.minute;
int hour = time.hour;
int sec = time.second;
myTextView.setText("当前时间为:" + year +
"年 " + month +
"月 " + day +
"日 " + hour +
"时 " + minute +
"分 " + sec +
"秒");





第五天

1、Activity,四大组件之一,创建成功之后,都需要在清单文件中进行注册
可以认为是应用程序的页面

创建Activity
a:创建子类继承Activity,重写onCreate方法
b:创建布局文件
c:在清单文件中进行注册

2、Intent,意图
启动Activity
方法1:
Intent intent = new Intent();
// 1.上下文,代表当前Activity
// 2.代表跳转的目的页面,传递的是Class类型的对象
intent.setClass(MainActivity.this, NextActivity.class);
// 启动意图
startActivity(intent);

方法2:
Intent intent = new Intent(MainActivity.this, NextActivity.class);
// 启动意图
startActivity(intent);

3、Intent传值
a:
A页面:Intent对象使用putExtra方法封装名值对
B页面:首先获得意图(getIntent())
之后使用相应的get***Extra()方法获得值

b:
A页面:创建Bundle对象,封装数据,之后将Bundle对象再封装到Intent中
Bundle bundle = new Bundle();
bundle.putString("sex", "male");
bundle.putInt("weight", 65);
intent.putExtra("bundle", bundle);
B页面:首先获得Bundle对象,获得Bundle封装的数据
Bundle bundle = intent.getBundleExtra("bundle");
String sex = bundle.getString("sex");
int weight = bundle.getInt("weight");

c:
A页面:使用Bundle对象封装数据
intent.putExtras(bundle);
B页面:获得Bundle对象,可以获得前一个页面使用putExtra方法封装的名值对
Bundle bundle = intent.getExtras();

d:传递对象,要求对象可序列化
A页面:封装对象
Person person = new Person("jack", 21);
intent.putExtra("person", person);
或者
bundle.putSerializable("person", person);

B页面;获得对象
Person person = (Person) intent.getSerializableExtra("person");
或者
Person person = (Person) bundle.getSerializable("person");


4.StartActivityForResult
跳转到下一个页面并返回结果

A页面,使用StartActivityForResult启动下一个页面
在onActivityResult方法中获得返回值
B页面,获得Intent(getIntent()),封装数据
// 设置响应码和Intent对象
setResult(2, intent);
// 结束Activity的生命周期
finish();

shutdown -s -t 60 -c
at 12:00 shutdown -s -t

5.Activity生命周期
方法有7个,是系统调用的
onCreate():创建并初始化Activity时使用
onStart():显示页面
onResume():获取用户焦点,与用户进行交互

onPause();失去焦点,暂停与用户的交互
onStop():关闭页面,处于后台运行
onDestroy():销毁页面

onRestart():页面重新启动并显示,级联调用onStart-onResume

6、分析生命周期
a:启动Activity,onCreate-onStart-onResume
b:当前Activity被其他Activity覆盖(第二个页面以对话框形式显示) 或 锁屏:onPause
当前Acitvity回到前台显示 或 解锁:onResume
c:跳转到新的Activity 或 按HOme键:onPause-onStop

d:按回退 或 再运行应用:onRestart-onStart-onResume

e:当b,c两种情况,当前Activity已经不可用,如果系统资源不足,将杀死当前的Activity
f:当用户退出Activity,onPause-onStop-onDestroy

8、生命周期的阶段
完整生命周期:onCreate-onDestroy
可见声明周期:onStart-onStop
前台(焦点)生命周期:onResume-onPause

7。现场保护

保存数据
onPause-onSaveInstanceState-onStop-onDestroy

恢复数据
onCreate-onStart-onRestoreInstanceState-onResume





Activity生命周期
1.打开主界面,后退键退出
onCreate-onStart-onResume-onPause-onStop-onDestroy
2.打开主界面,进入第二个页面
onCreate-onStart-onResume-AonPause-BonCreate-BonStart-BonResume-AonStop
在B页面按返回键
BonPause-AonRestart-AonStart-AonResume-BonStop-BonDestroy

2.1、打开主页面,进入第二个页面,第二个页面以对话框显示
在清单文件中,Activity标签中设置页面主题:
android:theme="@android:style/Theme.Dialog"

onCreate-onStart-onResume-AonPause-BonCreate-BonStart-BonResume

按返回或点击屏幕其他位置
BonPause-AonResume-BonStop-BonDestroy

3.打开主界面,模拟电话进入及挂机,再次显示主界面
onCreate-onStart-onResume-onPause-onStop-onRestart-onStart-onResume

4.打开主界面,HOME键退出
onCreate-onStart-onResume-onPause-onStop
5.打开主界面,HOME键退出,再次启动app
onCreate-onStart-onResume-onPause-onStop-onRestart-onStart-onResume

6.打开主界面,切换横屏竖屏。
onCreate-onStart-onResume-onPause-onStop-onDestroy-onCreate-onStart-onResume

屏幕切换,销毁当前页面,再重新创建


http://flash.weather.com.cn/wmaps/xml/china.xml








第六天
一、Task
* 任务栈 对 所有Activity涉及其操作的任务集合
*
* 特点:
* 1 栈顶的元素 是用户直接看到的那个任务 并且 可以进行交互
* 2 栈中的元素都处于停止的状态
* 3 弹出的任务 销毁状态
二、启动模式
* Activity 启动模式
* 配置方法: 在清单文件中activity 标签下 设置 launchMode = “”;
* 1.standard
* 标准的启动模式(默认) , 每次启动的时候都会实例化一个新的Activity对象放入栈中
* 2.singleTop
* 如果当前任务处于栈顶,则不会创建新的实例入栈,会调用当前栈顶元素的 onNewIntent 方法 如果该任务没有处于栈顶,则创建新的实例放入栈中
* 3.singleTask
* 如果栈中已经存在该实例,则重用该实例,不会创建新的实例,重用时 ,会将该实例上面的所有Activity 弹出销毁
* 当前实例处于栈顶
* 4.singleInstance
* 在一个新的栈当中创建Acitivty 的实例 对其他应用程序共享该实例
三、Intent 七大属性
* Intent: 意图
* 1.启动新的组件 Activity,Service ,BroadCast。。。
* 2.传递数据
* 3.根据action标记来启动系统页面
* 七大属性:
* 1. ComponentName 组成 ,要素,构成
* 1) 显示意图 直接设置上下文对象及目标Activity 进行跳转等同与Intent直接设置参数
* 2) 跨应用跳转Activity ( 包名,目标类的全路径)
* 2. Action 标识符
* intent-filter 意图过滤器 过滤条件的集合 在清单文件中配置
* action 与category 必须同时使用
* 1) 隐式意图作为跳转目标的标记 ,将目标Activity 的action设置一个字符串标识 根据Intent 的action 属性 进行跳转
* 2) 根据Intent类的常量调用系统页面(模拟器有问题)
* 3. Category种类
* 和Action 同时使用 表示当前Activity的类型
* 1) DEFAULT 默认
* 2) LAUNCHER 该应用启动的Activity
* 4.Data Uri
* Uri 统一资源标识符 格式:scheme://host:port/path
* 其他的 Android系统的 资源标识符

系统内置的几个Data属性常量:
tel://:号码数据格式,后跟电话号码。
mailto://:邮件数据格式,后跟邮件收件人地址。
smsto://:短息数据格式,后跟短信接收号码。
content://:内容数据格式,后跟需要读取的内容。
file://:文件数据格式,后跟文件路径。
market://search?q=pname:pkgname:市场数据格式,在Google Market里搜索包名为pkgname的应用。
geo://latitude, longitude:经纬数据格式,在地图上显示经纬度所指定的位置。


Uri 统一资源标识符
的格式如下:scheme://host:port/path
约束 主机名(域名:端口号) 路径
url http://www.baidu.com:8080/indext?page =1


//实现发短信
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setType("vnd.android-dir/mms-sms");
intent.putExtra("sms_body", "信息内容...");
startActivity(intent);


* 5.type类型
* 字符串格式 abc/xyc
* 6.Extra 携带数据
* 7.Flag 启动模式

intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); // -- singleTop
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // -- singleTask
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // -- singleInstance


四:
1.清单文件中 versionCode代表 版本号
versionName代表版本名称
Permissions 权限 ,有需要的添加
设置category 的Activity 为应用启动的Activity
2.注意命名规范
方法名使用驼峰式命名方法
尽量使用英文 不要使用汉语拼音
3.Debug 的两种方式


Intent意图

系统内置的几个Data属性常量:
tel://:号码数据格式,后跟电话号码。
mailto://:邮件数据格式,后跟邮件收件人地址。
smsto://:短息数据格式,后跟短信接收号码。
content://:内容数据格式,后跟需要读取的内容。
file://:文件数据格式,后跟文件路径。
market://search?q=pname:pkgname:市场数据格式,在Google Market里搜索包名为pkgname的应用。
geo://latitude, longitude:经纬数据格式,在地图上显示经纬度所指定的位置。


Uri 统一资源标识符
的格式如下:scheme://host:port/path
约束 主机名(域名:端口号) 路径
url http://www.baidu.com:8080/indext?page =1



Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setType("vnd.android-dir/mms-sms");
intent.putExtra("sms_body", "信息内容...");
startActivity(intent);





第七天

Json
http://sns.maimaicha.com/api?apikey=b4f4ee31a8b9acc866ef2afb754c33e6&format=json&method=news.getListByType&page=0&row=15&type=52

Image
https://www.baidu.com/img/bd_logo1.png

一、主线程(UI线程)不能访问网络 子线程不能更新UI
主线程(UI线程)不能访问网络,使用子线程获得网络数据,子线程不能更新UI,获得数据交给主线程完成UI的修改
二、AsyncTask 异步任务 抽象类
封装了 完成子线程的方法与 UI线程更新的方法


/**
* 第一个参数 : 参数 一般传入 URL String 类型
* 第二个参数 : 进度 Integer
* 第三个参数 : 结果 数据类型 根据返回值决定
*
* @author Mr.Zhao
*
*/
class MyTask extends AsyncTask<String, Integer, Object> {

/**
* 任务开始前的准备工作
* 通常用作于 UI的初始化
* 在UI 线程中
*/
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}

/**
* ×××××××× 重要 常用
* 子线程执行 网络请求 等 工作
* 参数 为 继承该抽象类的时候泛型中的第一个
* 参数类型必须保持一致 返回值: 是 网络请求结果 的值
* 数据类型 必须与 继承抽象类的泛型中的第三个
* 子线程
*/
@Override
protected Object doInBackground(String... params) {
// TODO Auto-generated method stub
return null;
}

/**
* 更新进度 values 代表着当前进度 UI线程中
*
*/
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}

/**
* 子线程工作后结果处理的方法 这个方法 已经回到了UI(主)线程
* 可以进行更新UI 的操作
* 重要 常用
*/
@Override
protected void onPostExecute(Object result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}

/**
*
* 取消当前任务
*/
@Override
protected void onCancelled() {
// TODO Auto-generated method stub
super.onCancelled();
}
}




第八天

ListView: 列表视图
可使用ArrayAdapter 实现简单的布局效果

BaseAdapter
自定义适配器 --- 抽象类

* 当Android 系统所提供的适配器无法满足用户需求的时候 那么就需要我们来自定义适配器达到想要的需求结果
*
* 自定义适配器需要继承现有的 BaseAdapter
* 抽象类 需重写各种方法
*
* 自定义适配器的步骤:
* 1.定义一个子类继承BaseAdapter
* 2.重写相应的方法
* a)getCount表示加载到当前适配器的条目总数
* b)getItem 表示根据位置获取Item 对象
* c)getItemId根据位置获取当前item 的ID
* d)getView 根据位置获取当前item 显示的View

引用XML文件布局作为 View
将xml布局转化为View对象

* 自定义的Adapter 的item不仅仅局限于 系统view 可以也 自定义 xml布局文件 那么 就需要将布局文件转换成为 View
*
* 将布局转换成为View 的方法 ---
* 一、LayoutInflater
* LayoutInflater 的实现方式
* 1.LayoutInflater.from(Context)
* 2.Activity.getLayoutInflater();
* 3.Context.getSystemService(Context_LAYOUT_INFLATER_SERVICE);
*
* 二、 直接将布局转换成为View
* View view = View.inflater(Context,R.layout.XXX,null);
*


ListView 优化
* ListView 优化
* 1. 重复利用convertView
* -- ViewHolder
六步骤
// 第一步 实例化 视图持有者 ViewHolder
// 第二步 判断convertView 是否被创建
// 第三步 实例化Holder 对象
// 第四步holder 对象 内部引用的实例化
// 第五步 -- 给convertView 设置 Holder标
// 第六步 --当convertView 不为null 的时候 通过convertView获取到 holder
* 2. ListView的高度设置 match_parent 或绝对数值
* 3. 尽量不要再getView 方法中进行 业务逻辑繁杂或延时操作

// 当数据源发生改变 后 调用该方法 刷新数据
该方法为Adapter 的方法 注意使用
notifyDataSetChanged();





第十一天

一,菜单 Menu


1,选项菜单(系统菜单)OptionsMenu

1.1 两种创建菜单项的方式

高版本:在xml中定义<item>菜单项


低版本:纯java代码创建Item项



1.2 高版本 在res/menu/main.xml中定义菜单项

<!--
android:id Menu资源的Id
android:title Menu菜单项的文本
android:orderInCategory="100" 设置菜单项显示的顺序,值越小,越在上面显示
android:showAsAction="never" 设置菜单项何时和怎样显示在Action Bar上

属性值: never 永远都不会显示在Action Bar上
ifRoom 如果有空间显示在Action Bar上
always 一直显示在Action Bar上

-->
<item
android:id="@+id/action_quit"
android:orderInCategory="100"
android:showAsAction="never"
android:title="退出"/>


/**
* 创建菜单项 ,当你创建Activity时调用
*
* 一个activity中只能有一个OptionsMenu
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// 加载菜单布局
getMenuInflater().inflate(R.menu.main, menu);

return true;
}

/**
* 点击Menu Item 的回调方法
*
* MenuItem item 当前点击的菜单项
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {

case R.id.action_quit:

finish();// 关闭当前页面

break;

case R.id.action_red:

tv.setTextColor(Color.RED);

break;


case R.id.action_size_40:

tv.setTextSize(40);

break;
}

return super.onOptionsItemSelected(item);
}



1.3 低版本的创建:纯JAVA代码

/**
* groupId 分组ID
* itemId 菜单项的Id
* order 菜单显示的顺序
* title 菜单文本
*/
menu.add(Menu.NONE, 1, Menu.NONE, "代码菜单1");

SubMenu subMenu = menu.addSubMenu(Menu.NONE, 2, Menu.NONE, "代码菜单2");
subMenu.add(Menu.NONE, 21, Menu.NONE, "sub 2_1");
subMenu.add(Menu.NONE, 22, Menu.NONE, "sub 2_2");


2,上下文菜单 ContextMenu 可以为任意View指定上下文菜单,长按View创建上下午菜单,通常使用在ListView或者GridView中


2.1 为View注册上下文菜单

registerForContextMenu(tv);


2.2 onCreateContextMenu()

/**
* 2, 重写父类的方法onCreateContextMeun()
*
* 当长按View时调用
*
* ContextMenu menu 需要显示的菜单 View v 用户选择的View ContextMenuInfo menuInfo
* 所选择页面的额外信息,(ListView,GridView,Spinner) 携带了AdapterView中的position信息
*/
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {

// 加载菜单布局
getMenuInflater().inflate(R.menu.main, menu);

super.onCreateContextMenu(menu, v, menuInfo);
}


2.3 onContextItemSelected()

@Override
public boolean onContextItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {

case R.id.action_delete:

//得到当前选中ListView的Item的信息
AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo)item.getMenuInfo();

//获取当前选中ListView的Item的下标
int posiotion = menuInfo.position;

//移除数据
data.remove(posiotion);
//刷新适配器
adapter.notifyDataSetChanged();
break;

}
return super.onContextItemSelected(item);
}





3,PopUpMenu 弹出式菜单 API 11以上,可以为任一View创建弹出式菜单

public void click(View v)
{
//创建PopupMenu
/**
* context 上下文对象
* anchor 当前弹出菜单的参考显示的位置
*/
PopupMenu pMenu = new PopupMenu(this, v);

//加载菜单
getMenuInflater().inflate(R.menu.main, pMenu.getMenu());

pMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {

@Override
public boolean onMenuItemClick(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.action_size_20:

tv.setTextSize(20);

break;

case R.id.action_size_30:

tv.setTextSize(30);

break;
}

return false;
}
});

//显示弹出式菜单
pMenu.show();
}




二,对话框 Dialog ,所有对话框都必须 show()


1, 普通对话框 AlertDialog

进度条对话框 ProgressDialog

日期选择对话框 DatePickerDialog

时间选择对话框 TimePickerDialog

自定义对话框



2,列表对话框(AlertDialog)

普通列表对话框

builder.setItems(R.array.arrColors,new OnClickListener() {});

单选对话框

builder2.setSingleChoiceItems(R.array.arrSizes, -1, new OnClickListener() {});

多选对话框

builder3.setMultiChoiceItems(R.array.arrHobbys, checkedItems, new OnMultiChoiceClickListener() {});


适配器对话框
builder4.setAdapter(adapter, new OnClickListener() {});


三,Toast 土司

1, 普通土司

Toast.makeText(getApplicationContext(), "提示信息", Toast.LENGTH_LONG).show();

2,指定位置的土司


//设置Toast显示的位置(显示的位置,X轴的偏移,Y轴的偏移)
toast2.setGravity(Gravity.CENTER, 0, 0);

3,自定义

Toast toast3 = new Toast(this);

TextView tv = new TextView(this);

tv.setText("我是自定义的Toast!");


toast3.setView(tv);

toast3.setDuration(Toast.LENGTH_LONG);

toast3.show();


四,通知栏








第十二天


Fragment 碎片


一,Fragment是什么?

是Android3.0之后,API11以上,是Activity的一个组成部分

提高代码的重用性和改善用户的体验(UI的合理利用)

Fragment有自己的生命周期和接受处理用户的事件,这样我们就不用在Activity中写一堆代码,更为重要的是
我们可以添加,替换、移除Fragment


Fragment 可以显示内容

Fragmnet 可以和用户交互


note: Fragment 必须显示在Activity中

一个Activity中可以包含多个Fragment,同一个Fragment可以被多个Activity包含


二,如何创建Fragment?


1,定义一个类,继承Fragment

2,重写父类的生命周期方法:onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState);

LayoutInflater inflater 布局加载器

ViewGroup container 当前Fragment所在的父容器对象

 Bundle savedInstanceState 存放的业务数据






三,Fragment的显示方式


1,静态方式显示

在Activity的布局文件中,<fragment>

必须要有id属性,来标示Fragment的唯一性

name:指定要显示的Fragment的名称


2,动态方式显示

2.1 需要在Activity布局中,通过布局容器占位


2.2 Activity中:显示

//1,得到Fragment的管理器对象
FragmentManager manager = getFragmentManager();

//2,开启Fragment的事务处理
FragmentTransaction ft = manager.beginTransaction();

//3,实例化Fragment(你要现实的Fragment)
LeftFragment fragment = new LeftFragment();

//4,动态显示Fragment
//containerViewId 在Activity布局中为Fragment占位的Id, fragment 要显示的Fragment
//ft.add(R.id.fragment_left_id, fragment);
ft.replace(R.id.fragment_left_id, fragment);

//5,提交事务(只能提交一次)
ft.commit();


四,Activity向Fragment传值

1,向Fragment传入参数

Bundle args = new Bundle();
args.putString("msg", "显示的内容:" + new Date());

fragment.setArguments(args);


2,在Fragment中获取传入的参数


Bundle bundle = getArguments();

String msg = bundle.getString("msg");

tv.setText(msg);

五,Fragment向Activity传值


1,Fragment中定义回调接口

//定义回调接口
public interface CallBack
{
public void getResult(String result);
}


2,Fragment中:回调方法

//回调方法
public void getEditText(CallBack callBack)
{
String msg = editText.getText().toString().trim();

callBack.getResult(msg);
}



3,Activity中:

fragment.getEditText(new CallBack() {

@Override
public void getResult(String result) {

tv.setText(result);
}

});

六,Fragment向Fragment传值

调用Fragmnet中定义的普通的方法:

Activity中:

Bundle bundle = new Bundle();
bundle.putString("fileName", fileName);

ContentFragment fragment = ContentFragment.newInstance(bundle);

Fragment中:
1,public static ContentFragment newInstance(Bundle bundle) {

ContentFragment contentFragment = new ContentFragment();

contentFragment.setArguments(bundle);

return contentFragment;
}

2,在onCreateView()中: fileName = getArguments().getString("fileName");


七,Fragment生命周期(11个)


1,初始化阶段--onCreate()

onAttach(Activity activity) 与归属Activity进行连接

onCreate(Bundle savedInstanceState) 初始化Fragment

onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) 初始化Fragment中显示的UI

onActivityCreated(Bundle savedInstanceState) 归属Activity的onCreate()执行完成

2, 显示/隐藏阶段

onStart() 显示Fragment

onResume() 获取到焦点

onPause() 失去焦点

onStop() 关闭Fragment

3,销毁阶段---onDestroy()

onDestroyView() 销毁Fragment中显示的UI

onDestroy() 销毁Fragment

onDetach() 与归属Activity断开连接



显示:

F:onAttach() -- F:onCreate() -- F:onCreateView() -- A:onCreate() -- F:onActivityCreated()
--A:onStart()--F:onStart()--A:onResume() -- F:onResume()



退出:

F:onPause()--A:onPause() --F:onStop()--A:onStop() -- F:onDestroyView() --F:onDestroy()
--F:onDetach()--A:onDestroy()


八,小应用:横竖屏切换(内容改变)


九,ListFragment

1, 定义一个类,继承ListFragment

2,碎片本身就UI控件 -- ListView

3,在onCreateView()生命周期方法之后,setListAdapter(adapter);

4,重写父类的onListItemClick(),监听






===============

Day12_Fragment_01 静态显示Fragment

Day12_Fragment_02 动态显示Fragmnet,Activity向Fragment传值

Day12_Fragment_03 Fragment向Activity传值

Day12_Fragment_04 Fragment显示笔记内容

Day12_Fragment_05 Fragment显示笔记内容(横竖屏)

Day12_Fragment_06 Fragment生命周期







第十三天 数据存储(读、写)



一,分类

共享参数

内部存储

扩展存储

数据库

网络存储


二,共享参数 SharedPreferences (基本设置,登陆,定位)

1,特点: 应用程序卸载后,文件也会被删除


2,存储的数据类型: boolean , int ,long,String,float


3,数据存放的位置:data/data/应用程序包名/shared_prefs/***.xml


4,存储数据:

//1,获取共享参数的对象
/**
* name 文件名称(不需要写扩展名称)
* mode 文件的操作模式
*
* Context.MODE_PRIVATE 文件只能被当前应用程序访问
* 写入数据时,如果Key相同,Value会覆盖之前的内容
*
* Context.MODE_APPEND 写入的文件可以追加
*
*
*
* getSharedPreferences(name, mode) 需要指定文件名称
* getPreferences(mode) 文件名称是当前Activity的类名
*/
SharedPreferences sp = getSharedPreferences("mysets", Context.MODE_PRIVATE);


//2,获取共享参数的编辑对象
Editor editor = sp.edit();

//3,向共享参数中写入数据
editor.putInt("fontSize", 20);
editor.putInt("color", Color.RED);
editor.putString("msg", "你已经更改了设置!!!");

//4,提交数据
editor.commit();


5,读取数据:

//1,得到共享参数的对象

SharedPreferences sp = getSharedPreferences("mysets", Context.MODE_PRIVATE);

//2,获取数据
/**
* key 存入数据是的Key
*
* defValue 如果读取不到Key对应的数据,那么显示默认的数据
*/
int fontSize = sp.getInt("fontSize", 15);
int color = sp.getInt("color", Color.BLACK);
String msg = sp.getString("msg", "读取数据失败");




三,内部存储

1,特点: 应用程序卸载后,文件也会被删除


2,路径: data/data/应用程序包名/files/***.***


3,核心代码:FileOutputStream


3.1 存入数据:

//1,打开内部存储文件的输出流
/**
* name 文件名称
* mode 文件操作模式
*
*/
FileOutputStream fos = openFileOutput(fileName, Context.MODE_PRIVATE);

//2,写入数据
fos.write(content.getBytes());

//3,关闭流
fos.close();

3.2 读取数据:

//1,打开内部存储的输入流
FileInputStream fis = openFileInput(fileName);

//2,读取长度
byte[] buffer = new byte[fis.available()];
//3,开始读取
fis.read(buffer);
//关闭流
fis.close();



四,扩展存储 SD卡

1,特点:

当卸载应用程序时,sd卡公共目录中的文件不会清除


2,路径:

android 4.0之前:mnt/sdcard

android 4.0之后:storage/sdcard


3,读写扩展卡的权限

Environment.getExternalStorageState()

4,获取扩展卡的根目录

Environment.getExternalStorageDirectory()


5,获取当前扩展卡的状态

<!-- 写SD卡的状态 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<!-- 读SD卡的状态 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>







第十四天


Oracle,SQL Server ,mySql,SQLite 都是关系型数据库



数据库 SQLite


一,特点

轻量级,零配置,跨平台,嵌入式

在程序的内部,可以在任何位置通过数据库的名称对其访问,其他的应用程序不可以访问。



二,数据类型

NULL(空值)
INTEGER(整型)
TEXT(文本)
VARCHAR(可变长度的字符数据)
BOOLEAN(布尔)
FLOAT(单精度)
DOUBLE(双精度)
DATETIME(日期)




三,SQL语句

创建表:

create table 表名(字段名称 字段类型,...)

create table user(_id integer primary key autoincrement,name varchar(50))


表中添加字段

alter table 表名 add 字段名 类型

alter table user add amount integer


插入数据:

insert into 表名(字段s) values(值s)

insert into user(name) values('刘能')


修改数据:

update 表名 set 字段=值 where 条件

update user set name='于军' where _id=1


删除数据:

delete from 表名 where 条件


delete from user where _id=2


查询数据:

select (字段s) from 表名 where 条件


select _id,name from user where _id=3



四,Android数据库的核心类 data/data/应用程序包名/database/数据库名称

1,SQLiteDatabase 管理和操作数据库


2,SQLiteOpenHelper 用于数据库的创建和版本的更新


作用: 初始化数据库

升级数据库

打开数据库的连接


2,.1 使用步奏:

2.1.1 定义一个类,继承SQLiteOpenHelper


2.1.2 重写父类的方法

/**
* 第一次执行是调用(只执行一次)
*
* 创建初始表
*
*
* SQLiteDatabase db 数据库操作类
*/
@Override
public void onCreate(SQLiteDatabase db) {

}

/**
* 更新数据库
*
* 如果数据库的版本发生变化,执行此方法
*
* SQLiteDatabase db 数据库的操作类
* int oldVersion 旧版本
* int newVersion 新版本
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}


2.1.3 构造方法

/**
* 构造方法
* @param context 上下文对象
* @param name 数据库名称
* @param factory 游标工厂
* @param version 版本号
*/
public DbOpenHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);

}


3,Cursor 游标 (查询数据后,游标默认位置在数据之上,游标的下标从0开始)

cursor.move(offset) 将指针向上或向下移动指定的行数,
offset为正数代表向下,负数代表向上,判断数据是否存在
cursor.moveToFirst() 游标移动到第一条数据,判断第一条数据是否存在
cursor.moveToLast() 游标移动到最后一条数据,判断最后一条数据是否存在
cursor.moveToNext() 游标移动到下一条数据,判断下一条数据是否存在
cursor.moveToPrevious() 游标移动到上一条数据,判断上一条数据是否存在
cursor.moveToPosition(position) 游标移动到某一条数据,判断数据是否存在


五,Android封装的方法(为不会写SQL语句的学者准备)



1,添加

SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

/**
* table 表名
* nullColumnHack 可以为null 如果是ContentValues insert into user () values ()
* values 值 ContentValues
*/
ContentValues values = new ContentValues();
//key 数据库的字段名, value 字段对应的内容
values.put("name", "赵四");
values.put("age", "18");
values.put("amount", "100");


db.insert("user", null, values);


2,修改:

SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

/**
* table 表名
* values 值 ContentValues
* whereClause where语句之后的字句
* whereArgs 占位符的取值
*/
ContentValues values = new ContentValues();
values.put("amount", "20000");

db.update("user", values, "_id=?", new String[]{"1"});

3,查询:

SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
/**
* distinct 是否去除重复
* table 表名
* columns 查询的字段 new String[]{"name","age","amount"}
* selection where字句之后的内容 _id=?
* selectionArgs 占位符的值 new String[]{"1"}
* groupBy 分组
* having 放到where后面,再次筛选
* orderBy 排序
* limit 区间
*/
Cursor cursor = db.query("user", new String[]{"name","age","amount"}, null, null, null, null, null);

while (cursor.moveToNext()) {

Log.i("info", "姓名:" + cursor.getString(cursor.getColumnIndex("name")) +
",年龄:" + cursor.getInt(cursor.getColumnIndex("age"))+
",钱包:" + cursor.getInt(cursor.getColumnIndex("amount")));
}


4,删除:

SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

/**
* table 表名
* whereClause 条件,where之后的字句
* whereArgs 占位符对应的值
*/
db.delete("user", "_id=?", new String[]{"1"});


六,数据库的事务:

事务的好处?

1,确保数据的一致性

2,提高效率


什么时候使用事务?

进行批量操作的时候使用事务

比如批量进行添加、修改、删除时,必须手动开启事务


SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

//1,开启事务
db.beginTransaction();

try{

for(int i=1;i<=100;i++)
{
db.execSQL("insert into user(name,age,amount) values('张三'"+i+",21,100)");
}
//2,成功后提交事务
//添加 事务成功的标记,当结束事务时提交事务, 如果不写,事务回滚,sql语句不执行
db.setTransactionSuccessful();

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

}finally
{
//3,关闭事务
db.endTransaction();
}


七,应用:通讯录

八,作业: 记事本(增,删,改,查)






第十五天


Content Provider 内容提供者(Android四大组件) 图书馆(短信记录,电话记录,联系人)


一,作用


将应用的私有数据库中的私有数据向外提供一个访问的接口,是基于URI的方式,向外提供统一的数据访问接口


二,URI统一资源标示

类似与URL网络资源地址,URI是用来标示Android应用中某一资源的唯一标识,在ContentProvider组件中,通过Uri向外部应用提供一个私有数据库中的“一张表”的资源唯一标示


内容提供者的URI格式: content://应用程序包名.provider/student


三,访问ContentProvider提供的URI接口


ContentProvider 内容提供者 负责暴露数据(数据库) “服务器”


ContentResolver 内容解析器 负责解析ContentProvider暴露出来的数据 “客户端”



四,案例一:访问短信记录

数据库路径:com.android.providers.telephony中sms表

/**
* 短信的uri
*
* content://sms 所有短信
* content://sms/outbox 发送的短信
* content//sms/inbox 接收的短信
*/
private Uri smsUri = Uri.parse("content://sms");

------------------------------------------------------------------

//1,得到ContentResolver对象
ContentResolver contentResolver = getContentResolver();

//2,通过URI访问数据
/**
* uri 访问ContentProvider的路径
* projection 查询数据库表中列的集合 new String[]{}
* _id,
* address: 地址(发送者)
* body: 短信内容
* type: 类型 1 接收,2 发送,3 草稿 ,4 未读,5 发送失败
*
* selection 查询条件
* selectionArgs 查询条件中占位符对应的集合
* sortOrder 排序
*/

cursor = contentResolver.query(smsUri, new String[]{"_id","address","body"}, null, null, null);

//3,读取游标中数据

adapter = new SimpleCursorAdapter(getApplicationContext(),
R.layout.item_lv,
cursor,
new String[]{"address","body"},
new int[]{R.id.address,R.id.body},
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

lv.setAdapter(adapter);

//4,在清单文件中增加访问短信记录的权限


五,案例二:访问电话记录


数据库路径:com.android.providers.contacts 中calls表

//private Uri uri = Uri.parse("content://call_log/calls");

private Uri uri = CallLog.Calls.CONTENT_URI;

private String[] columns = {CallLog.Calls._ID,//主键
CallLog.Calls.NUMBER,//电话号码
CallLog.Calls.DATE//时间
};


-----------------------------------------------------------------------

//1,得到CotentResolver对象

ContentResolver contentResolver = getContentResolver();

//2,通过URI接口查询数据

cursor = contentResolver.query(uri, columns, null, null, null);

//3,读取游标中的数据
while (cursor.moveToNext()) {

long id = cursor.getLong(cursor.getColumnIndex(CallLog.Calls._ID));
String phone = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));
long date = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATE));

String dataText = sf.format(new Date(date));

data.add(new CallInfo(id, phone, dataText));
}

//刷新适配器
adapter.notifyDataSetChanged();


//4,添加读取电话记录的权限


六,案例三:访问联系人



联系人数据库所在的位置

data/data/com.android.provides.contacts/database/contats2



联系人表URI:

content://com.android.contacts/raw_contacts

数据表URI:

content://com.android.contacts/data


表一:raw_contacts (有多少联系人就有多少条数据)

_id: 主键

display_name: 联系人姓名

表二: data

_id: 主键

mimetype_id : 外键 (mimetypes的主键)

raw_contact_id : 外键(raw_contacts的主键)

data1: 数据

表三:mimetypes

_id 主键(1 邮箱,5 电话,7 姓名)



查找 zhansan 的 电话 :select data1 from data where raw_contact_id=1

查找 姓名,电话 : select raw_contact_id,display_name,data1 from raw_contacts as t1,data as t2 where t1._id = t2.raw_contact_id and mimetype_id=5







第十六天


自定义ContentProvider 组件


一,如何创建

1,创建一个类,继承ContentProvider ,同时实现父类的6个抽象方法


onCreate() --- 初始化数据库的操作对象(工具类)

query(Uri uri....)

Uri uri = insert(Uri uri...)

update(Uri uri...)

delete(Uri uri...)

getType(Uri uri...) 一般情况,只实现,不做处理



2,声明ContentProvider组件的唯一标识 : authority


note :authority 内容必须是小写字母, 建议以当前的应用的包名+标识资源的名称(数据库的名称)



3,声明访问数据库的那些表的code(t_user = 0 ,t_older = 6)


4,定义Uri的匹配器,并实例化,同时增加完整的Uri访问资源的接口


5,定义数据库的操作类,并oncreate()方法中实例化


6,在相应查询,修改,删除,添加方法中,通过Uri匹配器,判断当前的Uri是访问那张表的code


7,在Manifist清单文件中注册ContentProvider组件;同时声明权限

<!-- 注册ContentProvider
android:name="" 名称
android:authorities="" ContentProvider 组件的唯一标识(和authority是一致的)
android:exported="" 设置当前的组件可以被外部应用访问
android:permission="" 声明访问当前组件的权限
-->
<provider
android:name="com.qf.day16_contentprovider.MyContentProvider"
android:authorities="com.qf.day16_contentprovider_01.users"
android:exported="true"
android:permission="com.qf.day16_contentprovider_01.users.WRITE_READ"
/>



<!-- 声明访问MyContentProvider组件的权限-->
<permission android:name="com.qf.day16_contentprovider_01.users.WRITE_READ"/>

<!-- 使用访问MyContentProvider 组件的权限
<uses-permission android:name="com.qf.day16_contentprovider_01.users.WRITE_READ"/>-->






第十七天

Loader


一,什么是Loader?


装载器,Android3.0后引进,它使得我们在activity或Fragment中异步加载数据变的简单。

二,作用

通过异步的方式加载数据(数据库中的数据,网络数据,大数据)

实时刷新数据,当Cursor中的数据发生变化时,ListView自动刷新

系统内部使用LoaderManager和LoaderCallBacks来管理Loader

三,LoaderManager

作用:
1,初始化启动Loader, 无条件加载数据

getLoaderManager().initLoader(编号,查询的条件,回调接口)

2,重启Loader, 有条件或者条件发生变化时加载数据

getLoaderManager().restartLoader(编号,查询的条件,回调接口)


注意: 1,一个Activity或Fragment中只能有一个LoaderManager,但是一个LoaderManager可以管理多个Loader


2,在启动Loader时,必须要提供一个回调接口,即LoaderCallBacks接口



四,CursorLoader


CursorLoader内部使用ContentResolve来加载ContentProvider暴露出来的数据,通过URI

内置了ContentOberver ,监听数据源的改变


五,LoaderCallBacks<Cursor> 回调方法

包含3个回调方法:


创建新的Loader,一般返回的是CursorLoader

onCreateLoader(int id,Bundle args)


Loader数据加载完成后,显示数据
onLoaderFinished(Loader<Cursor> loader,Cursor data)


在创建新的Loader之前,重置之前Loader加载的数据
onLoaderReset(Loader<Cursor> loader )


六,使用Loader加载联系人的姓名和电话

1, 在Activity或Fragment中实现LoaderCallBacks接口,重写父类3方法


2,在Activity或Fragment的初始化阶段的生命周期方法中,通过getLoaderManager()的到管理器的对象,初始化
启动Loader


3,在LoaderCallBacks的创建Loader的方法中( onCreateLoader),实例化CursorLoader,并返回

4,在LoaderCallBacks的加载完成的回调方法中(onLoaderFinished()),将加载完成的数据显示出来

SimpleCursorAdapter.swapCursor(cursor);

5,在LoaderCallBacks的重置方法中(onLoaderReset()),清除之前的数据

SimpleCursorAdapter.swapCursor(null);


6,在有条件或者条件发生变化时,重启启动Loader


七,短信记录


八,自定义Loader

1,定义一个类,继承AsyncTaskLoader<D>,并声明返回数据结果的泛型


2,重写方法onStartLoading()方法,执行forceLoad()方法(强制执行后台方法,来加载数据)


3,重写父类的方法:loadInBackground(),在此方法中执行获取数据的操作,并把结果返回



-------拓展---------

九,SearchView


<!-- android:iconifiedByDefault="false" 设置当前的控件是否以图标的方式显示 -->
<SearchView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/search_view_id"
android:iconifiedByDefault="false"
/>


十,ContentObserver 内容观察者

1,自定义内容观察者

//自定义内容观察者MyContentObServer
public class MyContentObServer extends ContentObserver
{

public MyContentObServer(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}

//当被观测的内容发生变化时,调用此方法
@Override
public void onChange(boolean selfChange) {

super.onChange(selfChange);

//重启Loader
getLoaderManager().restartLoader(2, null, MainActivity.this);


}

}

2,注册内容观察者

//自定义内容观察者MyContentObServer
public class MyContentObServer extends ContentObserver
{

public MyContentObServer(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}

//当被观测的内容发生变化时,调用此方法
@Override
public void onChange(boolean selfChange) {

super.onChange(selfChange);

//重启Loader
getLoaderManager().restartLoader(2, null, MainActivity.this);


}

}







第十八天


Handler 的使用


一,Android使用线程的规则:


1,UI线程不能被阻塞

2,子线程不能操作UI线程(除ProgressBar)

3,使用handler线程间的通信机制,实现子线程向UI线程发送数据


二,了解Handler的原理


Handler实现了线程间的通信的核心类:

Looper类: 循环读取MessageQueue中的Message(for(;;))


MessageQueue类:存放的是Handler发送过来的消息(Message)


Handler类:消息的发送者,又是消息的处理者

方法:
handleMessage() : 处理消息

obtainMessage() : 从消息队列中取出消息

sendEmptyMessage() : 发送的是Message中只给what属性赋值

sendEmptyMessageDelayed()

sendMessage(Message msg) : 发送Message

sendMessageDelayed() : 延迟发送消息

sendMessageAtTime() : 在当前设置的时间发送

post(Runnable) : 运行在主线程中,更新UI

postDelayed()

postAtTime()

Message类: 包装了线程间发送的数据

参数:8 个

int what : 发送空消息(状态)

int arg1

int arg2

Object obj :存放的Object类型的对象

Handler target :标签,由那个handler处理,就设为那个handler

Message sPool : 消息对象

int sPoolSize :当前内存中消息的数量

int MAX_POOL_SIZE = 50 :内存中最大的消息数量


方法:
obtain() 从消息池中取出消息

recycle() 将用完的消息对象及时回收到消息池中

setTarget(Handler target) 给每个消息对象贴标签,只有贴了标签,Looper才能知道 要传给那个Handler做处理

Handler getTarget()

sendToTarget() 把消息发送给那个handler


三,子线程向主线程发送消息


1,在主线程中实例化Handler对象,并重写handleMessage()方法,

在此方法中用于处理handler通过sendMessage()方法发送的消息


2,在子线程中,某一个合适的位置(数据加载完成) ,实例化Message对象,将相关的数据放入Message对象中



3,在子线程中发送消息:

3.1 send方法发送(3种)

handler.sendMessage(Message msg);


3.2 以post方式发送

handler.post(new Runnable(){})

这种方式,是子线程向主线程发送一段代码(代码块是在主线程中执行)





------扩展--------

计时器:

一:

Timer timer = new Timer();
//schedule(定时的任务, 第一次执行延迟的时间, 每隔多长时间执行一次)
timer.schedule(new TimerTask() {

@Override
public void run() {
// TODO 定时执行的内容(发送消息)

handler.sendEmptyMessage(1);

}
}, 0, 1000);



timer.cancel();//停止计时器


二:

ScheduledExecutorService scheduled = Executors.newSingleThreadScheduledExecutor();

scheduled.scheduleWithFixedDelay(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
handler.sendEmptyMessage(1);
}
}, 1, 1, TimeUnit.SECONDS);


scheduled.shutdowm();//停止






第十八天


Handler 的使用


一,Android使用线程的规则:


1,UI线程不能被阻塞

2,子线程不能操作UI线程(除ProgressBar)

3,使用handler线程间的通信机制,实现子线程向UI线程发送数据


二,了解Handler的原理


注意 : 一个线程只能有一个Looper对象,可以有多个Handler对象


Handler实现了线程间的通信的核心类:

Looper类: 循环读取MessageQueue中的Message(for(;;))

方法:
prepare() : 创建Looper对象

loop() : 循环读取MessageQueue中的message

myLooper() 返回子线程中的Looper对象

属性:

ThreadLocal<Looper> sThreadLocal : 本地线程的变量,能创建Looper对象

Looper sMainLooper :主线程中Looper对象

MessageQueue mQueue : 消息队列


MessageQueue类:存放的是Handler发送过来的消息(Message)


Handler类:消息的发送者,又是消息的处理者

方法:
handleMessage() : 处理消息

obtainMessage() : 从消息队列中取出消息

sendEmptyMessage() : 发送的是Message中只给what属性赋值

sendEmptyMessageDelayed()

sendMessage(Message msg) : 发送Message

sendMessageDelayed() : 延迟发送消息

sendMessageAtTime() : 在当前设置的时间发送

post(Runnable) : 运行在主线程中,更新UI

postDelayed()

postAtTime()

Message类: 包装了线程间发送的数据

参数:8 个

int what : 发送空消息(状态)

int arg1

int arg2

Object obj :存放的Object类型的对象

Handler target :标签,由那个handler处理,就设为那个handler

Message sPool : 消息对象

int sPoolSize :当前内存中消息的数量

int MAX_POOL_SIZE = 50 :内存中最大的消息数量


方法:
obtain() 从消息池中取出消息

recycle() 将用完的消息对象及时回收到消息池中

setTarget(Handler target) 给每个消息对象贴标签,只有贴了标签,Looper才能知道 要传给那个Handler做处理

Handler getTarget()

sendToTarget() 把消息发送给那个handler


三,子线程向主线程发送消息


1,在主线程中实例化Handler对象,并重写handleMessage()方法,

在此方法中用于处理handler通过sendMessage()方法发送的消息


2,在子线程中,某一个合适的位置(数据加载完成) ,实例化Message对象,将相关的数据放入Message对象中



3,在子线程中发送消息:

3.1 send方法发送(3种)

handler.sendMessage(Message msg);


方式一:

Message msg = Message.obtain();
msg.obj = bitmap;
handler.sendMessage(msg);

方式二:

Message msg = Message.obtain();
msg.obj = bitmap;
msg.setTarget(handler);
msg.sendToTarget();

方式三:

Message msg = handler.obtainMessage();
msg.obj = bitmap;
msg.sendToTarget();




3.2 以post方式发送

handler.post(new Runnable(){})

这种方式,是子线程向主线程发送一段代码(代码块是在主线程中执行)



方式四:

使用这种方法,不需要再重写handleMessage()方法

handler.post(new Runnable(){

//执行主线程赋值的操作

});



四,主线程向子线程发送消息


1,将子线程升级为Looper线程,即在子线程中创建Looper对象

Looper.perpare()方法,这个方法内部会创建一个MessageQueue对象,同时将创建的Looper保存在线程的本地变量中


2,在子线程中实例化Handler对象

new Handler()时,会判断当前的本地线程中是否存在Looper对象

3,在子线程中执行Looper.loop() 循环读取MessageQueue中的Message




五,实例 :

Day18_Handler_01 子线程向主线程发送消息的4中方式

Day18_Handler_02 图片自动播放+计时器

Day18_Handler_03 主线程向子线程发送消息

Day18_Handler_04 新闻网页


------扩展--------

计时器:

一:

Timer timer = new Timer();
//schedule(定时的任务, 第一次执行延迟的时间, 每隔多长时间执行一次)
timer.schedule(new TimerTask() {

@Override
public void run() {
// TODO 定时执行的内容(发送消息)

handler.sendEmptyMessage(1);

}
}, 0, 1000);



timer.cancel();//停止计时器


二:

ScheduledExecutorService scheduled = Executors.newSingleThreadScheduledExecutor();

scheduled.scheduleWithFixedDelay(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
handler.sendEmptyMessage(1);
}
}, 1, 1, TimeUnit.SECONDS);


scheduled.shutdowm();//停止



四大类
Handler
属性:MessageQueue -- handler讲消息发送出去实际就是放在这里
Looper--每个handler有一个looper为其不断的接受消息队列消息
CallBack--回调接收 方法handleMessage
方法:
handleMessage : 回调接口中的方法
obtainMessage:获取消息实例 本质还是调用Message.Obtain
sendMessage:
sendMessageDelayed:
sendMessageAtTime:
sendEmptyMessage:
sendEmptyMessageDelayed:
sendEmptyMessageAtTime:
post:
postDelayed:
postAiTime:
enqueueMessage:将消息压入到MessageQueue中
dispatchMessage:当looper不断的获取到消息后调用该方法分发消息触发CallBack里的handleMessage方法进行消息处理

Looper
属性:
ThreadLocal<Looper>: 本地线程变量 由于该变量保证每个线程只有一个Looper也就是说一个线程只能有一个Looper
方法:
prepare:所有的Handler 所在线程都必须有一个looper 准备好
prepareMainLooper:获取主线程中的looper对象
myLooper:从线程本地变量中获取当前线程的Looper对象
loop:循环接收消息队列中的消息

Message
属性:
what: 标记消息
arg1: 存放消息的 int
arg2: 存放消息的 int
obj: 用来存放消息的Object
data:用来存放消息属性Bundle
target:标示 Handler
sPool:消息池中的每个消息对象
sPoolSize:纪录消息池中剩余消息的数量
MAX_POOL_SIZE:消息池中的最大消息对象数量
replyTo: Messenger:自定义信使对象 跨进程

方法:
obtain: 获取Message实例
setTarget: 设置收到消息的Handler
getTarget: 获取应该收到消息的Handler
setData: 设置Bunldle对象
getData: 设置Bunldle对象
sendToTarget: 将消息发送到目标Handler对象,本质还是调用sendMessage
recycle: 往消息池中归还消息对象

MessageQueue
属性:
enqueueMessage:通过改方法将消息添加到自己的队列中
next:下一个Message



Handler 消息机制:


由于主线程(UI线程)不能访问网络,子线程不能更新UI,所以有了Handler消息传送机制用来将子线程的数据发送到主线程中来进行更新UI,在主线程中实例化Handler对象,
在子线程中将将要发送的数据 添加到Message对象中去,Message是可携带int,object,Bundle对象的,通过handler调用handler.sendMessage方法将消息发送出去,
这个时候消息会进入到消息队列MessageQueue 中去,MessageQueue 是个消息队列,enqueueMessage方法讲消息添加到队列中,looper提供了消息运转的动力,
每个线程只允许有一个looper,消息在MessageQueue中不断的一个一个的做进栈出栈动作,handler调用dispatchMessage方法对MessageQueue中出来Message进行分发
,分发根据的是target(Handler),而dispatchMessage方法执行的就是一个CallBack回调方法,也就是主线程中用来接收消息的的handleMessage方法,
这样主线程就可以对接收到的数据进行处理了。




第十九天


一,ActionBar

1,说明

ActionBar上Android3.0 后引入的,显示在标题栏上,创建的方式和菜单是相同的。

与菜单的主要区别是:showAsAction属性





2,ActionBar动作项(Item)显示的属性


showAsAction:

ifRoom : 如果标题栏有空间,则会显示动作项的图标

always :不管有没有空间,都会显示在标题栏

withText:带有文本信息显示

collapseActionView :可以被折叠的,单用户点击按钮时,这个操作视图才会被展开




3,创建ActionBar显示的动作项

3.1 在res/menu/目录下创建菜单资源,再声明<item>时必须声明显示属性(showAsAction)和图标属性(android:icon)

3.2 在Activity类中,重写onCreateOptionsMenu()方法,加载菜单资源

3.3 重写onOptionsItemSelected()方法,来处理ActionBar中的每个Action项的点击事件


4,分割栏操作:

API 14以上

在<application>或<activity>元素中添加android:uiOptions="splitActionBarWhenNarrow" 属性设置


5,启动程序导航图标

5.1 作用: 让APP的Logo也变成可点击的图标

5.2 getActionBar() 获取当前Activity的ActionBar对象

5.3
//设置是否显示Logo的图标
getActionBar().setDisplayShowHomeEnabled(true);

//设置是否将Logo图标作为可点击的按钮,并且在图标的前面添加一个向左的箭头
getActionBar().setDisplayHomeAsUpEnabled(true);


5.4 android.R.id.home://应用导航图标的ID


6,ActionView的使用

作用:可以编辑的动作项,如:searchView可以直接显示在ActionBar中


方式:

1,actionViewClass属性,指定实现CollapsibleActionView的子类

2,actionLayout属性,可以指定一个布局文件




二,ActionBar+Fragment


ActionBarTab 导航 : 通常通过选项标签切换Fragment


1,获取当前Activity的ActionBar对象(getActionBar()),并设置导航模式为TABS


2,在当前Activity中,实现ActionBar.TabListener接口(重写3个方法)


3,增加ActionBar.Tab 到ActionBar中

ActionBar.Tab tab = actionBar.newTab();

setText() 设置Tab显示的文本

setIcon() 设置Tab显示的图标

setTabListener() 设置Tab的监听


actionBar.addTab(tab,true);//第二个参数:默认选中的Tab项




第二十天

ViewPager


一,特点: 可以左右滑动的控件,需要PagerAdapter配合使用,由V4包



二,类名:android.support.v4.view.ViewPager;


三,使用步骤

1,在布局文件中使用<android.support.v4.view.ViewPager>标签


2,在代码中增加显示的页面


3,在Activity中实例化ViewPager组件,并设置适配器(PagerAdapter)




四:V4 包下Fragment


1,创建Fragment的子类,继承Fragment(V4包下)


2,Activity必须继承FragmentActivity(V4包下)


3,FragmentManager manager = getSupportFragmentManager();





第二十一天

案例
<不推荐使用方法>
一、TabHost+Activity 方法实现
二、ActionBar+Fragment 方法实现
三、ActionBar+ViewPager 方法实现
四、FragmentTabHost + Fragment 方法实现 ----√

<推荐使用方法>

五、ViewPager+PagerTabStrip+Fragment 方法实现√
六、RadioGroup+Fragment 方法实现 √
七、RadioGroup+ViewPager+Fragment 方法实现 √
八、HorizontalScrollView+Linearlayout+ViewPager 方法实现√

作业!
使用java代码方式写布局计算器





第二十二天



* 广播: 全局性的 ,系统级别的 消息传递机制
*
* 广播的三要素:
* 1.发送方 Context.sendBroadCast
* 2.发送内容 Intent
* 3.广播接收者 BroadCastReceiver
*
* 广播根据注册方式不同分为
* 静态注册
* 在清单文件中 <application> 标签下 添加<receiver> 标签 并 添加IntentFilter 及其 action 属性
* 动态注册
* 在 Activity 中 实例化 MyReceiver 对象 ,再定义一个 IntentFilter 对象 添加Action 属性
* 调用 registeReceiver方法 注册 同时 需要在 onDestory方法中调用 unRegisterReceiver方法 解除注册
*
* 静态注册与动态注册的区别:
* 1.动态注册的接收效率要比静态注册的稍高一些
* 2.静态注册的时候,app 退出 activity 的销毁 都不会影响广播接收者的接收
* 3.动态注册的时候,如果当前Activity 销毁 则不会再接收到广播
*
* 关键:
* 定义action
* 发送方的Intent 定义action(可以理解为一个频道)
* 所有存在于该频道的Receiver都能接收到这个频道的消息
*
* 发送方定义了action 所有的接收方(receiver) 只要都设置了这个action 就都能接收到 这个广播
*
* 广播的生命周期:
* 从接收方 onReceive方法 执行开始 当前的广播接收者有10s的活跃期 这个阶段 不会受到任何的影响,10s过后处于 失活状态
* 这个时候如果有系统进程需要内存空间,则,该广播接收者有可能会被回收,所以 如果需要在该方法中执行延时操作,需要开启一个衍生线程(子线程)来
* 完成这样的工作
*
* 广播实现步骤:
* 1.定义发送
* 2.定义发送的action --定义的时候一般定义为 包名+广播接收者的类名 (按照需求其名称 标准即可)
* 3.发送广播
* 4.定义广播接收者
* 5.注册广播接收者
* 动态
* 静态


有序广播
* 根据优先级 来决定广播接收者 接收广播的顺序
* 发送广播的方法 : sendOrderBroadCast
* 第二个参数 是权限名称 不需要的时候为 null
*
* 需要在注册的时候 添加优先级 (优先级 属性在 IntentFalter 标签内部 proprity 该属性)
* 取值范围 -1000 到 +1000 数值越大 优先级越高 会先接收到广播
*
* 所有的广播接收者不可更改 发送方发送出来的Intent
*
* 如果需要广播接收者之间传递数据
* 可使用 setResultExtra(Bundle) 方法
* 接收方 getResultExtras( boolean)
* 如果 boolean 为false 则 直接返回 传递对象 可为Bundle 可为null
* 如果boolean 为true 则 一定会返回 bundle 对象 但是 可能有值 可能 没有键值
*
* 只有优先级高的 可以向优先级低的传递数据
*
*拦截有序广播的方法
* abortBroadCast()
* 拦截后 ,所有优先级比当前优先级低的广播 都将不再接收到 广播



第二十三天

* Service: 服务
* 服务像Windows后台服务一样,服务是在后台运行,悄悄的承担着不为人知的一些工作
* Service 在后台运行,他是不可见的、无界面的程序
*
* 没有页面的程序 应用场景:播放音乐,下载 ,定位等
*
* 概念:
* 1.Service运行在后台不可与用户进行交互
* 2.服务不是一个单独的进程 ,服务对象本身并不是在自己的进程中运行。
* 3.服务不是一个线程,服务Service 与其他的组件一样,默认的代码是执行在主线程中的
* 4.需要一个上下文对象来启动服务
*
* Service 很大程度上承担了后台线程管理的角色:在Activity中开启一个线程,当Activity销毁后,Thread会继续工作,
* 但是与开启它的Activity 失去了联系,也就是说当前线程处于无人管理的状态,但是Service 可以有效的对后台线程进行管理
*
* Service比线程的优点:
* 1.Service 可以放在独立的进程中,所以更安全
* 2.系统可以重启被异常杀死的Service
* 3.Service可以依赖现有的Binder 机制(明天讲)
*
* Service与Activity的关系
* 1.相同点:都是四大组件,都需要在清单文件中注册,都具有一定的生命周期
* 2.不同点:Acitivty 存在着与用户交互的页面,Service 在后台运行
*
* 分类:本地服务LocalService 与远程服务 RemoteService
* A:本地服务 LocalService
* 根据启动模式分为两种:
* 1.startService(Intent)
* 被启动的服务是通过其他的组件(Activity或BroadCast)调用startService 方法启动的。该方法会导致Service 的生命周期中
* onCreate与onStartCommand方法执行,当Service 启动后,则与他的调用者的生命周期无关,即便调用者已经被销毁。Service 也会
* 一直存在,在后台执行,除非调用了stopService 或者stopSelf
* 2.bindService(。。。)(明天讲)
*
* Service 的生命周期:
*
* onCreat 服务被创建
* onStartCommand 服务开始执行
* onDestory 服务被销毁
*
* 说明:
* 1.当调用startService 方法后,服务会执行 onCreate onStartCommand 方法 ,此时服务处于is Running状态
* 2.如果服务已经被创建 则再次调用startService 方法,服务只会执行onStartCommand 方法,如果没有被创建,则执行onCreate onStartCommand方法
* 3.如果调用了stopService 或者 stopSelf方法 服务会执行onDestory 方法 销毁
* 4.所以 Service 的生命周期为 onCreat --->onStartCommand (可以被多次调用)--->onDestory
*
* onStartCommand方法:
* 根据返回值划分:
* 1. START_STIKEY:粘性的 常量为 1
* 如果服务被异常杀死 服务会被重新启动,但是Intent 值为null
* 2. START_NO_STIKEY :非粘性的 常量为 2
* 如果服务被异常杀死 服务不会被重新启动
* 3. STRAT_REDELIVER_INTENT 常量为 3
* 如果服务被异常杀死,服务会被重启,且Intent 有值

* B 远程服务 RemoteService(接下来讲)
* C IntentService(接下来讲)



第二十四天
* 绑定服务
*
* 绑定服务是允许其它应用程序绑定并且与之交互的Service的实现类。为了提供绑定,必须实现onBind()回调方法。
* 该方法返回IBinder对象,它定义了服务类与Activity交互的程序接口
*
*
* Activity通过bindService()方法绑定到服务类,同时Activity必须提供ServiceConnection接口的实现类,
* 它监视Activity与服务类之间的连接。在重写ServiceConnection接口的onServiceConnected()方法时,
* 实现了将服务类顺利赋值到了Activity中,实现了在Activity中使用该服务类并执行其中的方法
*
*
* 同一个Service可以绑定多个服务链接,这样可以同时为多个不同的组件提供服务 全部组件关闭后 他会关闭
*
* 作用
*
* 作用是在Service和调用者之 间建立一个桥梁,并不负责更多的工作(例如一个Service需要连接服务器 的操作),
* 一般使用bindService来绑定到一个现有的Service(即通过 StartService启动的服务)
*
* 生命周期 onCreate():创建服务 onBind():绑定服务,服务开始运行 onUnbind():取消绑定 onDestroy() :服务被停止
*
* 在程序中调用:context.bindService()会触发执行Service生命周期中的onCreate()、onBind()回调方法,
* 此时服务开始运行
*
* onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。
* 此后调用者(Context,例如Activity)会和Service绑定在一起
*
* 如果调用Service的调用者Context退出了,那么会依次调用Service生命周期中的onUnbind()、onDestroy()回调方法,
* 会让服务停止
*
* 所以BindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind -->
* onDestory


文件存储

临时存储
内存
持久化存储

内部存储
data-data-包名-/

1.cache 缓存
2.file 文件
3.database 数据库
4.shared_pref .xml sharedpreference 存储

Context.getCacheDir();
Context.getFileDir();
...

data-app
存放的都是apk 文件
真机可能需要root 权限才能看到


SD卡(外部存储)
1.判断是否存在SD卡 (挂载)
Environment.getExternalStorageState();
2.获取SD卡的根目录
Environment.getExternalStorageDirectory();
3.获取9大公有目录的路径
Environment.getExternalStoragePublicDirectory(TYPE);Environment.XXX

File.separator 分隔符

SD中的私有目录:
Android-data-包名- files
cache
//获取SD卡中私有目录的路径方法
Context.getExternalCacheDir();
Context.getExternalFilesDir();





//现成的文件引用工具类


package com.steven.helper;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;

public class SDCardHelper {

// 判断SD卡是否被挂载
public static boolean isSDCardMounted() {
// return Environment.getExternalStorageState().equals("mounted");
return Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
}

// 获取SD卡的根目录
public static String getSDCardBaseDir() {
if (isSDCardMounted()) {
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
return null;
}

// 获取SD卡的完整空间大小,返回MB
public static long getSDCardSize() {
if (isSDCardMounted()) {
StatFs fs = new StatFs(getSDCardBaseDir());
long count = fs.getBlockCountLong();
long size = fs.getBlockSizeLong();
return count * size / 1024 / 1024;
}
return 0;
}

// 获取SD卡的剩余空间大小
public static long getSDCardFreeSize() {
if (isSDCardMounted()) {
StatFs fs = new StatFs(getSDCardBaseDir());
long count = fs.getFreeBlocksLong();
long size = fs.getBlockSizeLong();
return count * size / 1024 / 1024;
}
return 0;
}

// 获取SD卡的可用空间大小
public static long getSDCardAvailableSize() {
if (isSDCardMounted()) {
StatFs fs = new StatFs(getSDCardBaseDir());
long count = fs.getAvailableBlocksLong();
long size = fs.getBlockSizeLong();
return count * size / 1024 / 1024;
}
return 0;
}

// 往SD卡的公有目录下保存文件
public static boolean saveFileToSDCardPublicDir(byte[] data, String type,
String fileName) {
BufferedOutputStream bos = null;
if (isSDCardMounted()) {
File file = Environment.getExternalStoragePublicDirectory(type);
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}

// 往SD卡的自定义目录下保存文件
public static boolean saveFileToSDCardCustomDir(byte[] data, String dir,
String fileName) {
BufferedOutputStream bos = null;
if (isSDCardMounted()) {
File file = new File(getSDCardBaseDir() + File.separator + dir);
if (!file.exists()) {
file.mkdirs();// 递归创建自定义目录
}
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}

// 往SD卡的私有Files目录下保存文件
public static boolean saveFileToSDCardPrivateFilesDir(byte[] data,
String type, String fileName, Context context) {
BufferedOutputStream bos = null;
if (isSDCardMounted()) {
File file = context.getExternalFilesDir(type);
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}

// 往SD卡的私有Cache目录下保存文件
public static boolean saveFileToSDCardPrivateCacheDir(byte[] data,
String fileName, Context context) {
BufferedOutputStream bos = null;
if (isSDCardMounted()) {
File file = context.getExternalCacheDir();
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}

// 保存bitmap图片到SDCard的私有Cache目录
public static boolean saveBitmapToSDCardPrivateCacheDir(Bitmap bitmap,
String fileName, Context context) {
if (isSDCardMounted()) {
BufferedOutputStream bos = null;
// 获取私有的Cache缓存目录
File file = context.getExternalCacheDir();

try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
if (fileName != null
&& (fileName.contains(".png") || fileName
.contains(".PNG"))) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
} else {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
}
bos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
} else {
return false;
}
}

// 从SD卡获取文件
public static byte[] loadFileFromSDCard(String fileDir) {
BufferedInputStream bis = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();

try {
bis = new BufferedInputStream(
new FileInputStream(new File(fileDir)));
byte[] buffer = new byte[8 * 1024];
int c = 0;
while ((c = bis.read(buffer)) != -1) {
baos.write(buffer, 0, c);
baos.flush();
}
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
baos.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}

// 从SDCard中寻找指定目录下的文件,返回Bitmap
public Bitmap loadBitmapFromSDCard(String filePath) {
byte[] data = loadFileFromSDCard(filePath);
if (data != null) {
Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
if (bm != null) {
return bm;
}
}
return null;
}

// 获取SD卡公有目录的路径
public static String getSDCardPublicDir(String type) {
return Environment.getExternalStoragePublicDirectory(type).toString();
}

// 获取SD卡私有Cache目录的路径
public static String getSDCardPrivateCacheDir(Context context) {
return context.getExternalCacheDir().getAbsolutePath();
}

// 获取SD卡私有Files目录的路径
public static String getSDCardPrivateFilesDir(Context context, String type) {
return context.getExternalFilesDir(type).getAbsolutePath();
}

public static boolean isFileExist(String filePath) {
File file = new File(filePath);
return file.isFile();
}

// 从sdcard中删除文件
public static boolean removeFileFromSDCard(String filePath) {
File file = new File(filePath);
if (file.exists()) {
try {
file.delete();
return true;
} catch (Exception e) {
return false;
}
} else {
return false;
}
}
}




第二十五天
远程服务
* 跨进程通信
* AIDL
*安卓接口定义语言
* android interface definition language
*
* 1.在服务端创建接口文件 .aidl
* 2. 在服务端将该接口实例返回
* 3.客户端需要将 服务端的.aidl文件所在 的包连同文件copy 到 客户端
* 4.客户端拿到接口实例,调用接口的方法




第二十六天
Android:
补间动画 :补充开始和结束中间的动画效果,支持 位移,缩放,透明度,旋转
属性动画 :通过改变对象的属性起始及结束的值来执行动画
帧动画 :多个图片连续播放 ,一帧一帧的 类似GIF 图

补间动画
实现方式:
1.通过xml代码方式
在res文件夹下创建 anim 文件夹 创建xml文件
2.通过java代码方式
Animation 子类: AlphaAnimation TranslateAnimation RotateAnimation ScaleAnimation AnimationSet


属性动画:
实现方式
1.通过xml代码方式:
在res文件夹下创建animator文件夹 创建xml文件
2.通过Java代码方式
ObjectAnimator 根据属性名称决定动画执行种类
属性名称:
alpha

rotation

rotationX

rotationY

translationX

translationY

scaleY

scaleX

帧动画:
实现方式
1.通过xml 设置
在res文件夹下创建drawable文件夹下 创建 根标签为 animation-list 的xml文件
2.通过Java代码方式
AnimationDrawable 类



第二十七天

屏幕适配
重要的概念:
一、屏幕尺寸:
屏幕对角线的长度 单位 英寸 1英寸 = 2.54cm
二、屏幕的分辨率:
屏幕宽高的像素点数 单位是 px像素
一些主流机型的分辨率: 1280×720 1920×1080 2560×1440
三、屏幕像素密度:
屏幕每英寸所含像素点数
四、dpi
单位 -- 屏幕像素密度的单位
五、px
单位 -- 像素的单位
六、sp
单位 -- 描述字体大小的单位
七、dp(dip)
独立的像素密度,与密度无关的像素
dp = px × 比例
比例 根据屏幕像素密度的不同而改变 如果屏幕的像素密度为160 dpi 则 dp与px 1:1 如果像素密度为 240dpi 则dp:px = 1:1.5 等等


适配的方案:
一、多套图片
制作多套分辨率不同的图片 来放在res 文件夹下不同的drawable资源文件夹下 ,系统会根据当前屏幕的像素密度的不同来
分别加载不同文件夹下的资源
注意:相同的图片在不同的文件夹下 名字必须一致
如果只有一套图片,则默认放在hdpi文件夹下 ,因为 系统加载该文件夹下的文件消耗最小
多套图片:不是所有的图片都需要做多套图片 一般情况下 最需要做多套图片的是 logo
二、多使用线性布局与相对布局 禁用绝对布局
使用 wrap_content match_parent weight 确保灵活使用并适应各种布局
三、布局
通过添加修饰符来加载不同的布局文件
layout-land 横向屏幕 加载该文件夹下的文件
了解
layout-small 屏幕尺寸小于3英寸左右的屏幕
layout-normal 屏幕尺寸小于4.5英寸左右的屏幕
layout-large 4英寸到7英寸之间
layout-xlarge 大于7英寸小于 11英寸
四、dimention
使用资源文件 values
新建文件夹 values-1377x899 命名规范: values 加上中横线 - 在加上屏幕分辨率中数大的 1377 加上小x 再加上屏幕分辨率 数小的 899
在该文件夹下 添加 文件 dimens.xml
使用方法与 values - dimens.xml 一样
在新建文件夹下的dimens文件中创建的值必须在 values 文件夹下 添加默认值
了解
values-small
values-normal
values-large
values-xlarge

sw<600> 最小宽度大于600 的屏幕
五、代码适配方案
通过 DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
获取屏幕宽度
定义基础宽度,计算获取到的屏幕宽度与基础宽度的比例
拿到比例后 计算每个View 的位置及大小 进行等比例缩放
所有单位为像素px 必须使用java代码的方式写布局
六、点9图片
工具路径:sdk/tools/draw9path.bat
可拉抻的图片
七、清单文件 中
supports-screens
anyDensity = true 支持任何像素密度的屏幕 默认就是支持的
八、国际化语言
创建 values文件夹 values - 加上国家缩写
在文件夹中创建string.xml 文件 将语言进行国际化转换
注意 在新建文件夹中 添加的 字符串必须在 values文件夹下 的string 里建立默认值
九、SDK 版本适配



UI美化
一、Style
Style 风格样式
适用于 View
定义后可以通过 parent 属性或 直接style 的名称加上点.再加上子类名称的方式进行继承
子类拥有父类的所有属性
并且可以更改 更改后以子类的为基准
如果 xml使用过程中再次修改属性
以xml的为准
二、Theme
Theme 主题样式
适用于 Applicaton activity
如果activity 设置了 theme 则设置了该主题的activity会覆盖application的主题
一般这里只是用两种
1 .Theme.NoTitleBar.Fullscreen
2. Theme.NoTitleBar
三、selector
选择器
state_focused 焦点 是否聚焦 EditText Search
state_enabled 能够接受点击或触摸事件 button textView
state_checkable 是否可以被选中 CheckBox RadioButton
state_selected 选中 spinner listView
state_pressed 按下 Button
四、shape
形状
属性参数 :
corners: 角度 五个属性同时设置 radius无效
gradient : 渐变 与solid同时设置 无效
stroke: 边框 虚线边框 dashWidth dashGap
solid : 填充 颜色 与gradient设置 时 gradient 无效
五、level-list
等级
<item
android:drawable="@drawable/wifi1"
android:maxLevel="10"
android:minLevel="5"/>

包含maxLevel 不包含minLevel
使用时 必须设置为IamgeView 的src 属性
一般用于 wifi信号 手机sim卡信号 电池电量信号 移动数据信号等
六、layer-list
叠加图片在 一个ImageView里



第二十八天
format 可以用|来同时使用
1、reference 参考某一资源Id
2、color 颜色值
3、boolean 布尔值
4、dimension 尺寸值(带有单位的 sp/dp)
5、float 浮点型
6、integer 整形
7、string 字符串
8、fraction 百分比
9、enum 枚举
10、flag 位或运算

第二十八天——————之后见项目


/////////////////////////////////////////////////////////////////////////////////////////
第八周,高级第一周(第三方Jar包的应用)

1,volley

jsonString:
StringRequest
JsonArrayRequest
jsonObjectRequest
自定义

步骤:1,得到queue 队列 2,请求 3,请求添加到队列 4,设置取消标记 5,进行取消

图片:
ImageRequest
ImageLoader :1,获取ImageLoader 对象 2,获取ImageListener 3,get(Url,iamgeListener)
NetworkImage :1,在布局中添加 2,获取ImageLoader 3,setImageUrl(Url,imagloder)

2,Xutils

ViewUtils :1,注入注解工具 2,可以进行注入 3类: 资源 控件 事件
HttpUtils :get /post / 下载
BtmapUtils : 本地图片 网络图片 display(控件 地址 )
DbUtils : 创建数据库 数据库升级 创建数据库表 增删改查

3,PullToRefresh:刷新控件
1,导入jar
2,在布局中添加刷新控件
3,进行设置
4,进行监听
5,下载完成 进行关闭
swipeRefreshLayout
1,在布局中添加
2,进行设置 背景 进度颜色
3,进行监听'
4,进行关闭
4,SlidingMenu: 主视图 被菜单 推出屏幕
1,导包
2,在布局中添加
3,进行设置
对布局里的控件 查找出来 进行监听


drawerLayout: 主视图 被菜单 覆盖
1,布局中 添加菜单
第一个子元素 :主视图 匹配父控件
第二个子元素 :菜单 不能设置大于320dp layout_grivat
5,OkHttp
高效的下载库
get /post

同步 和异步

1,获取OKHttpClient对象
2,获取Request对象
3,通过OKHttpClient对象调用 newCall() 将 Request对象 变成Call任务
4,启动任务 (同步 和异步)
6,Picasso

1,导包
2,一行代码就ok
Picasso.with(Context).load().into(控件)
图片的设置 需要在 into之前调用


7、RecyclerView


9、感应器;例:微信摇一摇的实现



第一天


1、LinearLayout,线性布局
vertically :垂直,纵向
horizontally:水平,横向

a:方向,默认横向
android:orientation="horizontal"
horizontal,在水平方向上一个挨着一个
vertical,在垂直方向上一个挨着一个

b:控件的宽,高
android:layout_width="fill_parent":宽
android:layout_height="fill_parent":高

fill_parent/match_parent:匹配父控件
wrap_content:包裹内容物
固定值:100dp

c:单位
dp:表示非文字大小的尺寸
sp:设置文字大小

d:设置背景颜色 或 背景图片
android:background="#ff0000"
android:background="#f00"

使用RGB三原色设置背景颜色
ARGB,A:alpha,带透明度的三原色
Color.rbg();
Color.arbg();

完全透明:#00~~~
完全不透明:#ff~~~

设置背景图片:
android:background="@drawable/img001"
@drawable/img001:访问图片的资源文件

e:边距
内边距:控件内部,内容与边框的距离
android:padding:四个方向
paddingleft,rigth,top,bottom

外边距:控件之间的距离
android:layout_margin:四个方向
layout_marginLeft,right,top,bottom

f:
android:gravity:设置View中内容的位置
1).设置在布局节点(LinearLayout),指定布局中控件的位置
2).设置在控件中(Button,TextView……),指定控件中文字的位置
android:gravity="right|bottom",右下角

android:layout_gravity:控件相对于容器的位置,使用在控件中
在横向布局中,设置为right失效
在纵向布局中,设置bottom失效

g:
android:weight:设置权重,在横向或纵向上,控件占用空间的比例
默认权重为0

在横向布局中,设置android:layout_width="0dp"
在纵向布局中,设置android:layout_height="0dp"

h:
android:id,设置控件的id,给控件起个名字,可以在应用中使用名字获得该控件
android:id="@+id/mTextView",
可以理解为:在R文件中新增控件,名为mTextView

通过id获得控件
mTextView = (TextView) findViewById(R.id.mTextView);


2,FrameLayout:帧布局
在屏幕的某个区域可以添加多个控件,最近(最后)添加的显示在最上方

重点:
id
width
height

边距:padding,margin

weight:权重

gravity
layout_gravity




RelativeLayout相对布局

a:控件与布局之间的对齐方式,值为true
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"

android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"

b:兄弟控件之间的相对位置,值为另外一个控件的id,不能设置第一个控件的左方和上方
android:layout_above="@id/tv1"
android:layout_below="@id/tv1"
android:layout_toLeftOf="@id/tv1"
android:layout_toRightOf="@id/tv1"


c:兄弟控件之间的对齐方式,值为另外一个控件的id
android:layout_alignLeft="@id/tv1"
android:layout_alignRight="@id/tv1"
android:layout_alignTop="@id/tv1"
android:layout_alignBottom="@id/tv1"

d:基准线对齐,本控件文字的底边与目标控件文字的底边对齐
android:layout_alignBaseLine




第二天
复习:
1、LinearLayout,线性布局
android:orientation
horizontal
vertical

2、
android:layout_width
android:layout_height

fill_parent,match_parent
wrap_content
固定值:100dp

3、background,背景颜色 和 背景图片
RGB
ARGB

@drawable/img

4、边距:
内边距:padding
外边距:margin

5、gravity:
layout_gravity:

6.weight:权重,默认0
水平布局,layout_width="0dp"
垂直布局,layout_height="0dp"

7.FrameLayout,帧布局

本课内容:
1、RelativeLayout,相对布局

参考文档

2、GridLayout,网格布局
与线性布局类似,需要指定控件的方向
android:orientation= horizontal 或 vertical

指定行数和列数
android:rowCount="5":行数
android:columnCount="4":列数

合并单元格
android:layout_rowSpan="2",跨行合并
android:layout_columnSpan="2",跨列合并

合并之后应该进行填充
android:layout_gravity="fill_vertical",fill,fill_horiaontal

网格中的单元格可以通过索引访问,索引从0开始

指定控件在网格中显示的位置
android:layout_row="0"
android:layout_column="3"

3.TextView:用于显示文本

android:text="@string/textView":设置文本内容
android:textSize="30sp":大小
android:textColor="#f00":颜色
android:textStyle="bold|italic":样式

android:autoLink="web",设置链接,phone,email,map,all

android:singleLine="true":单行显示,默认在末尾加...

android:marqueeRepeatLimit="marquee_forever",设置滚动的次数,
android:focusable="true",是否获得焦点
android:focusableInTouchMode="true",以触摸的形式获得焦点

4.EditText:用于输入文本,获得光标时,显示不同的软键盘
是TextView的子类

android:hint:设置提示
android:inputType:设置输入的类型,弹出的软键盘不同

5、Button
添加按钮的单击事件
a:创建子类(内部类),实现android.view.View.OnClickListener接口,重写onClick方法
b:匿名内部类
c:在布局文件中,Button标签添加onClick属性,属性值为方法名
该方法声明要求:
public void 方法名(view v){}

多个按钮处理单击事件
a:实现android.view.View.OnClickListener接口,重写方法
1).创建子类
2).MainActivity实现接口
b:在Button标签中添加onClick属性,设置方法名

switch判断具体的按钮

6、Toast,吐司
// 1.上下文;2.显示文本;3.显示的时间
Toast.makeText(this, "button1", Toast.LENGTH_LONG).show();
注:一定要有show()方法

7、查看logCat日志信息
verbose:啰嗦的,琐碎的,冗长的
Log.v(),级别最低的一个,显示全部信息
debug:显示调试信息
Log.d()
info:显示重要的调试信息,异常
Log.i()
warn:显示警告信息
Log.w()
error:显示错误信息
Log.e()

8.RadioButton,单选按钮
保证单选按钮互斥访问,成为单选按钮,需要使用RadioGroup

默认选中:android:checked="true"

单击事件
a:在RadioButton标签中添加onClick属性
b:给RadioGroup注册监听,实现接口android.widget.RadioGroup.OnCheckedChangeListener

c: 获得选中的RadioButton的id
int id = rg.getCheckedRadioButtonId();

预习:
checkBox
ImageView








第三天

复习:
1、RelativeLayout,相对布局
16个属性

7个相对于布局
4个兄弟节点之间的相对位置
4个兄弟节点之间的对齐方式
1个基准线对齐

2.GridLayout,网格布局
方向,android:orientation

行数,rowcount
列数,columnCount

跨行合并,rowSpan
跨列合并,columnSpan
layout_gravity=“fill”

通过索引访问单元格,0起始
layout_row
layout_column

3.TextView

4.EditText,可编辑的
hint
inputType

5.Button,
单击事件,
a:OnClickListener
b:onClick="send"

public void send(View v){}

6.RadioButton
RadioGroup保证可单选

事件
a:RadioButton,onclick
b:RadioGroup,设置监听,onCheckedChangeListener


i18n: internationalization,国际化
本课内容:
1、CheckBox
事件
a:在CheckBox标签中添加onClick属性
b:使用onCheckedChangeListener

2.ImageView,显示图片

android:src="@drawable/bg04",指定显示的图片资源

三个属性搭配使用,调整图片的宽高,保证图片的宽高比例
android:adjustViewBounds="true",是否调整ImageView的边界来保持宽高比例
android:maxWidth="100dp",最大宽度
android:maxHeight="300dp",最大高度

android:cropToPadding="true",是否截取图片指定的区域使用空白来替代
android:scrollX="15dp",x轴方向截取
android:scrollY="17dp",y轴方向截取
//反向截取
android:scrollX="-15dp",x轴方向截取
android:scrollY="-17dp",y轴方向截取

android:tint="#f00",使用指定的颜色渲染图片
android:alpha="0.5f",设置透明度


android:scaleType="",设置裁剪的类型

matrix:保持图片原大小显示,从左上角开始显示

fitStart:保持横纵比例缩放图片,并将图片放到ImageView的左上角

fitEnd:保持横纵比例缩放图片,并将图片放到ImageView的右下角

fitCenter:保持横纵比例缩放图片,并将图片放到ImageView的中间

fitXY:横向,纵向独立缩放图片,适应Imageview的大小,不保持原来图片的比例,填充ImageView

center:不进行任何缩放,将图片放到ImageView的中央,如果图片大于ImageView,截取中间部分显示

centerCrop:保持横纵比例缩放图片,使图片覆盖ImageView,以图片和ImageView的中心为基准点,进行缩放,直到图片最小的某方向等于ImageView的某边(某一方向的长宽等于ImageView,另一方向大于ImageView),进行截取

centerInside:保持横纵比例缩放图片,使ImageView能完全显示图片,以图片和ImageView的中心为基准点,进行缩放,显示图片内容,如果图片小于ImageView,不进行缩放,居中显示;如果图片大于Imageview,进行缩放,居中显示


3、AutoCompleteTextView

控件
适配器(adapter:ArrayAdapter,SimpleAdapter,BaseAdapter……)
数据源

适配器作用:实现数据源和控件的关联





第四天
复习:
1.CheckBox
事件
a:onClick
b:onCheckedChangeListener

2.ImageView
src="@drawable/bg"
iv.setImageResource(resId);

scaleType
tint
alpha

3.ToggleButton Switch

4.AutoCompleteTextView

适配器:ArrayAdapter,数据源是集合或数组


本课内容:
1、Spinner:下拉列表

在布局文件中,Spinner标签添加属性,与字符串数组资源关联
android:entries="@array/planets_array"(关联的资源是res文件夹下的values文件夹中string中的string_array)

给Spinner添加事件,实现接口是OnItemSelectedListener
注意:注册监听器

代码详见案例。

2、解析xml文件,首先在res下创建xml文件夹,放置xml文件

xml解析获得标签属性值:parser.getAttributeValue(null,"cityname")//null:固定值;cityname:属性的名字
3、ArrayAdapter,数据源是集合或数组

更新适配器:adapter.notifyDataSetChanged();
4、获取当前时间
安卓控件
http://www.cnblogs.com/menlsh/archive/2013/02/23/2923867.html
方法一
Calendar c = Calendar.getInstance();
取得系统日期:year = c.get(Calendar.YEAR)
month = c.grt(Calendar.MONTH)
day = c.get(Calendar.DAY_OF_MONTH)
取得系统时间:hour = c.get(Calendar.HOUR_OF_DAY);
minute = c.get(Calendar.MINUTE)


方法二
TextView myTextView = (TextView)findViewById(R.id.myTextView);
Time time = new Time("GMT+8");
time.setToNow();
int year = time.year;
int month = time.month;
int day = time.monthDay;
int minute = time.minute;
int hour = time.hour;
int sec = time.second;
myTextView.setText("当前时间为:" + year +
"年 " + month +
"月 " + day +
"日 " + hour +
"时 " + minute +
"分 " + sec +
"秒");





第五天

1、Activity,四大组件之一,创建成功之后,都需要在清单文件中进行注册
可以认为是应用程序的页面

创建Activity
a:创建子类继承Activity,重写onCreate方法
b:创建布局文件
c:在清单文件中进行注册

2、Intent,意图
启动Activity
方法1:
Intent intent = new Intent();
// 1.上下文,代表当前Activity
// 2.代表跳转的目的页面,传递的是Class类型的对象
intent.setClass(MainActivity.this, NextActivity.class);
// 启动意图
startActivity(intent);

方法2:
Intent intent = new Intent(MainActivity.this, NextActivity.class);
// 启动意图
startActivity(intent);

3、Intent传值
a:
A页面:Intent对象使用putExtra方法封装名值对
B页面:首先获得意图(getIntent())
之后使用相应的get***Extra()方法获得值

b:
A页面:创建Bundle对象,封装数据,之后将Bundle对象再封装到Intent中
Bundle bundle = new Bundle();
bundle.putString("sex", "male");
bundle.putInt("weight", 65);
intent.putExtra("bundle", bundle);
B页面:首先获得Bundle对象,获得Bundle封装的数据
Bundle bundle = intent.getBundleExtra("bundle");
String sex = bundle.getString("sex");
int weight = bundle.getInt("weight");

c:
A页面:使用Bundle对象封装数据
intent.putExtras(bundle);
B页面:获得Bundle对象,可以获得前一个页面使用putExtra方法封装的名值对
Bundle bundle = intent.getExtras();

d:传递对象,要求对象可序列化
A页面:封装对象
Person person = new Person("jack", 21);
intent.putExtra("person", person);
或者
bundle.putSerializable("person", person);

B页面;获得对象
Person person = (Person) intent.getSerializableExtra("person");
或者
Person person = (Person) bundle.getSerializable("person");


4.StartActivityForResult
跳转到下一个页面并返回结果

A页面,使用StartActivityForResult启动下一个页面
在onActivityResult方法中获得返回值
B页面,获得Intent(getIntent()),封装数据
// 设置响应码和Intent对象
setResult(2, intent);
// 结束Activity的生命周期
finish();

shutdown -s -t 60 -c
at 12:00 shutdown -s -t

5.Activity生命周期
方法有7个,是系统调用的
onCreate():创建并初始化Activity时使用
onStart():显示页面
onResume():获取用户焦点,与用户进行交互

onPause();失去焦点,暂停与用户的交互
onStop():关闭页面,处于后台运行
onDestroy():销毁页面

onRestart():页面重新启动并显示,级联调用onStart-onResume

6、分析生命周期
a:启动Activity,onCreate-onStart-onResume
b:当前Activity被其他Activity覆盖(第二个页面以对话框形式显示) 或 锁屏:onPause
当前Acitvity回到前台显示 或 解锁:onResume
c:跳转到新的Activity 或 按HOme键:onPause-onStop

d:按回退 或 再运行应用:onRestart-onStart-onResume

e:当b,c两种情况,当前Activity已经不可用,如果系统资源不足,将杀死当前的Activity
f:当用户退出Activity,onPause-onStop-onDestroy

8、生命周期的阶段
完整生命周期:onCreate-onDestroy
可见声明周期:onStart-onStop
前台(焦点)生命周期:onResume-onPause

7。现场保护

保存数据
onPause-onSaveInstanceState-onStop-onDestroy

恢复数据
onCreate-onStart-onRestoreInstanceState-onResume





Activity生命周期
1.打开主界面,后退键退出
onCreate-onStart-onResume-onPause-onStop-onDestroy
2.打开主界面,进入第二个页面
onCreate-onStart-onResume-AonPause-BonCreate-BonStart-BonResume-AonStop
在B页面按返回键
BonPause-AonRestart-AonStart-AonResume-BonStop-BonDestroy

2.1、打开主页面,进入第二个页面,第二个页面以对话框显示
在清单文件中,Activity标签中设置页面主题:
android:theme="@android:style/Theme.Dialog"

onCreate-onStart-onResume-AonPause-BonCreate-BonStart-BonResume

按返回或点击屏幕其他位置
BonPause-AonResume-BonStop-BonDestroy

3.打开主界面,模拟电话进入及挂机,再次显示主界面
onCreate-onStart-onResume-onPause-onStop-onRestart-onStart-onResume

4.打开主界面,HOME键退出
onCreate-onStart-onResume-onPause-onStop
5.打开主界面,HOME键退出,再次启动app
onCreate-onStart-onResume-onPause-onStop-onRestart-onStart-onResume

6.打开主界面,切换横屏竖屏。
onCreate-onStart-onResume-onPause-onStop-onDestroy-onCreate-onStart-onResume

屏幕切换,销毁当前页面,再重新创建


http://flash.weather.com.cn/wmaps/xml/china.xml








第六天
一、Task
* 任务栈 对 所有Activity涉及其操作的任务集合
*
* 特点:
* 1 栈顶的元素 是用户直接看到的那个任务 并且 可以进行交互
* 2 栈中的元素都处于停止的状态
* 3 弹出的任务 销毁状态
二、启动模式
* Activity 启动模式
* 配置方法: 在清单文件中activity 标签下 设置 launchMode = “”;
* 1.standard
* 标准的启动模式(默认) , 每次启动的时候都会实例化一个新的Activity对象放入栈中
* 2.singleTop
* 如果当前任务处于栈顶,则不会创建新的实例入栈,会调用当前栈顶元素的 onNewIntent 方法 如果该任务没有处于栈顶,则创建新的实例放入栈中
* 3.singleTask
* 如果栈中已经存在该实例,则重用该实例,不会创建新的实例,重用时 ,会将该实例上面的所有Activity 弹出销毁
* 当前实例处于栈顶
* 4.singleInstance
* 在一个新的栈当中创建Acitivty 的实例 对其他应用程序共享该实例
三、Intent 七大属性
* Intent: 意图
* 1.启动新的组件 Activity,Service ,BroadCast。。。
* 2.传递数据
* 3.根据action标记来启动系统页面
* 七大属性:
* 1. ComponentName 组成 ,要素,构成
* 1) 显示意图 直接设置上下文对象及目标Activity 进行跳转等同与Intent直接设置参数
* 2) 跨应用跳转Activity ( 包名,目标类的全路径)
* 2. Action 标识符
* intent-filter 意图过滤器 过滤条件的集合 在清单文件中配置
* action 与category 必须同时使用
* 1) 隐式意图作为跳转目标的标记 ,将目标Activity 的action设置一个字符串标识 根据Intent 的action 属性 进行跳转
* 2) 根据Intent类的常量调用系统页面(模拟器有问题)
* 3. Category种类
* 和Action 同时使用 表示当前Activity的类型
* 1) DEFAULT 默认
* 2) LAUNCHER 该应用启动的Activity
* 4.Data Uri
* Uri 统一资源标识符 格式:scheme://host:port/path
* 其他的 Android系统的 资源标识符

系统内置的几个Data属性常量:
tel://:号码数据格式,后跟电话号码。
mailto://:邮件数据格式,后跟邮件收件人地址。
smsto://:短息数据格式,后跟短信接收号码。
content://:内容数据格式,后跟需要读取的内容。
file://:文件数据格式,后跟文件路径。
market://search?q=pname:pkgname:市场数据格式,在Google Market里搜索包名为pkgname的应用。
geo://latitude, longitude:经纬数据格式,在地图上显示经纬度所指定的位置。


Uri 统一资源标识符
的格式如下:scheme://host:port/path
约束 主机名(域名:端口号) 路径
url http://www.baidu.com:8080/indext?page =1


//实现发短信
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setType("vnd.android-dir/mms-sms");
intent.putExtra("sms_body", "信息内容...");
startActivity(intent);


* 5.type类型
* 字符串格式 abc/xyc
* 6.Extra 携带数据
* 7.Flag 启动模式

intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); // -- singleTop
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // -- singleTask
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // -- singleInstance


四:
1.清单文件中 versionCode代表 版本号
versionName代表版本名称
Permissions 权限 ,有需要的添加
设置category 的Activity 为应用启动的Activity
2.注意命名规范
方法名使用驼峰式命名方法
尽量使用英文 不要使用汉语拼音
3.Debug 的两种方式


Intent意图

系统内置的几个Data属性常量:
tel://:号码数据格式,后跟电话号码。
mailto://:邮件数据格式,后跟邮件收件人地址。
smsto://:短息数据格式,后跟短信接收号码。
content://:内容数据格式,后跟需要读取的内容。
file://:文件数据格式,后跟文件路径。
market://search?q=pname:pkgname:市场数据格式,在Google Market里搜索包名为pkgname的应用。
geo://latitude, longitude:经纬数据格式,在地图上显示经纬度所指定的位置。


Uri 统一资源标识符
的格式如下:scheme://host:port/path
约束 主机名(域名:端口号) 路径
url http://www.baidu.com:8080/indext?page =1



Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setType("vnd.android-dir/mms-sms");
intent.putExtra("sms_body", "信息内容...");
startActivity(intent);





第七天

Json
http://sns.maimaicha.com/api?apikey=b4f4ee31a8b9acc866ef2afb754c33e6&format=json&method=news.getListByType&page=0&row=15&type=52

Image
https://www.baidu.com/img/bd_logo1.png

一、主线程(UI线程)不能访问网络 子线程不能更新UI
主线程(UI线程)不能访问网络,使用子线程获得网络数据,子线程不能更新UI,获得数据交给主线程完成UI的修改
二、AsyncTask 异步任务 抽象类
封装了 完成子线程的方法与 UI线程更新的方法


/**
* 第一个参数 : 参数 一般传入 URL String 类型
* 第二个参数 : 进度 Integer
* 第三个参数 : 结果 数据类型 根据返回值决定
*
* @author Mr.Zhao
*
*/
class MyTask extends AsyncTask<String, Integer, Object> {

/**
* 任务开始前的准备工作
* 通常用作于 UI的初始化
* 在UI 线程中
*/
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}

/**
* ×××××××× 重要 常用
* 子线程执行 网络请求 等 工作
* 参数 为 继承该抽象类的时候泛型中的第一个
* 参数类型必须保持一致 返回值: 是 网络请求结果 的值
* 数据类型 必须与 继承抽象类的泛型中的第三个
* 子线程
*/
@Override
protected Object doInBackground(String... params) {
// TODO Auto-generated method stub
return null;
}

/**
* 更新进度 values 代表着当前进度 UI线程中
*
*/
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}

/**
* 子线程工作后结果处理的方法 这个方法 已经回到了UI(主)线程
* 可以进行更新UI 的操作
* 重要 常用
*/
@Override
protected void onPostExecute(Object result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}

/**
*
* 取消当前任务
*/
@Override
protected void onCancelled() {
// TODO Auto-generated method stub
super.onCancelled();
}
}




第八天

ListView: 列表视图
可使用ArrayAdapter 实现简单的布局效果

BaseAdapter
自定义适配器 --- 抽象类

* 当Android 系统所提供的适配器无法满足用户需求的时候 那么就需要我们来自定义适配器达到想要的需求结果
*
* 自定义适配器需要继承现有的 BaseAdapter
* 抽象类 需重写各种方法
*
* 自定义适配器的步骤:
* 1.定义一个子类继承BaseAdapter
* 2.重写相应的方法
* a)getCount表示加载到当前适配器的条目总数
* b)getItem 表示根据位置获取Item 对象
* c)getItemId根据位置获取当前item 的ID
* d)getView 根据位置获取当前item 显示的View

引用XML文件布局作为 View
将xml布局转化为View对象

* 自定义的Adapter 的item不仅仅局限于 系统view 可以也 自定义 xml布局文件 那么 就需要将布局文件转换成为 View
*
* 将布局转换成为View 的方法 ---
* 一、LayoutInflater
* LayoutInflater 的实现方式
* 1.LayoutInflater.from(Context)
* 2.Activity.getLayoutInflater();
* 3.Context.getSystemService(Context_LAYOUT_INFLATER_SERVICE);
*
* 二、 直接将布局转换成为View
* View view = View.inflater(Context,R.layout.XXX,null);
*


ListView 优化
* ListView 优化
* 1. 重复利用convertView
* -- ViewHolder
六步骤
// 第一步 实例化 视图持有者 ViewHolder
// 第二步 判断convertView 是否被创建
// 第三步 实例化Holder 对象
// 第四步holder 对象 内部引用的实例化
// 第五步 -- 给convertView 设置 Holder标
// 第六步 --当convertView 不为null 的时候 通过convertView获取到 holder
* 2. ListView的高度设置 match_parent 或绝对数值
* 3. 尽量不要再getView 方法中进行 业务逻辑繁杂或延时操作

// 当数据源发生改变 后 调用该方法 刷新数据
该方法为Adapter 的方法 注意使用
notifyDataSetChanged();





第十一天

一,菜单 Menu


1,选项菜单(系统菜单)OptionsMenu

1.1 两种创建菜单项的方式

高版本:在xml中定义<item>菜单项


低版本:纯java代码创建Item项



1.2 高版本 在res/menu/main.xml中定义菜单项

<!--
android:id Menu资源的Id
android:title Menu菜单项的文本
android:orderInCategory="100" 设置菜单项显示的顺序,值越小,越在上面显示
android:showAsAction="never" 设置菜单项何时和怎样显示在Action Bar上

属性值: never 永远都不会显示在Action Bar上
ifRoom 如果有空间显示在Action Bar上
always 一直显示在Action Bar上

-->
<item
android:id="@+id/action_quit"
android:orderInCategory="100"
android:showAsAction="never"
android:title="退出"/>


/**
* 创建菜单项 ,当你创建Activity时调用
*
* 一个activity中只能有一个OptionsMenu
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// 加载菜单布局
getMenuInflater().inflate(R.menu.main, menu);

return true;
}

/**
* 点击Menu Item 的回调方法
*
* MenuItem item 当前点击的菜单项
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {

case R.id.action_quit:

finish();// 关闭当前页面

break;

case R.id.action_red:

tv.setTextColor(Color.RED);

break;


case R.id.action_size_40:

tv.setTextSize(40);

break;
}

return super.onOptionsItemSelected(item);
}



1.3 低版本的创建:纯JAVA代码

/**
* groupId 分组ID
* itemId 菜单项的Id
* order 菜单显示的顺序
* title 菜单文本
*/
menu.add(Menu.NONE, 1, Menu.NONE, "代码菜单1");

SubMenu subMenu = menu.addSubMenu(Menu.NONE, 2, Menu.NONE, "代码菜单2");
subMenu.add(Menu.NONE, 21, Menu.NONE, "sub 2_1");
subMenu.add(Menu.NONE, 22, Menu.NONE, "sub 2_2");


2,上下文菜单 ContextMenu 可以为任意View指定上下文菜单,长按View创建上下午菜单,通常使用在ListView或者GridView中


2.1 为View注册上下文菜单

registerForContextMenu(tv);


2.2 onCreateContextMenu()

/**
* 2, 重写父类的方法onCreateContextMeun()
*
* 当长按View时调用
*
* ContextMenu menu 需要显示的菜单 View v 用户选择的View ContextMenuInfo menuInfo
* 所选择页面的额外信息,(ListView,GridView,Spinner) 携带了AdapterView中的position信息
*/
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {

// 加载菜单布局
getMenuInflater().inflate(R.menu.main, menu);

super.onCreateContextMenu(menu, v, menuInfo);
}


2.3 onContextItemSelected()

@Override
public boolean onContextItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {

case R.id.action_delete:

//得到当前选中ListView的Item的信息
AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo)item.getMenuInfo();

//获取当前选中ListView的Item的下标
int posiotion = menuInfo.position;

//移除数据
data.remove(posiotion);
//刷新适配器
adapter.notifyDataSetChanged();
break;

}
return super.onContextItemSelected(item);
}





3,PopUpMenu 弹出式菜单 API 11以上,可以为任一View创建弹出式菜单

public void click(View v)
{
//创建PopupMenu
/**
* context 上下文对象
* anchor 当前弹出菜单的参考显示的位置
*/
PopupMenu pMenu = new PopupMenu(this, v);

//加载菜单
getMenuInflater().inflate(R.menu.main, pMenu.getMenu());

pMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {

@Override
public boolean onMenuItemClick(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.action_size_20:

tv.setTextSize(20);

break;

case R.id.action_size_30:

tv.setTextSize(30);

break;
}

return false;
}
});

//显示弹出式菜单
pMenu.show();
}




二,对话框 Dialog ,所有对话框都必须 show()


1, 普通对话框 AlertDialog

进度条对话框 ProgressDialog

日期选择对话框 DatePickerDialog

时间选择对话框 TimePickerDialog

自定义对话框



2,列表对话框(AlertDialog)

普通列表对话框

builder.setItems(R.array.arrColors,new OnClickListener() {});

单选对话框

builder2.setSingleChoiceItems(R.array.arrSizes, -1, new OnClickListener() {});

多选对话框

builder3.setMultiChoiceItems(R.array.arrHobbys, checkedItems, new OnMultiChoiceClickListener() {});


适配器对话框
builder4.setAdapter(adapter, new OnClickListener() {});


三,Toast 土司

1, 普通土司

Toast.makeText(getApplicationContext(), "提示信息", Toast.LENGTH_LONG).show();

2,指定位置的土司


//设置Toast显示的位置(显示的位置,X轴的偏移,Y轴的偏移)
toast2.setGravity(Gravity.CENTER, 0, 0);

3,自定义

Toast toast3 = new Toast(this);

TextView tv = new TextView(this);

tv.setText("我是自定义的Toast!");


toast3.setView(tv);

toast3.setDuration(Toast.LENGTH_LONG);

toast3.show();


四,通知栏








第十二天


Fragment 碎片


一,Fragment是什么?

是Android3.0之后,API11以上,是Activity的一个组成部分

提高代码的重用性和改善用户的体验(UI的合理利用)

Fragment有自己的生命周期和接受处理用户的事件,这样我们就不用在Activity中写一堆代码,更为重要的是
我们可以添加,替换、移除Fragment


Fragment 可以显示内容

Fragmnet 可以和用户交互


note: Fragment 必须显示在Activity中

一个Activity中可以包含多个Fragment,同一个Fragment可以被多个Activity包含


二,如何创建Fragment?


1,定义一个类,继承Fragment

2,重写父类的生命周期方法:onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState);

LayoutInflater inflater 布局加载器

ViewGroup container 当前Fragment所在的父容器对象

 Bundle savedInstanceState 存放的业务数据






三,Fragment的显示方式


1,静态方式显示

在Activity的布局文件中,<fragment>

必须要有id属性,来标示Fragment的唯一性

name:指定要显示的Fragment的名称


2,动态方式显示

2.1 需要在Activity布局中,通过布局容器占位


2.2 Activity中:显示

//1,得到Fragment的管理器对象
FragmentManager manager = getFragmentManager();

//2,开启Fragment的事务处理
FragmentTransaction ft = manager.beginTransaction();

//3,实例化Fragment(你要现实的Fragment)
LeftFragment fragment = new LeftFragment();

//4,动态显示Fragment
//containerViewId 在Activity布局中为Fragment占位的Id, fragment 要显示的Fragment
//ft.add(R.id.fragment_left_id, fragment);
ft.replace(R.id.fragment_left_id, fragment);

//5,提交事务(只能提交一次)
ft.commit();


四,Activity向Fragment传值

1,向Fragment传入参数

Bundle args = new Bundle();
args.putString("msg", "显示的内容:" + new Date());

fragment.setArguments(args);


2,在Fragment中获取传入的参数


Bundle bundle = getArguments();

String msg = bundle.getString("msg");

tv.setText(msg);

五,Fragment向Activity传值


1,Fragment中定义回调接口

//定义回调接口
public interface CallBack
{
public void getResult(String result);
}


2,Fragment中:回调方法

//回调方法
public void getEditText(CallBack callBack)
{
String msg = editText.getText().toString().trim();

callBack.getResult(msg);
}



3,Activity中:

fragment.getEditText(new CallBack() {

@Override
public void getResult(String result) {

tv.setText(result);
}

});

六,Fragment向Fragment传值

调用Fragmnet中定义的普通的方法:

Activity中:

Bundle bundle = new Bundle();
bundle.putString("fileName", fileName);

ContentFragment fragment = ContentFragment.newInstance(bundle);

Fragment中:
1,public static ContentFragment newInstance(Bundle bundle) {

ContentFragment contentFragment = new ContentFragment();

contentFragment.setArguments(bundle);

return contentFragment;
}

2,在onCreateView()中: fileName = getArguments().getString("fileName");


七,Fragment生命周期(11个)


1,初始化阶段--onCreate()

onAttach(Activity activity) 与归属Activity进行连接

onCreate(Bundle savedInstanceState) 初始化Fragment

onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) 初始化Fragment中显示的UI

onActivityCreated(Bundle savedInstanceState) 归属Activity的onCreate()执行完成

2, 显示/隐藏阶段

onStart() 显示Fragment

onResume() 获取到焦点

onPause() 失去焦点

onStop() 关闭Fragment

3,销毁阶段---onDestroy()

onDestroyView() 销毁Fragment中显示的UI

onDestroy() 销毁Fragment

onDetach() 与归属Activity断开连接



显示:

F:onAttach() -- F:onCreate() -- F:onCreateView() -- A:onCreate() -- F:onActivityCreated()
--A:onStart()--F:onStart()--A:onResume() -- F:onResume()



退出:

F:onPause()--A:onPause() --F:onStop()--A:onStop() -- F:onDestroyView() --F:onDestroy()
--F:onDetach()--A:onDestroy()


八,小应用:横竖屏切换(内容改变)


九,ListFragment

1, 定义一个类,继承ListFragment

2,碎片本身就UI控件 -- ListView

3,在onCreateView()生命周期方法之后,setListAdapter(adapter);

4,重写父类的onListItemClick(),监听






===============

Day12_Fragment_01 静态显示Fragment

Day12_Fragment_02 动态显示Fragmnet,Activity向Fragment传值

Day12_Fragment_03 Fragment向Activity传值

Day12_Fragment_04 Fragment显示笔记内容

Day12_Fragment_05 Fragment显示笔记内容(横竖屏)

Day12_Fragment_06 Fragment生命周期







第十三天 数据存储(读、写)



一,分类

共享参数

内部存储

扩展存储

数据库

网络存储


二,共享参数 SharedPreferences (基本设置,登陆,定位)

1,特点: 应用程序卸载后,文件也会被删除


2,存储的数据类型: boolean , int ,long,String,float


3,数据存放的位置:data/data/应用程序包名/shared_prefs/***.xml


4,存储数据:

//1,获取共享参数的对象
/**
* name 文件名称(不需要写扩展名称)
* mode 文件的操作模式
*
* Context.MODE_PRIVATE 文件只能被当前应用程序访问
* 写入数据时,如果Key相同,Value会覆盖之前的内容
*
* Context.MODE_APPEND 写入的文件可以追加
*
*
*
* getSharedPreferences(name, mode) 需要指定文件名称
* getPreferences(mode) 文件名称是当前Activity的类名
*/
SharedPreferences sp = getSharedPreferences("mysets", Context.MODE_PRIVATE);


//2,获取共享参数的编辑对象
Editor editor = sp.edit();

//3,向共享参数中写入数据
editor.putInt("fontSize", 20);
editor.putInt("color", Color.RED);
editor.putString("msg", "你已经更改了设置!!!");

//4,提交数据
editor.commit();


5,读取数据:

//1,得到共享参数的对象

SharedPreferences sp = getSharedPreferences("mysets", Context.MODE_PRIVATE);

//2,获取数据
/**
* key 存入数据是的Key
*
* defValue 如果读取不到Key对应的数据,那么显示默认的数据
*/
int fontSize = sp.getInt("fontSize", 15);
int color = sp.getInt("color", Color.BLACK);
String msg = sp.getString("msg", "读取数据失败");




三,内部存储

1,特点: 应用程序卸载后,文件也会被删除


2,路径: data/data/应用程序包名/files/***.***


3,核心代码:FileOutputStream


3.1 存入数据:

//1,打开内部存储文件的输出流
/**
* name 文件名称
* mode 文件操作模式
*
*/
FileOutputStream fos = openFileOutput(fileName, Context.MODE_PRIVATE);

//2,写入数据
fos.write(content.getBytes());

//3,关闭流
fos.close();

3.2 读取数据:

//1,打开内部存储的输入流
FileInputStream fis = openFileInput(fileName);

//2,读取长度
byte[] buffer = new byte[fis.available()];
//3,开始读取
fis.read(buffer);
//关闭流
fis.close();



四,扩展存储 SD卡

1,特点:

当卸载应用程序时,sd卡公共目录中的文件不会清除


2,路径:

android 4.0之前:mnt/sdcard

android 4.0之后:storage/sdcard


3,读写扩展卡的权限

Environment.getExternalStorageState()

4,获取扩展卡的根目录

Environment.getExternalStorageDirectory()


5,获取当前扩展卡的状态

<!-- 写SD卡的状态 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<!-- 读SD卡的状态 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>







第十四天


Oracle,SQL Server ,mySql,SQLite 都是关系型数据库



数据库 SQLite


一,特点

轻量级,零配置,跨平台,嵌入式

在程序的内部,可以在任何位置通过数据库的名称对其访问,其他的应用程序不可以访问。



二,数据类型

NULL(空值)
INTEGER(整型)
TEXT(文本)
VARCHAR(可变长度的字符数据)
BOOLEAN(布尔)
FLOAT(单精度)
DOUBLE(双精度)
DATETIME(日期)




三,SQL语句

创建表:

create table 表名(字段名称 字段类型,...)

create table user(_id integer primary key autoincrement,name varchar(50))


表中添加字段

alter table 表名 add 字段名 类型

alter table user add amount integer


插入数据:

insert into 表名(字段s) values(值s)

insert into user(name) values('刘能')


修改数据:

update 表名 set 字段=值 where 条件

update user set name='于军' where _id=1


删除数据:

delete from 表名 where 条件


delete from user where _id=2


查询数据:

select (字段s) from 表名 where 条件


select _id,name from user where _id=3



四,Android数据库的核心类 data/data/应用程序包名/database/数据库名称

1,SQLiteDatabase 管理和操作数据库


2,SQLiteOpenHelper 用于数据库的创建和版本的更新


作用: 初始化数据库

升级数据库

打开数据库的连接


2,.1 使用步奏:

2.1.1 定义一个类,继承SQLiteOpenHelper


2.1.2 重写父类的方法

/**
* 第一次执行是调用(只执行一次)
*
* 创建初始表
*
*
* SQLiteDatabase db 数据库操作类
*/
@Override
public void onCreate(SQLiteDatabase db) {

}

/**
* 更新数据库
*
* 如果数据库的版本发生变化,执行此方法
*
* SQLiteDatabase db 数据库的操作类
* int oldVersion 旧版本
* int newVersion 新版本
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}


2.1.3 构造方法

/**
* 构造方法
* @param context 上下文对象
* @param name 数据库名称
* @param factory 游标工厂
* @param version 版本号
*/
public DbOpenHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);

}


3,Cursor 游标 (查询数据后,游标默认位置在数据之上,游标的下标从0开始)

cursor.move(offset) 将指针向上或向下移动指定的行数,
offset为正数代表向下,负数代表向上,判断数据是否存在
cursor.moveToFirst() 游标移动到第一条数据,判断第一条数据是否存在
cursor.moveToLast() 游标移动到最后一条数据,判断最后一条数据是否存在
cursor.moveToNext() 游标移动到下一条数据,判断下一条数据是否存在
cursor.moveToPrevious() 游标移动到上一条数据,判断上一条数据是否存在
cursor.moveToPosition(position) 游标移动到某一条数据,判断数据是否存在


五,Android封装的方法(为不会写SQL语句的学者准备)



1,添加

SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

/**
* table 表名
* nullColumnHack 可以为null 如果是ContentValues insert into user () values ()
* values 值 ContentValues
*/
ContentValues values = new ContentValues();
//key 数据库的字段名, value 字段对应的内容
values.put("name", "赵四");
values.put("age", "18");
values.put("amount", "100");


db.insert("user", null, values);


2,修改:

SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

/**
* table 表名
* values 值 ContentValues
* whereClause where语句之后的字句
* whereArgs 占位符的取值
*/
ContentValues values = new ContentValues();
values.put("amount", "20000");

db.update("user", values, "_id=?", new String[]{"1"});

3,查询:

SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
/**
* distinct 是否去除重复
* table 表名
* columns 查询的字段 new String[]{"name","age","amount"}
* selection where字句之后的内容 _id=?
* selectionArgs 占位符的值 new String[]{"1"}
* groupBy 分组
* having 放到where后面,再次筛选
* orderBy 排序
* limit 区间
*/
Cursor cursor = db.query("user", new String[]{"name","age","amount"}, null, null, null, null, null);

while (cursor.moveToNext()) {

Log.i("info", "姓名:" + cursor.getString(cursor.getColumnIndex("name")) +
",年龄:" + cursor.getInt(cursor.getColumnIndex("age"))+
",钱包:" + cursor.getInt(cursor.getColumnIndex("amount")));
}


4,删除:

SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

/**
* table 表名
* whereClause 条件,where之后的字句
* whereArgs 占位符对应的值
*/
db.delete("user", "_id=?", new String[]{"1"});


六,数据库的事务:

事务的好处?

1,确保数据的一致性

2,提高效率


什么时候使用事务?

进行批量操作的时候使用事务

比如批量进行添加、修改、删除时,必须手动开启事务


SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

//1,开启事务
db.beginTransaction();

try{

for(int i=1;i<=100;i++)
{
db.execSQL("insert into user(name,age,amount) values('张三'"+i+",21,100)");
}
//2,成功后提交事务
//添加 事务成功的标记,当结束事务时提交事务, 如果不写,事务回滚,sql语句不执行
db.setTransactionSuccessful();

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

}finally
{
//3,关闭事务
db.endTransaction();
}


七,应用:通讯录

八,作业: 记事本(增,删,改,查)






第十五天


Content Provider 内容提供者(Android四大组件) 图书馆(短信记录,电话记录,联系人)


一,作用


将应用的私有数据库中的私有数据向外提供一个访问的接口,是基于URI的方式,向外提供统一的数据访问接口


二,URI统一资源标示

类似与URL网络资源地址,URI是用来标示Android应用中某一资源的唯一标识,在ContentProvider组件中,通过Uri向外部应用提供一个私有数据库中的“一张表”的资源唯一标示


内容提供者的URI格式: content://应用程序包名.provider/student


三,访问ContentProvider提供的URI接口


ContentProvider 内容提供者 负责暴露数据(数据库) “服务器”


ContentResolver 内容解析器 负责解析ContentProvider暴露出来的数据 “客户端”



四,案例一:访问短信记录

数据库路径:com.android.providers.telephony中sms表

/**
* 短信的uri
*
* content://sms 所有短信
* content://sms/outbox 发送的短信
* content//sms/inbox 接收的短信
*/
private Uri smsUri = Uri.parse("content://sms");

------------------------------------------------------------------

//1,得到ContentResolver对象
ContentResolver contentResolver = getContentResolver();

//2,通过URI访问数据
/**
* uri 访问ContentProvider的路径
* projection 查询数据库表中列的集合 new String[]{}
* _id,
* address: 地址(发送者)
* body: 短信内容
* type: 类型 1 接收,2 发送,3 草稿 ,4 未读,5 发送失败
*
* selection 查询条件
* selectionArgs 查询条件中占位符对应的集合
* sortOrder 排序
*/

cursor = contentResolver.query(smsUri, new String[]{"_id","address","body"}, null, null, null);

//3,读取游标中数据

adapter = new SimpleCursorAdapter(getApplicationContext(),
R.layout.item_lv,
cursor,
new String[]{"address","body"},
new int[]{R.id.address,R.id.body},
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

lv.setAdapter(adapter);

//4,在清单文件中增加访问短信记录的权限


五,案例二:访问电话记录


数据库路径:com.android.providers.contacts 中calls表

//private Uri uri = Uri.parse("content://call_log/calls");

private Uri uri = CallLog.Calls.CONTENT_URI;

private String[] columns = {CallLog.Calls._ID,//主键
CallLog.Calls.NUMBER,//电话号码
CallLog.Calls.DATE//时间
};


-----------------------------------------------------------------------

//1,得到CotentResolver对象

ContentResolver contentResolver = getContentResolver();

//2,通过URI接口查询数据

cursor = contentResolver.query(uri, columns, null, null, null);

//3,读取游标中的数据
while (cursor.moveToNext()) {

long id = cursor.getLong(cursor.getColumnIndex(CallLog.Calls._ID));
String phone = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));
long date = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATE));

String dataText = sf.format(new Date(date));

data.add(new CallInfo(id, phone, dataText));
}

//刷新适配器
adapter.notifyDataSetChanged();


//4,添加读取电话记录的权限


六,案例三:访问联系人



联系人数据库所在的位置

data/data/com.android.provides.contacts/database/contats2



联系人表URI:

content://com.android.contacts/raw_contacts

数据表URI:

content://com.android.contacts/data


表一:raw_contacts (有多少联系人就有多少条数据)

_id: 主键

display_name: 联系人姓名

表二: data

_id: 主键

mimetype_id : 外键 (mimetypes的主键)

raw_contact_id : 外键(raw_contacts的主键)

data1: 数据

表三:mimetypes

_id 主键(1 邮箱,5 电话,7 姓名)



查找 zhansan 的 电话 :select data1 from data where raw_contact_id=1

查找 姓名,电话 : select raw_contact_id,display_name,data1 from raw_contacts as t1,data as t2 where t1._id = t2.raw_contact_id and mimetype_id=5







第十六天


自定义ContentProvider 组件


一,如何创建

1,创建一个类,继承ContentProvider ,同时实现父类的6个抽象方法


onCreate() --- 初始化数据库的操作对象(工具类)

query(Uri uri....)

Uri uri = insert(Uri uri...)

update(Uri uri...)

delete(Uri uri...)

getType(Uri uri...) 一般情况,只实现,不做处理



2,声明ContentProvider组件的唯一标识 : authority


note :authority 内容必须是小写字母, 建议以当前的应用的包名+标识资源的名称(数据库的名称)



3,声明访问数据库的那些表的code(t_user = 0 ,t_older = 6)


4,定义Uri的匹配器,并实例化,同时增加完整的Uri访问资源的接口


5,定义数据库的操作类,并oncreate()方法中实例化


6,在相应查询,修改,删除,添加方法中,通过Uri匹配器,判断当前的Uri是访问那张表的code


7,在Manifist清单文件中注册ContentProvider组件;同时声明权限

<!-- 注册ContentProvider
android:name="" 名称
android:authorities="" ContentProvider 组件的唯一标识(和authority是一致的)
android:exported="" 设置当前的组件可以被外部应用访问
android:permission="" 声明访问当前组件的权限
-->
<provider
android:name="com.qf.day16_contentprovider.MyContentProvider"
android:authorities="com.qf.day16_contentprovider_01.users"
android:exported="true"
android:permission="com.qf.day16_contentprovider_01.users.WRITE_READ"
/>



<!-- 声明访问MyContentProvider组件的权限-->
<permission android:name="com.qf.day16_contentprovider_01.users.WRITE_READ"/>

<!-- 使用访问MyContentProvider 组件的权限
<uses-permission android:name="com.qf.day16_contentprovider_01.users.WRITE_READ"/>-->






第十七天

Loader


一,什么是Loader?


装载器,Android3.0后引进,它使得我们在activity或Fragment中异步加载数据变的简单。

二,作用

通过异步的方式加载数据(数据库中的数据,网络数据,大数据)

实时刷新数据,当Cursor中的数据发生变化时,ListView自动刷新

系统内部使用LoaderManager和LoaderCallBacks来管理Loader

三,LoaderManager

作用:
1,初始化启动Loader, 无条件加载数据

getLoaderManager().initLoader(编号,查询的条件,回调接口)

2,重启Loader, 有条件或者条件发生变化时加载数据

getLoaderManager().restartLoader(编号,查询的条件,回调接口)


注意: 1,一个Activity或Fragment中只能有一个LoaderManager,但是一个LoaderManager可以管理多个Loader


2,在启动Loader时,必须要提供一个回调接口,即LoaderCallBacks接口



四,CursorLoader


CursorLoader内部使用ContentResolve来加载ContentProvider暴露出来的数据,通过URI

内置了ContentOberver ,监听数据源的改变


五,LoaderCallBacks<Cursor> 回调方法

包含3个回调方法:


创建新的Loader,一般返回的是CursorLoader

onCreateLoader(int id,Bundle args)


Loader数据加载完成后,显示数据
onLoaderFinished(Loader<Cursor> loader,Cursor data)


在创建新的Loader之前,重置之前Loader加载的数据
onLoaderReset(Loader<Cursor> loader )


六,使用Loader加载联系人的姓名和电话

1, 在Activity或Fragment中实现LoaderCallBacks接口,重写父类3方法


2,在Activity或Fragment的初始化阶段的生命周期方法中,通过getLoaderManager()的到管理器的对象,初始化
启动Loader


3,在LoaderCallBacks的创建Loader的方法中( onCreateLoader),实例化CursorLoader,并返回

4,在LoaderCallBacks的加载完成的回调方法中(onLoaderFinished()),将加载完成的数据显示出来

SimpleCursorAdapter.swapCursor(cursor);

5,在LoaderCallBacks的重置方法中(onLoaderReset()),清除之前的数据

SimpleCursorAdapter.swapCursor(null);


6,在有条件或者条件发生变化时,重启启动Loader


七,短信记录


八,自定义Loader

1,定义一个类,继承AsyncTaskLoader<D>,并声明返回数据结果的泛型


2,重写方法onStartLoading()方法,执行forceLoad()方法(强制执行后台方法,来加载数据)


3,重写父类的方法:loadInBackground(),在此方法中执行获取数据的操作,并把结果返回



-------拓展---------

九,SearchView


<!-- android:iconifiedByDefault="false" 设置当前的控件是否以图标的方式显示 -->
<SearchView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/search_view_id"
android:iconifiedByDefault="false"
/>


十,ContentObserver 内容观察者

1,自定义内容观察者

//自定义内容观察者MyContentObServer
public class MyContentObServer extends ContentObserver
{

public MyContentObServer(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}

//当被观测的内容发生变化时,调用此方法
@Override
public void onChange(boolean selfChange) {

super.onChange(selfChange);

//重启Loader
getLoaderManager().restartLoader(2, null, MainActivity.this);


}

}

2,注册内容观察者

//自定义内容观察者MyContentObServer
public class MyContentObServer extends ContentObserver
{

public MyContentObServer(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}

//当被观测的内容发生变化时,调用此方法
@Override
public void onChange(boolean selfChange) {

super.onChange(selfChange);

//重启Loader
getLoaderManager().restartLoader(2, null, MainActivity.this);


}

}







第十八天


Handler 的使用


一,Android使用线程的规则:


1,UI线程不能被阻塞

2,子线程不能操作UI线程(除ProgressBar)

3,使用handler线程间的通信机制,实现子线程向UI线程发送数据


二,了解Handler的原理


Handler实现了线程间的通信的核心类:

Looper类: 循环读取MessageQueue中的Message(for(;;))


MessageQueue类:存放的是Handler发送过来的消息(Message)


Handler类:消息的发送者,又是消息的处理者

方法:
handleMessage() : 处理消息

obtainMessage() : 从消息队列中取出消息

sendEmptyMessage() : 发送的是Message中只给what属性赋值

sendEmptyMessageDelayed()

sendMessage(Message msg) : 发送Message

sendMessageDelayed() : 延迟发送消息

sendMessageAtTime() : 在当前设置的时间发送

post(Runnable) : 运行在主线程中,更新UI

postDelayed()

postAtTime()

Message类: 包装了线程间发送的数据

参数:8 个

int what : 发送空消息(状态)

int arg1

int arg2

Object obj :存放的Object类型的对象

Handler target :标签,由那个handler处理,就设为那个handler

Message sPool : 消息对象

int sPoolSize :当前内存中消息的数量

int MAX_POOL_SIZE = 50 :内存中最大的消息数量


方法:
obtain() 从消息池中取出消息

recycle() 将用完的消息对象及时回收到消息池中

setTarget(Handler target) 给每个消息对象贴标签,只有贴了标签,Looper才能知道 要传给那个Handler做处理

Handler getTarget()

sendToTarget() 把消息发送给那个handler


三,子线程向主线程发送消息


1,在主线程中实例化Handler对象,并重写handleMessage()方法,

在此方法中用于处理handler通过sendMessage()方法发送的消息


2,在子线程中,某一个合适的位置(数据加载完成) ,实例化Message对象,将相关的数据放入Message对象中



3,在子线程中发送消息:

3.1 send方法发送(3种)

handler.sendMessage(Message msg);


3.2 以post方式发送

handler.post(new Runnable(){})

这种方式,是子线程向主线程发送一段代码(代码块是在主线程中执行)





------扩展--------

计时器:

一:

Timer timer = new Timer();
//schedule(定时的任务, 第一次执行延迟的时间, 每隔多长时间执行一次)
timer.schedule(new TimerTask() {

@Override
public void run() {
// TODO 定时执行的内容(发送消息)

handler.sendEmptyMessage(1);

}
}, 0, 1000);



timer.cancel();//停止计时器


二:

ScheduledExecutorService scheduled = Executors.newSingleThreadScheduledExecutor();

scheduled.scheduleWithFixedDelay(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
handler.sendEmptyMessage(1);
}
}, 1, 1, TimeUnit.SECONDS);


scheduled.shutdowm();//停止






第十八天


Handler 的使用


一,Android使用线程的规则:


1,UI线程不能被阻塞

2,子线程不能操作UI线程(除ProgressBar)

3,使用handler线程间的通信机制,实现子线程向UI线程发送数据


二,了解Handler的原理


注意 : 一个线程只能有一个Looper对象,可以有多个Handler对象


Handler实现了线程间的通信的核心类:

Looper类: 循环读取MessageQueue中的Message(for(;;))

方法:
prepare() : 创建Looper对象

loop() : 循环读取MessageQueue中的message

myLooper() 返回子线程中的Looper对象

属性:

ThreadLocal<Looper> sThreadLocal : 本地线程的变量,能创建Looper对象

Looper sMainLooper :主线程中Looper对象

MessageQueue mQueue : 消息队列


MessageQueue类:存放的是Handler发送过来的消息(Message)


Handler类:消息的发送者,又是消息的处理者

方法:
handleMessage() : 处理消息

obtainMessage() : 从消息队列中取出消息

sendEmptyMessage() : 发送的是Message中只给what属性赋值

sendEmptyMessageDelayed()

sendMessage(Message msg) : 发送Message

sendMessageDelayed() : 延迟发送消息

sendMessageAtTime() : 在当前设置的时间发送

post(Runnable) : 运行在主线程中,更新UI

postDelayed()

postAtTime()

Message类: 包装了线程间发送的数据

参数:8 个

int what : 发送空消息(状态)

int arg1

int arg2

Object obj :存放的Object类型的对象

Handler target :标签,由那个handler处理,就设为那个handler

Message sPool : 消息对象

int sPoolSize :当前内存中消息的数量

int MAX_POOL_SIZE = 50 :内存中最大的消息数量


方法:
obtain() 从消息池中取出消息

recycle() 将用完的消息对象及时回收到消息池中

setTarget(Handler target) 给每个消息对象贴标签,只有贴了标签,Looper才能知道 要传给那个Handler做处理

Handler getTarget()

sendToTarget() 把消息发送给那个handler


三,子线程向主线程发送消息


1,在主线程中实例化Handler对象,并重写handleMessage()方法,

在此方法中用于处理handler通过sendMessage()方法发送的消息


2,在子线程中,某一个合适的位置(数据加载完成) ,实例化Message对象,将相关的数据放入Message对象中



3,在子线程中发送消息:

3.1 send方法发送(3种)

handler.sendMessage(Message msg);


方式一:

Message msg = Message.obtain();
msg.obj = bitmap;
handler.sendMessage(msg);

方式二:

Message msg = Message.obtain();
msg.obj = bitmap;
msg.setTarget(handler);
msg.sendToTarget();

方式三:

Message msg = handler.obtainMessage();
msg.obj = bitmap;
msg.sendToTarget();




3.2 以post方式发送

handler.post(new Runnable(){})

这种方式,是子线程向主线程发送一段代码(代码块是在主线程中执行)



方式四:

使用这种方法,不需要再重写handleMessage()方法

handler.post(new Runnable(){

//执行主线程赋值的操作

});



四,主线程向子线程发送消息


1,将子线程升级为Looper线程,即在子线程中创建Looper对象

Looper.perpare()方法,这个方法内部会创建一个MessageQueue对象,同时将创建的Looper保存在线程的本地变量中


2,在子线程中实例化Handler对象

new Handler()时,会判断当前的本地线程中是否存在Looper对象

3,在子线程中执行Looper.loop() 循环读取MessageQueue中的Message




五,实例 :

Day18_Handler_01 子线程向主线程发送消息的4中方式

Day18_Handler_02 图片自动播放+计时器

Day18_Handler_03 主线程向子线程发送消息

Day18_Handler_04 新闻网页


------扩展--------

计时器:

一:

Timer timer = new Timer();
//schedule(定时的任务, 第一次执行延迟的时间, 每隔多长时间执行一次)
timer.schedule(new TimerTask() {

@Override
public void run() {
// TODO 定时执行的内容(发送消息)

handler.sendEmptyMessage(1);

}
}, 0, 1000);



timer.cancel();//停止计时器


二:

ScheduledExecutorService scheduled = Executors.newSingleThreadScheduledExecutor();

scheduled.scheduleWithFixedDelay(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
handler.sendEmptyMessage(1);
}
}, 1, 1, TimeUnit.SECONDS);


scheduled.shutdowm();//停止



四大类
Handler
属性:MessageQueue -- handler讲消息发送出去实际就是放在这里
Looper--每个handler有一个looper为其不断的接受消息队列消息
CallBack--回调接收 方法handleMessage
方法:
handleMessage : 回调接口中的方法
obtainMessage:获取消息实例 本质还是调用Message.Obtain
sendMessage:
sendMessageDelayed:
sendMessageAtTime:
sendEmptyMessage:
sendEmptyMessageDelayed:
sendEmptyMessageAtTime:
post:
postDelayed:
postAiTime:
enqueueMessage:将消息压入到MessageQueue中
dispatchMessage:当looper不断的获取到消息后调用该方法分发消息触发CallBack里的handleMessage方法进行消息处理

Looper
属性:
ThreadLocal<Looper>: 本地线程变量 由于该变量保证每个线程只有一个Looper也就是说一个线程只能有一个Looper
方法:
prepare:所有的Handler 所在线程都必须有一个looper 准备好
prepareMainLooper:获取主线程中的looper对象
myLooper:从线程本地变量中获取当前线程的Looper对象
loop:循环接收消息队列中的消息

Message
属性:
what: 标记消息
arg1: 存放消息的 int
arg2: 存放消息的 int
obj: 用来存放消息的Object
data:用来存放消息属性Bundle
target:标示 Handler
sPool:消息池中的每个消息对象
sPoolSize:纪录消息池中剩余消息的数量
MAX_POOL_SIZE:消息池中的最大消息对象数量
replyTo: Messenger:自定义信使对象 跨进程

方法:
obtain: 获取Message实例
setTarget: 设置收到消息的Handler
getTarget: 获取应该收到消息的Handler
setData: 设置Bunldle对象
getData: 设置Bunldle对象
sendToTarget: 将消息发送到目标Handler对象,本质还是调用sendMessage
recycle: 往消息池中归还消息对象

MessageQueue
属性:
enqueueMessage:通过改方法将消息添加到自己的队列中
next:下一个Message



Handler 消息机制:


由于主线程(UI线程)不能访问网络,子线程不能更新UI,所以有了Handler消息传送机制用来将子线程的数据发送到主线程中来进行更新UI,在主线程中实例化Handler对象,
在子线程中将将要发送的数据 添加到Message对象中去,Message是可携带int,object,Bundle对象的,通过handler调用handler.sendMessage方法将消息发送出去,
这个时候消息会进入到消息队列MessageQueue 中去,MessageQueue 是个消息队列,enqueueMessage方法讲消息添加到队列中,looper提供了消息运转的动力,
每个线程只允许有一个looper,消息在MessageQueue中不断的一个一个的做进栈出栈动作,handler调用dispatchMessage方法对MessageQueue中出来Message进行分发
,分发根据的是target(Handler),而dispatchMessage方法执行的就是一个CallBack回调方法,也就是主线程中用来接收消息的的handleMessage方法,
这样主线程就可以对接收到的数据进行处理了。




第十九天


一,ActionBar

1,说明

ActionBar上Android3.0 后引入的,显示在标题栏上,创建的方式和菜单是相同的。

与菜单的主要区别是:showAsAction属性





2,ActionBar动作项(Item)显示的属性


showAsAction:

ifRoom : 如果标题栏有空间,则会显示动作项的图标

always :不管有没有空间,都会显示在标题栏

withText:带有文本信息显示

collapseActionView :可以被折叠的,单用户点击按钮时,这个操作视图才会被展开




3,创建ActionBar显示的动作项

3.1 在res/menu/目录下创建菜单资源,再声明<item>时必须声明显示属性(showAsAction)和图标属性(android:icon)

3.2 在Activity类中,重写onCreateOptionsMenu()方法,加载菜单资源

3.3 重写onOptionsItemSelected()方法,来处理ActionBar中的每个Action项的点击事件


4,分割栏操作:

API 14以上

在<application>或<activity>元素中添加android:uiOptions="splitActionBarWhenNarrow" 属性设置


5,启动程序导航图标

5.1 作用: 让APP的Logo也变成可点击的图标

5.2 getActionBar() 获取当前Activity的ActionBar对象

5.3
//设置是否显示Logo的图标
getActionBar().setDisplayShowHomeEnabled(true);

//设置是否将Logo图标作为可点击的按钮,并且在图标的前面添加一个向左的箭头
getActionBar().setDisplayHomeAsUpEnabled(true);


5.4 android.R.id.home://应用导航图标的ID


6,ActionView的使用

作用:可以编辑的动作项,如:searchView可以直接显示在ActionBar中


方式:

1,actionViewClass属性,指定实现CollapsibleActionView的子类

2,actionLayout属性,可以指定一个布局文件




二,ActionBar+Fragment


ActionBarTab 导航 : 通常通过选项标签切换Fragment


1,获取当前Activity的ActionBar对象(getActionBar()),并设置导航模式为TABS


2,在当前Activity中,实现ActionBar.TabListener接口(重写3个方法)


3,增加ActionBar.Tab 到ActionBar中

ActionBar.Tab tab = actionBar.newTab();

setText() 设置Tab显示的文本

setIcon() 设置Tab显示的图标

setTabListener() 设置Tab的监听


actionBar.addTab(tab,true);//第二个参数:默认选中的Tab项




第二十天

ViewPager


一,特点: 可以左右滑动的控件,需要PagerAdapter配合使用,由V4包



二,类名:android.support.v4.view.ViewPager;


三,使用步骤

1,在布局文件中使用<android.support.v4.view.ViewPager>标签


2,在代码中增加显示的页面


3,在Activity中实例化ViewPager组件,并设置适配器(PagerAdapter)




四:V4 包下Fragment


1,创建Fragment的子类,继承Fragment(V4包下)


2,Activity必须继承FragmentActivity(V4包下)


3,FragmentManager manager = getSupportFragmentManager();





第二十一天

案例
<不推荐使用方法>
一、TabHost+Activity 方法实现
二、ActionBar+Fragment 方法实现
三、ActionBar+ViewPager 方法实现
四、FragmentTabHost + Fragment 方法实现 ----√

<推荐使用方法>

五、ViewPager+PagerTabStrip+Fragment 方法实现√
六、RadioGroup+Fragment 方法实现 √
七、RadioGroup+ViewPager+Fragment 方法实现 √
八、HorizontalScrollView+Linearlayout+ViewPager 方法实现√

作业!
使用java代码方式写布局计算器





第二十二天



* 广播: 全局性的 ,系统级别的 消息传递机制
*
* 广播的三要素:
* 1.发送方 Context.sendBroadCast
* 2.发送内容 Intent
* 3.广播接收者 BroadCastReceiver
*
* 广播根据注册方式不同分为
* 静态注册
* 在清单文件中 <application> 标签下 添加<receiver> 标签 并 添加IntentFilter 及其 action 属性
* 动态注册
* 在 Activity 中 实例化 MyReceiver 对象 ,再定义一个 IntentFilter 对象 添加Action 属性
* 调用 registeReceiver方法 注册 同时 需要在 onDestory方法中调用 unRegisterReceiver方法 解除注册
*
* 静态注册与动态注册的区别:
* 1.动态注册的接收效率要比静态注册的稍高一些
* 2.静态注册的时候,app 退出 activity 的销毁 都不会影响广播接收者的接收
* 3.动态注册的时候,如果当前Activity 销毁 则不会再接收到广播
*
* 关键:
* 定义action
* 发送方的Intent 定义action(可以理解为一个频道)
* 所有存在于该频道的Receiver都能接收到这个频道的消息
*
* 发送方定义了action 所有的接收方(receiver) 只要都设置了这个action 就都能接收到 这个广播
*
* 广播的生命周期:
* 从接收方 onReceive方法 执行开始 当前的广播接收者有10s的活跃期 这个阶段 不会受到任何的影响,10s过后处于 失活状态
* 这个时候如果有系统进程需要内存空间,则,该广播接收者有可能会被回收,所以 如果需要在该方法中执行延时操作,需要开启一个衍生线程(子线程)来
* 完成这样的工作
*
* 广播实现步骤:
* 1.定义发送
* 2.定义发送的action --定义的时候一般定义为 包名+广播接收者的类名 (按照需求其名称 标准即可)
* 3.发送广播
* 4.定义广播接收者
* 5.注册广播接收者
* 动态
* 静态


有序广播
* 根据优先级 来决定广播接收者 接收广播的顺序
* 发送广播的方法 : sendOrderBroadCast
* 第二个参数 是权限名称 不需要的时候为 null
*
* 需要在注册的时候 添加优先级 (优先级 属性在 IntentFalter 标签内部 proprity 该属性)
* 取值范围 -1000 到 +1000 数值越大 优先级越高 会先接收到广播
*
* 所有的广播接收者不可更改 发送方发送出来的Intent
*
* 如果需要广播接收者之间传递数据
* 可使用 setResultExtra(Bundle) 方法
* 接收方 getResultExtras( boolean)
* 如果 boolean 为false 则 直接返回 传递对象 可为Bundle 可为null
* 如果boolean 为true 则 一定会返回 bundle 对象 但是 可能有值 可能 没有键值
*
* 只有优先级高的 可以向优先级低的传递数据
*
*拦截有序广播的方法
* abortBroadCast()
* 拦截后 ,所有优先级比当前优先级低的广播 都将不再接收到 广播



第二十三天

* Service: 服务
* 服务像Windows后台服务一样,服务是在后台运行,悄悄的承担着不为人知的一些工作
* Service 在后台运行,他是不可见的、无界面的程序
*
* 没有页面的程序 应用场景:播放音乐,下载 ,定位等
*
* 概念:
* 1.Service运行在后台不可与用户进行交互
* 2.服务不是一个单独的进程 ,服务对象本身并不是在自己的进程中运行。
* 3.服务不是一个线程,服务Service 与其他的组件一样,默认的代码是执行在主线程中的
* 4.需要一个上下文对象来启动服务
*
* Service 很大程度上承担了后台线程管理的角色:在Activity中开启一个线程,当Activity销毁后,Thread会继续工作,
* 但是与开启它的Activity 失去了联系,也就是说当前线程处于无人管理的状态,但是Service 可以有效的对后台线程进行管理
*
* Service比线程的优点:
* 1.Service 可以放在独立的进程中,所以更安全
* 2.系统可以重启被异常杀死的Service
* 3.Service可以依赖现有的Binder 机制(明天讲)
*
* Service与Activity的关系
* 1.相同点:都是四大组件,都需要在清单文件中注册,都具有一定的生命周期
* 2.不同点:Acitivty 存在着与用户交互的页面,Service 在后台运行
*
* 分类:本地服务LocalService 与远程服务 RemoteService
* A:本地服务 LocalService
* 根据启动模式分为两种:
* 1.startService(Intent)
* 被启动的服务是通过其他的组件(Activity或BroadCast)调用startService 方法启动的。该方法会导致Service 的生命周期中
* onCreate与onStartCommand方法执行,当Service 启动后,则与他的调用者的生命周期无关,即便调用者已经被销毁。Service 也会
* 一直存在,在后台执行,除非调用了stopService 或者stopSelf
* 2.bindService(。。。)(明天讲)
*
* Service 的生命周期:
*
* onCreat 服务被创建
* onStartCommand 服务开始执行
* onDestory 服务被销毁
*
* 说明:
* 1.当调用startService 方法后,服务会执行 onCreate onStartCommand 方法 ,此时服务处于is Running状态
* 2.如果服务已经被创建 则再次调用startService 方法,服务只会执行onStartCommand 方法,如果没有被创建,则执行onCreate onStartCommand方法
* 3.如果调用了stopService 或者 stopSelf方法 服务会执行onDestory 方法 销毁
* 4.所以 Service 的生命周期为 onCreat --->onStartCommand (可以被多次调用)--->onDestory
*
* onStartCommand方法:
* 根据返回值划分:
* 1. START_STIKEY:粘性的 常量为 1
* 如果服务被异常杀死 服务会被重新启动,但是Intent 值为null
* 2. START_NO_STIKEY :非粘性的 常量为 2
* 如果服务被异常杀死 服务不会被重新启动
* 3. STRAT_REDELIVER_INTENT 常量为 3
* 如果服务被异常杀死,服务会被重启,且Intent 有值

* B 远程服务 RemoteService(接下来讲)
* C IntentService(接下来讲)



第二十四天
* 绑定服务
*
* 绑定服务是允许其它应用程序绑定并且与之交互的Service的实现类。为了提供绑定,必须实现onBind()回调方法。
* 该方法返回IBinder对象,它定义了服务类与Activity交互的程序接口
*
*
* Activity通过bindService()方法绑定到服务类,同时Activity必须提供ServiceConnection接口的实现类,
* 它监视Activity与服务类之间的连接。在重写ServiceConnection接口的onServiceConnected()方法时,
* 实现了将服务类顺利赋值到了Activity中,实现了在Activity中使用该服务类并执行其中的方法
*
*
* 同一个Service可以绑定多个服务链接,这样可以同时为多个不同的组件提供服务 全部组件关闭后 他会关闭
*
* 作用
*
* 作用是在Service和调用者之 间建立一个桥梁,并不负责更多的工作(例如一个Service需要连接服务器 的操作),
* 一般使用bindService来绑定到一个现有的Service(即通过 StartService启动的服务)
*
* 生命周期 onCreate():创建服务 onBind():绑定服务,服务开始运行 onUnbind():取消绑定 onDestroy() :服务被停止
*
* 在程序中调用:context.bindService()会触发执行Service生命周期中的onCreate()、onBind()回调方法,
* 此时服务开始运行
*
* onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。
* 此后调用者(Context,例如Activity)会和Service绑定在一起
*
* 如果调用Service的调用者Context退出了,那么会依次调用Service生命周期中的onUnbind()、onDestroy()回调方法,
* 会让服务停止
*
* 所以BindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind -->
* onDestory


文件存储

临时存储
内存
持久化存储

内部存储
data-data-包名-/

1.cache 缓存
2.file 文件
3.database 数据库
4.shared_pref .xml sharedpreference 存储

Context.getCacheDir();
Context.getFileDir();
...

data-app
存放的都是apk 文件
真机可能需要root 权限才能看到


SD卡(外部存储)
1.判断是否存在SD卡 (挂载)
Environment.getExternalStorageState();
2.获取SD卡的根目录
Environment.getExternalStorageDirectory();
3.获取9大公有目录的路径
Environment.getExternalStoragePublicDirectory(TYPE);Environment.XXX

File.separator 分隔符

SD中的私有目录:
Android-data-包名- files
cache
//获取SD卡中私有目录的路径方法
Context.getExternalCacheDir();
Context.getExternalFilesDir();





//现成的文件引用工具类


package com.steven.helper;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;

public class SDCardHelper {

// 判断SD卡是否被挂载
public static boolean isSDCardMounted() {
// return Environment.getExternalStorageState().equals("mounted");
return Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
}

// 获取SD卡的根目录
public static String getSDCardBaseDir() {
if (isSDCardMounted()) {
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
return null;
}

// 获取SD卡的完整空间大小,返回MB
public static long getSDCardSize() {
if (isSDCardMounted()) {
StatFs fs = new StatFs(getSDCardBaseDir());
long count = fs.getBlockCountLong();
long size = fs.getBlockSizeLong();
return count * size / 1024 / 1024;
}
return 0;
}

// 获取SD卡的剩余空间大小
public static long getSDCardFreeSize() {
if (isSDCardMounted()) {
StatFs fs = new StatFs(getSDCardBaseDir());
long count = fs.getFreeBlocksLong();
long size = fs.getBlockSizeLong();
return count * size / 1024 / 1024;
}
return 0;
}

// 获取SD卡的可用空间大小
public static long getSDCardAvailableSize() {
if (isSDCardMounted()) {
StatFs fs = new StatFs(getSDCardBaseDir());
long count = fs.getAvailableBlocksLong();
long size = fs.getBlockSizeLong();
return count * size / 1024 / 1024;
}
return 0;
}

// 往SD卡的公有目录下保存文件
public static boolean saveFileToSDCardPublicDir(byte[] data, String type,
String fileName) {
BufferedOutputStream bos = null;
if (isSDCardMounted()) {
File file = Environment.getExternalStoragePublicDirectory(type);
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}

// 往SD卡的自定义目录下保存文件
public static boolean saveFileToSDCardCustomDir(byte[] data, String dir,
String fileName) {
BufferedOutputStream bos = null;
if (isSDCardMounted()) {
File file = new File(getSDCardBaseDir() + File.separator + dir);
if (!file.exists()) {
file.mkdirs();// 递归创建自定义目录
}
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}

// 往SD卡的私有Files目录下保存文件
public static boolean saveFileToSDCardPrivateFilesDir(byte[] data,
String type, String fileName, Context context) {
BufferedOutputStream bos = null;
if (isSDCardMounted()) {
File file = context.getExternalFilesDir(type);
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}

// 往SD卡的私有Cache目录下保存文件
public static boolean saveFileToSDCardPrivateCacheDir(byte[] data,
String fileName, Context context) {
BufferedOutputStream bos = null;
if (isSDCardMounted()) {
File file = context.getExternalCacheDir();
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}

// 保存bitmap图片到SDCard的私有Cache目录
public static boolean saveBitmapToSDCardPrivateCacheDir(Bitmap bitmap,
String fileName, Context context) {
if (isSDCardMounted()) {
BufferedOutputStream bos = null;
// 获取私有的Cache缓存目录
File file = context.getExternalCacheDir();

try {
bos = new BufferedOutputStream(new FileOutputStream(new File(
file, fileName)));
if (fileName != null
&& (fileName.contains(".png") || fileName
.contains(".PNG"))) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
} else {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
}
bos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
} else {
return false;
}
}

// 从SD卡获取文件
public static byte[] loadFileFromSDCard(String fileDir) {
BufferedInputStream bis = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();

try {
bis = new BufferedInputStream(
new FileInputStream(new File(fileDir)));
byte[] buffer = new byte[8 * 1024];
int c = 0;
while ((c = bis.read(buffer)) != -1) {
baos.write(buffer, 0, c);
baos.flush();
}
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
baos.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}

// 从SDCard中寻找指定目录下的文件,返回Bitmap
public Bitmap loadBitmapFromSDCard(String filePath) {
byte[] data = loadFileFromSDCard(filePath);
if (data != null) {
Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
if (bm != null) {
return bm;
}
}
return null;
}

// 获取SD卡公有目录的路径
public static String getSDCardPublicDir(String type) {
return Environment.getExternalStoragePublicDirectory(type).toString();
}

// 获取SD卡私有Cache目录的路径
public static String getSDCardPrivateCacheDir(Context context) {
return context.getExternalCacheDir().getAbsolutePath();
}

// 获取SD卡私有Files目录的路径
public static String getSDCardPrivateFilesDir(Context context, String type) {
return context.getExternalFilesDir(type).getAbsolutePath();
}

public static boolean isFileExist(String filePath) {
File file = new File(filePath);
return file.isFile();
}

// 从sdcard中删除文件
public static boolean removeFileFromSDCard(String filePath) {
File file = new File(filePath);
if (file.exists()) {
try {
file.delete();
return true;
} catch (Exception e) {
return false;
}
} else {
return false;
}
}
}




第二十五天
远程服务
* 跨进程通信
* AIDL
*安卓接口定义语言
* android interface definition language
*
* 1.在服务端创建接口文件 .aidl
* 2. 在服务端将该接口实例返回
* 3.客户端需要将 服务端的.aidl文件所在 的包连同文件copy 到 客户端
* 4.客户端拿到接口实例,调用接口的方法




第二十六天
Android:
补间动画 :补充开始和结束中间的动画效果,支持 位移,缩放,透明度,旋转
属性动画 :通过改变对象的属性起始及结束的值来执行动画
帧动画 :多个图片连续播放 ,一帧一帧的 类似GIF 图

补间动画
实现方式:
1.通过xml代码方式
在res文件夹下创建 anim 文件夹 创建xml文件
2.通过java代码方式
Animation 子类: AlphaAnimation TranslateAnimation RotateAnimation ScaleAnimation AnimationSet


属性动画:
实现方式
1.通过xml代码方式:
在res文件夹下创建animator文件夹 创建xml文件
2.通过Java代码方式
ObjectAnimator 根据属性名称决定动画执行种类
属性名称:
alpha

rotation

rotationX

rotationY

translationX

translationY

scaleY

scaleX

帧动画:
实现方式
1.通过xml 设置
在res文件夹下创建drawable文件夹下 创建 根标签为 animation-list 的xml文件
2.通过Java代码方式
AnimationDrawable 类



第二十七天

屏幕适配
重要的概念:
一、屏幕尺寸:
屏幕对角线的长度 单位 英寸 1英寸 = 2.54cm
二、屏幕的分辨率:
屏幕宽高的像素点数 单位是 px像素
一些主流机型的分辨率: 1280×720 1920×1080 2560×1440
三、屏幕像素密度:
屏幕每英寸所含像素点数
四、dpi
单位 -- 屏幕像素密度的单位
五、px
单位 -- 像素的单位
六、sp
单位 -- 描述字体大小的单位
七、dp(dip)
独立的像素密度,与密度无关的像素
dp = px × 比例
比例 根据屏幕像素密度的不同而改变 如果屏幕的像素密度为160 dpi 则 dp与px 1:1 如果像素密度为 240dpi 则dp:px = 1:1.5 等等


适配的方案:
一、多套图片
制作多套分辨率不同的图片 来放在res 文件夹下不同的drawable资源文件夹下 ,系统会根据当前屏幕的像素密度的不同来
分别加载不同文件夹下的资源
注意:相同的图片在不同的文件夹下 名字必须一致
如果只有一套图片,则默认放在hdpi文件夹下 ,因为 系统加载该文件夹下的文件消耗最小
多套图片:不是所有的图片都需要做多套图片 一般情况下 最需要做多套图片的是 logo
二、多使用线性布局与相对布局 禁用绝对布局
使用 wrap_content match_parent weight 确保灵活使用并适应各种布局
三、布局
通过添加修饰符来加载不同的布局文件
layout-land 横向屏幕 加载该文件夹下的文件
了解
layout-small 屏幕尺寸小于3英寸左右的屏幕
layout-normal 屏幕尺寸小于4.5英寸左右的屏幕
layout-large 4英寸到7英寸之间
layout-xlarge 大于7英寸小于 11英寸
四、dimention
使用资源文件 values
新建文件夹 values-1377x899 命名规范: values 加上中横线 - 在加上屏幕分辨率中数大的 1377 加上小x 再加上屏幕分辨率 数小的 899
在该文件夹下 添加 文件 dimens.xml
使用方法与 values - dimens.xml 一样
在新建文件夹下的dimens文件中创建的值必须在 values 文件夹下 添加默认值
了解
values-small
values-normal
values-large
values-xlarge

sw<600> 最小宽度大于600 的屏幕
五、代码适配方案
通过 DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
获取屏幕宽度
定义基础宽度,计算获取到的屏幕宽度与基础宽度的比例
拿到比例后 计算每个View 的位置及大小 进行等比例缩放
所有单位为像素px 必须使用java代码的方式写布局
六、点9图片
工具路径:sdk/tools/draw9path.bat
可拉抻的图片
七、清单文件 中
supports-screens
anyDensity = true 支持任何像素密度的屏幕 默认就是支持的
八、国际化语言
创建 values文件夹 values - 加上国家缩写
在文件夹中创建string.xml 文件 将语言进行国际化转换
注意 在新建文件夹中 添加的 字符串必须在 values文件夹下 的string 里建立默认值
九、SDK 版本适配



UI美化
一、Style
Style 风格样式
适用于 View
定义后可以通过 parent 属性或 直接style 的名称加上点.再加上子类名称的方式进行继承
子类拥有父类的所有属性
并且可以更改 更改后以子类的为基准
如果 xml使用过程中再次修改属性
以xml的为准
二、Theme
Theme 主题样式
适用于 Applicaton activity
如果activity 设置了 theme 则设置了该主题的activity会覆盖application的主题
一般这里只是用两种
1 .Theme.NoTitleBar.Fullscreen
2. Theme.NoTitleBar
三、selector
选择器
state_focused 焦点 是否聚焦 EditText Search
state_enabled 能够接受点击或触摸事件 button textView
state_checkable 是否可以被选中 CheckBox RadioButton
state_selected 选中 spinner listView
state_pressed 按下 Button
四、shape
形状
属性参数 :
corners: 角度 五个属性同时设置 radius无效
gradient : 渐变 与solid同时设置 无效
stroke: 边框 虚线边框 dashWidth dashGap
solid : 填充 颜色 与gradient设置 时 gradient 无效
五、level-list
等级
<item
android:drawable="@drawable/wifi1"
android:maxLevel="10"
android:minLevel="5"/>

包含maxLevel 不包含minLevel
使用时 必须设置为IamgeView 的src 属性
一般用于 wifi信号 手机sim卡信号 电池电量信号 移动数据信号等
六、layer-list
叠加图片在 一个ImageView里



第二十八天
format 可以用|来同时使用
1、reference 参考某一资源Id
2、color 颜色值
3、boolean 布尔值
4、dimension 尺寸值(带有单位的 sp/dp)
5、float 浮点型
6、integer 整形
7、string 字符串
8、fraction 百分比
9、enum 枚举
10、flag 位或运算

第二十八天——————之后见项目


/////////////////////////////////////////////////////////////////////////////////////////
第八周,高级第一周(第三方Jar包的应用)

1,volley

jsonString:
StringRequest
JsonArrayRequest
jsonObjectRequest
自定义

步骤:1,得到queue 队列 2,请求 3,请求添加到队列 4,设置取消标记 5,进行取消

图片:
ImageRequest
ImageLoader :1,获取ImageLoader 对象 2,获取ImageListener 3,get(Url,iamgeListener)
NetworkImage :1,在布局中添加 2,获取ImageLoader 3,setImageUrl(Url,imagloder)

2,Xutils

ViewUtils :1,注入注解工具 2,可以进行注入 3类: 资源 控件 事件
HttpUtils :get /post / 下载
BtmapUtils : 本地图片 网络图片 display(控件 地址 )
DbUtils : 创建数据库 数据库升级 创建数据库表 增删改查

3,PullToRefresh:刷新控件
1,导入jar
2,在布局中添加刷新控件
3,进行设置
4,进行监听
5,下载完成 进行关闭
swipeRefreshLayout
1,在布局中添加
2,进行设置 背景 进度颜色
3,进行监听'
4,进行关闭
4,SlidingMenu: 主视图 被菜单 推出屏幕
1,导包
2,在布局中添加
3,进行设置
对布局里的控件 查找出来 进行监听


drawerLayout: 主视图 被菜单 覆盖
1,布局中 添加菜单
第一个子元素 :主视图 匹配父控件
第二个子元素 :菜单 不能设置大于320dp layout_grivat
5,OkHttp
高效的下载库
get /post

同步 和异步

1,获取OKHttpClient对象
2,获取Request对象
3,通过OKHttpClient对象调用 newCall() 将 Request对象 变成Call任务
4,启动任务 (同步 和异步)
6,Picasso

1,导包
2,一行代码就ok
Picasso.with(Context).load().into(控件)
图片的设置 需要在 into之前调用


7、RecyclerView


9、感应器;例:微信摇一摇的实现


更多相关文章

  1. Android 性能监控与分析方法
  2. Android 解决setRequestedOrientation之后手机屏幕的旋转不触发o
  3. Android线程调度机制
  4. 转-Android数据存储(总结篇)
  5. 面试例题6:两种方法将图像显示在View上
  6. Android NDK报错(Eclipse)及解决方法
  7. Android 更新UI的两个方法
  8. 收藏Android下bitmap内存限制OUT OF MEMORY的方法

随机推荐

  1. Android学习笔记(九)
  2. android之layout配置文件解读
  3. Android(安卓)开发中怎么使用自定义字体?
  4. Android:shape属性详解(图文并茂)
  5. Android(安卓)Porting Steps for ARM
  6. windows上 android 21.1版本ADT环境搭建
  7. android 从tomcat读取文件出错:connect fa
  8. Android点击左右按钮实现左右滑动页面切
  9. Android(安卓)The SourceSet 'instrument
  10. Android(安卓)比Timer更好方法