项目目录结构:
Src: java.class源文件
Gen: Android开发工具自动生成.自动维护,不能修改
R.java 不能手工修改此类中的内容记录各种资源的ID 可以根据R文件中的ID查找各个方法
Assets: 存放资源文件.但存放的资源不会在R.java中生成ID
必须指定路径才能引用其中的文件
Res: 存放各种资源文件.
-hdpi:
里面存放高分辨率的图片,如WVGA (480x800),FWVGA (480x854)
-ldpi:
低分辨率的图片,如QVGA (240x320)
mdpi:
中等分辨率的图片,如HVGA (320x480)
在分辨率低于480*800时把图片放在drawable—mdpi中是不会有什么影响,但是当分辨率为420*800或高于它时就会出问题了。你的手机屏幕有那么大但是他会将图片拉伸,当加载图片后让你感觉该屏幕没有实际的大小,而如果将图片放到drawable—hdpi中则该问题就不会存在了。比如手机屏幕的大小为420*800如果你将图片放在drawable—mdpi中,那么你就要准备一张340*525分辨率的图片,
系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片。
layout:
main.XML界面资源
Values:
<resources>为根节点</resources>
<string>通过string指定</string>
String.XML应用中文字,尺寸,颜色等数据
Default.properties:系统文件
AndroidManifest.XML:项目清单文件.配置文件. 权限配置.
布局控件
<Gallery>:画廊式 TabWidget>:切换卡 TextView>:文本框 <button>:按钮控件
<EditText>:编辑框. EditText.setHint(“设置默认背景内容”)—XML设置:android:hit=” 设置默认背景内容”
<imageView>:图片显示控件
@+id/button :在R文件内的ID中内部类添加常量button.引用button为Button的ID
FindViewbyid(R.id.button); //获取按钮
Setonclicklistener(); //获取点击事件
Gettext().toString(); //获取用户在文本框中输入的数据.转换为字符串
Android:gravity=”XXx”–重心偏移
Android:minLines =”3”; //指定文本框的高度.
<EdiTest>控件:
Android:numecic: 限制文本框只能输入数字
Android:phoneNumber=”true” 只接收电话号码
<Button>控件:
<ImageButton><ImageButton>设置按钮图标使用
Android:Onclick=”query”当用户点击按钮时,调用query中的点击方法
自动适应屏幕的模式,横竖屏自动转换:
<activityandroid:name=”.Acitivty”
Android:label=string/app_name”
Android:screenOrientation=”sensor”>
Android:layout_weigth=”0-??”确定显示控件优先确定 默认为0,0为最大
< HorizontalScrollView>:水平滑动布局
RandOmAccessFile:随即文件访问方法
<ProgressBar>进度条设置Style=”@android:style
在Android中,应用的响应性被活动管理器(Activity Manager)
和窗口管理器(Window Manager)这两个系统服务所监视。
当用户触发了输入事件(如键盘输入,点击按钮等),
如果应用5秒内没有响应用户的输入事件,那么,Android会认
为该应用无响应,便弹出ANR(Application No Response)
在正常情况下,Android程序会在一条单线程里运行。如果Activity要处理一件比较耗时的工作,应该交给子线程完成,否侧会因为主线程被阻塞,后面的用户输入事件因没能在5秒内响应,导致应用出现ANR对话框。
应用程序的4个模块构成:
1. Activity(活动窗口):监听各种系统事件
对话框主题: <activity android:name = “.activity”android:theme=”@android:stsyle/Theme.Dialog”/>
多个Activity同时出现在一个程序中需要在AndroidManifest.xml 申请配置
void onCreate(BundlesavedInstanceState)
onCreate() onStart()- onResume()- onPause()- onStop()- onDestroy()
创建- 开始- 恢复- 暂停- 停止- 销毁
Task:启动模式:android:launchMode
Standard: 每次访问实例化新的.
singleTop: 每次访问,看栈顶元素是目标对象,是则返回,不再实例化,否则,还是实例化.
singelTask: 保证activity实例化一次,单任务,由此所开启的活动和本活动位于同一task中 .
singelInstance: 保证activity实例化一次,单实例,由此所开启的活动在新的task中,和本活动id不一致.
三种状态:
运行状态: 处于激活状态,能够响应用户操作 触发onCreate();onstart();onresume();
暂停状态:
停止状态:
关闭新的Activity重新触发onCreate();onstart();onresume()方法.
Android系统为了让程序再次启动的速度更快.程序并没有真正意义的关闭.而是存储在内存中
内存管理机制:
在内存不足时为了让系统决定杀死哪个进程,Android 根据每个进程中运行的组件以及组件的状态把进程放入一个“重要级别(importancehierarchy)”中,级别低的进程优先被杀死。进程的重要级别排序(级别高的排在前面):
1.前台(foreground)进程,与用户当前正在做的事情密切相关。当下面任何一个条件满足时,会考虑 将进程移到前台:
进程正在屏幕的最前端运行一个与用户交互的Activity (它的onResume()方法被调用)
进程有一正在运行的BroadcastReceiver(它的BroadcastReceiver.onReceive()方法正在执行)
进程有一个Service,并且在Service的某个回调函数(Service.onCreate(),Service.onStart(), Service.onDestroy())内有正在执行的代码。
2.可见(visible)进程,它有一个可以被用户从屏幕上看到的Activity,但不在前台(它的onPause()方 法被调用)。
3.服务(service)进程,进程中存在一个已经用startService()方法启动的Service。
4.后台(background)进程, 拥有一个当前用户看不到的Activity(它的onStop()方法被调用)。
5.空(empty)进程,不包含任何处于活动状态的应用程序组件。
onSaveInstanceState():当应用遇到意外情况由系统销毁一个Activity时会调用此方法来缓存一些数据
onRestoreInstanceState():调用此方法恢复缓存的数据,
重写onSaveInstanceState()和onRestoreInstanceState()方法
privateString name;
protected voidonRestoreInstanceState(Bundle savedInstanceState) {
name = savedInstanceState.getString("name"); //被重新创建后恢复缓存的数据
super.onRestoreInstanceState(savedInstanceState); }
protected void onSaveInstanceState(BundleoutState) {
outState.putString("name", "liming");//被摧毁前缓存一些数据
super.onSaveInstanceState(outState); }
Bundle类用作携带数据,它类似于Map,用于存放key-value名值对形式的值。相对于Map,它提供了各种常用类型的putXxx()/getXxx()方法,如:putString()/getString()和putInt()/getInt(),putXxx()用于往Bundle对象放入数据,getXxx()方法用于从Bundle对象里获取数据。Bundle的内部实际上是使用了HashMap<String,Object>类型的变量来存放putXxx()方法放入的值:
publicfinal class Bundle implements Parcelable, Cloneable {
Map<String, Object> mMap;
public Bundle() {
mMap = new HashMap<String,Object>(); }
public void putString(String key, Stringvalue) {
mMap.put(key, value); }
publicString getString(String key) {
Object o = mMap.get(key);
return (String) o;
........//类型转换失败后会返回null,这里省略了类型转换失败后的处理代码} }
在调用Bundle对象的getXxx()方法时,方法内部会从该变量中获取数据,然后对数据进行类型转换,转换成什么类型由方法的Xxx决定,getXxx()方法会把转换后的值返回。
请求码用于标识结果数据来自哪个startActivityForResult(Intent intent, int requestCode)方法
结果码用于为结果数据定义唯一id
2. BroadcastReceiver(广播接收者):
OnReceive()方法在10秒内没有执行,androidh会认为该程序无响应
两种注册方式:代码注册,manifest中配置
声明周期较短. 如有耗时的工作,应该通过发送Intent给Service.由Service来解决,不能让子线程解决
短信窃听器: 继承BroadcastReceiver intent的action名称为:android.provider.Telephony.SMS_RECEIVED
获取信息内容:
Object[] pdus = (Object[])intent.getExtras().get(“pdus”); 系统内部自动对pdus进行解析
循环迭代信息内容
For(Object[] pdu : pdus)
格式转换”2011-01-0112:00:00”
SimpleDateFormat format = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”)
String time = format.format(date)
拦截外拨电话:
获取拨打的号码 getResultData();
将获取到得号码设置为null setResultData(null);
两种类型:: 粘性广播
普通广播(Normalbroadcasts), :接受者不能将处理结果传递给下一个接收者.并且无法终止广播Intent的广播
有序广播(Orderedbroadcasts):系统发出的广播为有序广播, 有序广播按照接受者声明的优先级别被接受者一次接收广播
a.在<intent-filterandroid:priority=1000>属性中声明,数值越大优先级别越高,取值范围”-1000--1000”
b调用intentFilter对象的Priority()设置通过调用IntentFilter对象的setPriority()进行设置
配置广播清单:在AndroidManifest.xml中
<application>
<receiveranroid:name= “.SMSBroadcastReceiver”>
<intent-filter>
<action android:name=”android.provider.Telephony.SMS_RECEIVED/>
</intent-filter>
</receiver>
</application>
abortBroadcast();//终止广播传递
AIDL(android interface definition language) -
一种接口定义语言 约束两个进程间的通讯规则,供编译器生成代码,实现与两个进程之间的通信
文件后缀名为 aidl
InterfaceIPersonService {
String sayHello(String name)
} android自动在gen目录下生产对应的java类
1.接口名与aidl文件名相同
2.接口和方法千不用加访问权限修饰符:public orivate,protected等.也不能用final ,static
3. Aidl默认支持类型包括java基本类型(int,long,boolean等)和(String,Llist,Map,CharSeqence),使用这些类型是不需要import声明 ,对于list和map中的元素类型必须是Aidl支持的类型,如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口
4自定义类型和AIDL生成的其他接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中
5 在aidl文件中所有非java基本数据类型参数必须加上in ,outinout标记.以指明参数是输入参数.输出参数还是输入输出参数
6 java原始类型默认的标记为in.不能为其他标记
3.Service(服务):一个生命周期长并且没有用户界面的程序
在系统后台运行
onCreate(),只在服务创建时调用一次. 无论调用多少次startService()或bindservice().服务也只创建一次
启动方式:
Stratservice:
第一次启动at()àonStartCommand()
启动后startCommand()
Stopservice:
Ondestroy();
服务与访问者在同一应用,仅供内部访问称为本地服务 ――内存交互
服务与访问者在不同应用.属于外部调用访问则为远程服务 -通过操作系统中介进行交互
继承Service类.android.app包
startService()启动服务stopservice()关闭服务–适用于服务和访问者之间没有交互
在androidManifest.xml文件中<application>节点里对服务进行配置
媒体刻录机: MediaRecorder recorder =new MeidaRecorder();
电话窃听器:
监听电话三种状态:
空闲状态:LISTEN_CALL_IDLE
响铃状态:LISTEN_STATE_RINGING
接听状态:LISTEN_STATE_OFFHOOK
注册监听器:
将录音文件保存在SDCARD根目录下
<service android:name read_phone_start>;
将录音文件上传到服务器中:
bindService()启动服务 unbindService()关闭服务 –适用服务与访问者之间需要方法调用或者传递参数
IBinder:远程过程调用的核心部分
4.Content Provider(内容提供者):实现程序与程序间的数据共享
,需要在androidMainfest.XML声明
<uses-permissionandroid:name=”android:name=”android.permission.READ_CONTACTS”></uses-permission>
5.Intent(意图):通过intent激活其他组建 三种核心组件,活动,广播接受者,服务
1.用于返回新Activity结束后的结果数据:
StartActivityForResult(intent,resultCode标识应用中的调用位置);
2.重写 onActivityResult方法
protected void onActivityResult(int requestCode, intresultCode, Intent data)
用于往Activity传递数据
Activity1: Intent.putExtre(“name”, “名称”); //添加数据
Activity2: intent.getintent(); String name = intent.getStringExtra(“name”); //获取Activity1的数据
显式意图:调用intent.setcomponet()intent.setclassName()或intent.setclass()方法明确指定了组件名
隐式意图:根据设置的动作(action),类别(category),数据(URI和数据类型)找到合适的组件来处理
没有数据内容项的时候intent中的Action和category都必须出现在intentfileer中
隐式方法中设置的动作(action),类别(category),数据(URI和数据类型)必须与intent-filter中的设置一致
<intent-filter>
<action android:name = “android.intent.action.CALL”/>
<categoy android:name = ”android:intent.actionINTENT”/>
<data android:scheme=””android:host:”主机名” android:path=”路径”/>
<data android:mimeType=”image/*”/>
SetType():会自动清除setData()所设置的数据,所以要用到setDataAndType(setData() , SetType());
应用之间激活对方组件使用隐式
应用内部激活自身组件使用显式
startActivity();--激活制定的Activity
在一个程序中添加多个Activity
任务堆栈存放每个Activity实例的。当应用新打开时 ,入口activity会放在任务堆栈顶部,当在入口activity中激活了新的activity时,新的activity实例会放在堆栈顶部
默认行为:采用intent激活组建,会创建一个新的组件实例,放在堆栈顶部。
修改需要在 AndroidManifest.xml 配置对应的
android:launchMode=”
standard-默认行为;
singleTop-当Activity存在时,使用intent激活时重新调用该Activity;
singleTask-打开Activity时会在新的堆栈中执行-新进程中运行;
singleInstance-Activity在堆栈中存在时直接打开,永远保持一个Activity;”
Applicationname: 应用的名称.默认出现在程序的图标的底下,标题栏.可以进行修改.
Package:包名为一标识一个应用.,一般存放java源文件.
GreateActivity: 代表一个可以接收用户输入信息,事件的窗口.
MinSDK Version:版本对应的级别.
像素单位,
px–, dip || dp----常用像素密度使用 , sp, --文字使用
<applicationandroid:icon="@drawable/应用图标名称"android:label="@string/app_name">
Android中数据采用URI表示 Setdata(Uri.parese(“”));
调用 StartActivity() ;方法把意图传给操作系统. 激活对应的Activity
<uses-permissionandroid:name=”android.permission.INTERNET”/>访问网络权限设置
权限:定义….summary类.
//方法的内部会自动为intent对象设置类别:android.intent.category.DEFAULT
权限定义在XML文件<uses-permission android :name =”android.permission.CALL_PHONE”>;
短信发送器:
短信字符限制:70个汉字(包括标点),150个英文字母.
短信拆分.------SmsMaager.getDefault();
短信发送:
SendTextMessage((destinationAddress)手机号, (scAddress)短信中心地址默认为null, 短信内容(text),(sentIntent)传一个广播意图,获取发送短信后的状态默认为null, (deliveryintent)得到发送短信后对方是否收到短信的状态默认为null)
通知方式:
Toast.makeText(context(上下文对象)类名.this或getapplicationcontext(),指定文字的自然ID text, dutation(toast在屏幕上显示的时间 Toast.0或1)).show();
单元测试: 新建等待测试的业务类; 单元测试包跟应用包同名.
单元测试类继承AndroidTestCase,
//定义一个TAG方法,进行测试;
private static final String TAG ="PersonServiceTest";
//方法名称必须加上test
public void testSave() throws Throwable{
测试权限设置:在<application>节点下,放置单元测试库
<application>
<uses-library android:name="android.test.runner"/>
</application >
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="cn.test" android:label="Testsfor My App" />
结果检验..方法是否正常.
Tag: 输出日志信息
Log.v(TAG, "VERBOSE"); //verbose –所有信息
Log.d(TAG,"DEBUG"); //debug-除错
Log.i(TAG,"INFO"); //info-信息
Log.w(TAG,"WARN"); //warn-警告
Log.e(TAG, "ERROR"); //error-错误
ListVIew控件:用于将各种控件,数据显示到屏幕上
了解ListView的用法.如何将数据显示到屏幕上,添加点击事件进行操作
定义简单的适配器用来将绑定数据显示到ListView控件上:
1.Simpleadapter:
用于得到给定数据索引位置的数据对象getitemAcposition(),内部使用get()方法取得数据的位置
获取ListView中数据进行点击事件.
通过调用数据的索引位置来进行点击事件
2.当业务bean返回类型为cursor类型时:
业务bean中Cursor游标对象不能关闭,适配器对cursor对象进行迭代访问,关闭后无法得到数据
表主键取名时 id 建议取名加 _id;否则会出错
使用SimpleCursorAdapter
数据存储与访问:
文件存储:
保存的文件默认存放在/data/data/<package>/files目录下
Context.Openfileoutput(文件名称,文件的操作模式(Context.MODE_PRIVATE)私有操作模式只能在本应用操作文件,以覆盖方式写入数据); //创建一个文件.默认存放在手机存储空间
4种文件操作方式:
1. context.MODE_PRIVATE:默认操作模式,只能被应用本身进行读取写入.以覆盖方式写入数据
2. context.MODE_APPEND:文件存在则在文件末尾追加内容.否则创建新文件
3. context.MODE_WORLD_READABLE:能被其他应用读取数据.
4. context.MODE_WORLD_WRITEABLE:能被其他应用写入数据.不能被读取要追加内容需要改变路径保存方式(path, true()默认为false以覆盖方式写入数据)
getcacheDIr();获取/data/data/<packagename>/cache 目录---保存缓存
getfileDir();获取/data/data/<packagename>/file 目录---保存文件
(context.MODE_WORLD_READABLE+context.MODE_WORLD_WRITEABLE);
通过this.openfileputput(“…”,context.Mode_private)方法保存文件.文件将存储在默认目录下
调用这个方法取得外存储设备的路径,应对不同版本的系统:
Environment.getEcternalStorageDirectory(),filename;
首先判断SDcard是否存在
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
File sdCardDir =Environment.getExternalStorageDirectory();//获取SDCard目录
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Sharedpreferences配置参数保存:存放软件的配置参数
/shared_prets目录下
This.getSharedpreference(“??”,);--追加方式存储数据
获取编辑框内容:edit.putString(“name”, name);
Edit.putInt(“age”,age);
调用 edit.commit() ,回写到文件中
数据默认保存在内存中 ,
SQLite数据库:
SQlite: 存储地址:/data/data/<package_name>/databases
关系型数据库.支持5种据类型:NULL, NTEGER,EAL(浮点数字),EXT(字符串文本),LOB(二进制对象)
无需加载数据库.自动加载驱动
存储字段无数据类型限制 可以保存任何类型数据.
Super(content, “数据库名称”, 工厂方法.默认为null, 版本号:数据库第一次创建版本号为0
.获取5条记录.跳过前面3条
Select*fromAccount limit 5 offset 3
继承 SQLiteOpenHelper------- .
通过getreadabledata (一般用于读取数据)
或 .getwriteabledata (一般用于修改数据)
创建数据库
操作数据库使用openorcreateDatanase,存在则打开,不存在则创建,创建成功返回SQLiteDatabase对象
创建表:
CREATE TABLE person(personid integer primary key autoincrement, name varchar(20));
查询表:
privateDBOpenHelper dbOpenHelper;
public PersonService(Contextcontext){
dbOpenHelper = newDBOpenHelper(context);
}
public void payment(){
SQLiteDatabase db =dbOpenHelper.getWritableDatabase();
db.beginTransaction(); //开启事务
try{
db.execSQL("updateperson set amount=amount-10 where personid=2");
db.execSQL("updateperson set amount=amount+10 where personid=3");
db.setTransactionSuccessful();
}finally{
//默认情况下,事务标志为False
db.endTransaction();//提交还是回滚,是由事务标志决定的,如果事务的标志为True,就会提交事务,否则回滚事务
} }
public voidsave(Person person){
SQLiteDatabase db =dbOpenHelper.getWritableDatabase();
db.execSQL("insertinto person(name,phone,amount) values(?,?,?)",
newObject[]{person.getName(), person.getPhone(), person.getAmount()});
//db.close();
}
public voiddelete(Integer id){
SQLiteDatabase db =dbOpenHelper.getWritableDatabase();
db.execSQL("deletefrom person where personid=?", new Object[]{id});
}
public voidupdate(Person person){
SQLiteDatabase db =dbOpenHelper.getWritableDatabase();
db.execSQL("updateperson set name=?,phone=?,amount=? where personid=?",
newObject[]{person.getName(), person.getPhone(), person.getAmount(),person.getId()});
}
public Personfind(Integer id){
SQLiteDatabase db =dbOpenHelper.getReadableDatabase();
Cursorcursor = db.rawQuery("select * from person where personid=?", newString[]{id.toString()});
if(cursor.moveToFirst()){
String name =cursor.getString(cursor.getColumnIndex("name"));
String phone =cursor.getString(cursor.getColumnIndex("phone"));
int amount =cursor.getInt(cursor.getColumnIndex("amount"));
cursor.close();
return newPerson(id, name, phone, amount); }
return null; }
publicList<Person> getScrollData(int offset, int maxResult){
List<Person> persons =new ArrayList<Person>();
SQLiteDatabase db =dbOpenHelper.getReadableDatabase();
Cursorcursor = db.rawQuery("select * from person order by personid asc limit?,?",
newString[]{String.valueOf(offset), String.valueOf(maxResult)});
while(cursor.moveToNext()){
Integer id =cursor.getInt(cursor.getColumnIndex("personid"));
String name =cursor.getString(cursor.getColumnIndex("name"));
String phone =cursor.getString(cursor.getColumnIndex("phone"));
int amount =cursor.getInt(cursor.getColumnIndex("amount"));
persons.add(newPerson(id, name, phone, amount)); }
cursor.close();
return persons;
}
public longgetCount(){
SQLiteDatabase db =dbOpenHelper.getReadableDatabase();
Cursorcursor = db.rawQuery("select count(*) from person", null);
cursor.moveToFirst();
long result=cursor.getLong(0);
cursor.close();
return result; } }
通过cursor对象对结果集进行随即访问.移动游标指针到指定位置 .rawQuery
用Cursor类来实现;使用 SQLiteDataBase.query()返回cursor对象
事务操作: beginTransaction() //开启事务
设置调用事务try{ setTransactionSuccessful()}
finally{ EndTransaction()}//提交事务,默认为fals;如果事务的标志为True,就会提交事务,否则回滚事务}
隔离级别:1,读未提交 2, 读已提交 4,可以重复读 8,串行化.悲观锁,不支持并发,安全性高,性能低
网络(在互联网服务器中存储)Network:
通过“GET” “POST”方法获取静态页面,
1. 检测网络状态:
ConnectivityManager cm = (ConnectivityManager)Context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
netInfo.toString();
2. 使用网络权限
<uses-permissionandroid:name="android.permission.INTERNET"/>
3. 通过URL+HttpURLConnection获得数据(文本和图片) 注:HttpUrlConnection中的is和os都是指body部分的数据.
URL url =new URL("http://www.sohu.com");
HttpURLConnectionconn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5*1000); //设置超时时间
conn.setRequestMethod("GET");//设置提交方法
conn.getResponseCode()!= 200) throw ..; //响应码
InputStreamis = conn.getInputStream();
Stringresult = readData(is, "GBK");
conn.disconnect();
//获取图片同上.
内容提供者(Content Provider)数据对外共享
统一数据的访问方式
ContentProvider,可通过2种方法:
1.创建一个属于你自己的ContentProvider
2.将你的数据添加到一个已经存在的ContentProvider中,当然前提是有相同数
据类型并且有写入Content provider的权限。
1.当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写下面方法:
publicclass PersonContentProvider extends ContentProvider{
onCreate()
Uri insert(Uri uri, ContentValuesvalues)
int delete(Uri uri, Stringselection, String[] selectionArgs)
int update(Uri uri, ContentValuesvalues, String selection, String[] selectionArgs)
Cursor query(Uri uri, String[]projection, String selection, String[] selectionArgs, String sortOrder)
getType(Uri uri)}
通过contentresolver()取得共享数据
2.第二步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider , ContentProvider 采用了authorities(主机名/域名)对它进行唯一标识,你可以把 ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:
<manifest .... >
<application android:icon="@drawable/icon"android:label="@string/app_name">
<providerandroid:name=".类名" android:authorities="给定的唯一标识cn.itcast.providers.personprovider"/>
</application>
</manifest>
PrivateContext context; //声明一个上下文对象
实现contentresolver接口 通过getcontentresolver()方法取得contentresolver对象
Adapter()适配器:条目界面与数据的绑定
内容观察者:
XML解析:<元素节点>,<文本节点>
1. DOM:基于XML文档树结构的解析,占用内存较高,适合随机访问XML文件(两次加载)
Document object model
2. SAX:基于事件流的解析方式.顺序访问xml文件内容,适合顺序访问,不可暂停或倒退,每一个文档,元素的开始或结束都会触发一个事件.(一次加载)
StartDocument StartElement endElement endDocumentcharacter
获取
重写StartDocument StartElement endElement endDocument character 方法
3. PULL:基于XML节点内容对象,适合选择访问 Parser.next().获取下一个类型节点,
XmlPullParser parser = newXmlPullParser();
解析XML文件类:XmlPullParser
public class PullXMLReader {
public static List<Person>readXML(InputStream inStream) {
XmlPullParserparser = Xml.newPullParser();
try{
parser.setInput(inStream,"UTF-8");
inteventType = parser.getEventType();
PersoncurrentPerson = null;
List<Person>persons = null;
while(eventType != XmlPullParser.END_DOCUMENT) {
switch(eventType) {
XmlPullParser.START_DOCUMENT://文档开始事件,可以进行数据初始化处理
persons= new ArrayList<Person>();
break;
XmlPullParser.START_TAG://开始元素事件
Stringname = parser.getName();
if(name.equalsIgnoreCase("person")) {
currentPerson= new Person();
currentPerson.setId(newInteger(parser.getAttributeValue(null, "id")));
}else if (currentPerson != null) {
if(name.equalsIgnoreCase("name")) {
currentPerson.setName(parser.nextText());//如果后面是Text节点,即返回它的值
}else if (name.equalsIgnoreCase("age")) {
currentPerson.setAge(newShort(parser.nextText())); } }
break;
XmlPullParser.END_TAG://结束元素事件
if(parser.getName().equalsIgnoreCase("person") && currentPerson!= null) {
persons.add(currentPerson);
currentPerson= null; }
break; }
eventType= parser.next(); }
inStream.close();
returnpersons;
}catch (Exception e) {
e.printStackTrace(); }
returnnull; } }
生成XML文件内容的序列化类: XmlSerializer
public static StringwriteXML(List<Person> persons, Writer writer){
XmlSerializer serializer =Xml.newSerializer();
try {
serializer.setOutput(writer);
serializer.startDocument("UTF-8", true);
//第一个参数为命名空间,如果不使用命名空间,可以设置为null
serializer.startTag("","persons");
for (Person person : persons){
serializer.startTag("","person");
serializer.attribute("","id", person.getId().toString());
serializer.startTag("","name");
serializer.text(person.getName());
serializer.endTag("","name");
serializer.startTag("","age");
serializer.text(person.getAge().toString());
serializer.endTag("","age");
serializer.endTag("","person"); }
serializer.endTag("","persons");
serializer.endDocument();
return writer.toString();
} catch (Exception e) {
e.printStackTrace(); }
return null; }
多线程:
Handler: 线程处理器负责将message和runable对象传递给messagequeue,并且在这些对象离开时,负责执行
MessageQueue:消息队列 message列表的底层类。Looper负责分发这些message。Messages并不是 直接加到一个MessageQueue中,而是通过MessageQueue.IdleHandler关联到Looper。
Looper: 线程轮偱器Looper类被用来执行一个线程中的message循环。默认情况,没有一个消息循环关联到线程。在线程中调用prepare()创建一个Looper,然后用loop()来处理messages,直到循环终止
动画:
Tween:
Alpha:渐变透明度
Scale:渐变尺寸伸缩
Translate:画面转换位置移动
Rotate:画面转移旋转
Frame动画 帧动画,类似于GIF动画,配置好每个图片,安装每一帧的顺序,出现时间进行更换
显示:
/* 设置为无标题栏 */
requestWindowFeature(Window.FEATURE_NO_TITLE);
/* 设置为全屏模式 */
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
/* 设置为横屏 */
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);;
多媒体:
Open Core(PV,PacketVideo): 多媒体框架的核心
PVPlayer:媒体播放器—音频(Audio),视频(Video)流的回放
PVAuthor:媒体流记录—音频,视频流以及静态图像的捕获
getDuration() 获取播放文件总时间
音乐播放器:
音乐文件播放由MeidaPlayer 内部调用底层代码进行运行
MediaPlayermediaPlayer = new MediaPlayer();
if(mediaPlayer.isPlaying()) {
mediaPlayer.reset();//重置为初始状态
}
mediaPlayer.setDataSource("/mnt/sdcard/god.mp3");
mediaPlayer.prepare();
mediaPlayer.start();//开始或恢复播放
mediaPlayer.pause();//暂停播放
定义一个变量,记录播放位置
mediaPlayer.start();//恢复播放
mediaPlayer.stop();//停止播放
mediaPlayer.release();//释放资源
mediaPlayer.setOnCompletionListener(newMediaPlayer.OnCompletionListener() {//播出完毕事件
@Override public voidonCompletion(MediaPlayer arg0) {
mediaPlayer.release(); }
});
mediaPlayer.setOnErrorListener(newMediaPlayer.OnErrorListener() {// 错误处理事件
@Override public booleanonError(MediaPlayer player, int arg1, int arg2) {
mediaPlayer.release();
return false; } });
setVisibility
//绑定拖动条-获取媒体的长度
private void refreshSeekbar() {
Runnable r = new Runnable() {
public void run() {
if(player.isPlaying()){
intcurrPos = player.getCurrentPosition();
bar.setProgress(currPos);
h.postDelayed(this,500);
} } };
//清除队列中r消息.
h.removeCallbacks(r);
//发送r对象到消息队列
h.post(r); }
视频播放器:
当SurfaceView所在的Activity不在前台,SurfaceView会被销毁,如果Activity重新回到前台SurfaceView会被重新创建,但SurfaceView创建的时间会在OnResunme()方法之后.,
需要创建回调监听时间. 模拟器2.1以上版本不能正常播放视频文件
SurfaceView –表层视图绘图界面 .显示视频界面
surfaceView.getHolder() –获取控制对象,以显示内容-进行图画操作
在main.xml布局文件添加用于视频画面绘制的SurfaceView 控件:
<SurfaceView android:layout_width="fill_parent" android:layout_height="240dip"android:id="@+id/surfaceView"/>
SurfaceViewsurfaceView = (SurfaceView)this.findViewById(R.id.surfaceView);
surfaceView.getHolder().setFixedSize(176,144); //设置分辨率
/*下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前*/
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
MediaPlayermediaPlayer = new MediaPlayer();
mediaPlayer.reset();//重置为初始状态
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
/* 设置Video影片以SurfaceHolder播放 */
mediaPlayer.setDisplay(surfaceView.getHolder());
mediaPlayer.setDataSource("/mnt/sdcard/oppo.mp4");
mediaPlayer.prepare();
mediaPlayer.start();//播放
mediaPlayer.pause();//暂停播放
mediaPlayer.start();//恢复播放
mediaPlayer.stop();//停止播放
mediaPlayer.release();//释放
在线视频播放:
流媒体两种分发方式:
渐进式下载(Progressive Download) :可以通过HTTP或FTP协议来分发,需要Web服务器或者FTP服务器
需要将视频文件转换为渐进式视频文件-3G格式
实时流媒体: 通过RTP和RTSP这种实时协议来分发,那样的话就需要一个流媒体服务器
网络通信:
HTTP通信:
”一次连接” 连接过程:客户端->发送请求->服务器回送响应->释放连接
3种网络接口:
java.net*(标准java接口), 提供与联网有关的类,包括流和数据包套接字,Internet协议,常见HTTP处理
orgapache(Apache接口), HTTPClient 更加完善的HTTP扩展开源项目
android.net*(Android网络接口)
HttpClient接口: 使用HttpClient上传文件缓存超过1M会出现内存溢出
1. clientConnectionManager接口:客户端连接管理器接口,提供几个抽象方法:
clientconnectionManager-关闭所有无效,超时的连接
chosedleConnections- 关闭空闲的连接
releaseconnection-释放一个连接
requestConnection-请求一个新的连接
shutdown-关闭管理器并释放资源
2. defaultHttpClient:默认的一个HTTP客户端,可以使用创建一个HTTP连接:
例子:HttpClient httoclient= newDefaultHttpClient();
3. HttpResphone:是一个Http连接响应,当执行一个HTTP连接后,就会返回一个HttpResponse,可以通过HttpResphonse获得一些响应信息, 请求HTTP连接并获得请求是否成功的代码:
HttpResponse httpResponse=httpclient.execute(httpRequest);
If(httpResponse,getStatusLine().getStatusCode()==HttpStatus.SC_OK){
//连接成功
}
Socket通信:
用于描述IP地址和端口,是一个通信链的句柄
包含进行网络通信必须得5种信息:
1.连接使用的协议, 2.本地主机的IP地址, 3.本地进程的协议端口,
4.远地主机的IP地址, 5.远地进程的协议端口
两种主要的操作方式: 面向连接和无连接
Webservice:
调用API.用于对各个独立的应用程序之间进行串联调用www.webxml.com.cn
Soapaction-请求头soap有.1.2没.1.2加上会报错
公开在网络上的API,通过soap协议调用(基于XML语法)
wsdl:用于查看描述接口语言
使用webservice调用手机归属地API进行归属地查询:
/*@param mobile 手机号*/
public static String getAddress(Stringmobile) throws Exception{
InputStream inStream =MobileService.class.getClassLoader().getResourceAsStream("soap12.xml");
byte[] data =StreamTool.read(inStream);
String xml = newString(data);
xml = xml.replaceAll("\\$mobile",mobile);
data = xml.getBytes();
http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx";
HttpURLConnection conn =(HttpURLConnection) new URL(path).openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type","application/soap+xml; charset=utf-8");//soap格式数据
conn.setRequestProperty("Content-Length",String.valueOf(data.length));
conn.getOutputStream().write(data);
if(conn.getResponseCode() ==200){
InputStreamsoapStream = conn.getInputStream();
returnparseXML(soapStream); }
return null; }
解析soap协议,得到返回结果
private static String parseXML(InputStreamsoapStream) throws Exception{
XmlPullParser pullParser =Xml.newPullParser();
pullParser.setInput(soapStream,"UTF-8");
int event =pullParser.getEventType();
while(event!=XmlPullParser.END_DOCUMENT){
switch (event) {
caseXmlPullParser.START_TAG:
if("getMobileCodeInfoResult".equals(pullParser.getName())){
returnpullParser.nextText(); }
break; }
event =pullParser.next(); }
return null; } }
//调用手机归属地的SOAP协议
<?xmlversion="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<getMobileCodeInfoxmlns="http://WebXml.com.cn/">
<mobileCode>$mobile</mobileCode>
<userID> </userID>
</getMobileCodeInfo>
</soap12:Body>
</soap12:Envelope>
手势识别:
第一步:建立手势库
使用SDK自带例子GestureBuilder建立手势库(位置:android-sdk-windows\samples\android-8\GestureBuilder)。使用 GestureBuilder之前,你需要恢复其到开发环境,然后进行编绎并部署到手机上。此时,就可以使用GestureBuilder建立手势库,生成的手势库文件在SCDard上,默认文件名称为:gestures
第二步:在应用中加载手势库文件,然后开发手势识别代码。
把手势库文件gestures文件拷贝到项目的res/raw目录下。然后在布局文件中添加用于手势绘制的View:
android.gesture.GestureOverlayView
android:id="@+id/gestures"
android:layout_width="fill_parent“android:layout_height="0dip"
android:layout_weight="1.0" />
为View添加手势监听事件:gestureOverlayView.addOnGesturePerformedListener();
监听单笔事件overlayView.addOnGesturePerformedListener(newGestureListener());
监听多笔事件:overlayView.addOnGrestureListener(newGestureListener());
得到手势库:mLibrary =GestureLibraries.fromRawResource(this, R.raw.gestures);
加载手势库:mLibrary.load();List<Prediction>predictions = mLibrary.recognize(gesture);
//从手势库中查询匹配的内容,匹配的结果可能包括多个相似的内容,匹配度高的结果放在最前面
大多数情况下,手势都是通过一笔完成。然而有一些特别的需求就需要通过多个笔画来实现,这时可以使多笔手势:
用gestureStrokeType属性进行设置:android:gestureStrokeType="multiple"
应用关闭:2.2之前版本
1.获取当前进程ID,杀死进程(建议使用)
Android.os.Proicess.killProcess(android.os.Process.myPid())
2.终止当前正在运行的java虚拟机,导致程序终止
System.exit(0);
3.强制关闭与该包有关联的一切执行
ActiviryManager manager =(ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
Manager.restartPackage(getPackageName());
<uses-permissionandroid:name=”android:permission.RESTART_PACKAGES”/>
Widget:(窗口小部件)
<metea-data>:
每个widget就是一个BroadcastReceiver(广播接受者)
使用XML metadata来描述Widget细节
WebKit应用:
开源的浏览器网页排版引擎
对应:Geko(Mozilla,Firefox等使用) Trident(也称MSHTML,IE使用)
可以运行HTML代码 可以与Javascript 互相调用
由3个模块组成:
JavaSciptCore: WebCore: WebKit
使用:在XML布局文件中定义webView控件:
<WebView
android:id =”+id/WebVIew”
android=layout_width=”fill_parent”
android=layout_heigth=”fill_parent”
android:layout_weigth=”1”/>
国际化:
文字,.图片.屏幕适配,样式,主题
控件:
话框通知(Dialog Notification):
当你的应用需要显示一个进度条或需要用户对信息进行确认时,可以使用对话框来完成。
下面代码将打开一个如右图所示的对话框:
new AlertDialog.Builder(context)
.setTitle("java培训")
.setCancelable(false) //设置不能通过“后退”按钮关闭对话框
.setMessage("浏览传智播客网站?")
.setPositiveButton("确认",
newDialogInterface.OnClickListener(){
public voidonClick(DialogInterface dialoginterface, int i){
Uri uri =Uri.parse("http://www.itcast.cn/");//打开链接
Intent intent = newIntent(Intent.ACTION_VIEW, uri);
startActivity(intent); } })
.setNegativeButton("取消", newDialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
dialog.cancel(); } })
.show();//显示对话框
上面代码采用的是一个链式调用,像setTitle()、setMessage()这些方法,他们的返回值都是当前对话框对象。
创建带单选项列表的对话框:
下面代码将打开一个如右上图所示的选项列表对话框:
finalString[] items = {"java", ".net", "php"};
newAlertDialog.Builder(SenderNotificationActivity.this).setTitle("选择语言")
.setItems(items, newDialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
Toast.makeText(getApplicationContext(), items[item],
Toast.LENGTH_SHORT).show();
}
}).show();//显示对话框
下面代码将打开一个如右下图所示的带单选框的列表对话框:
finalString[] items = {"java", ".net", "php"};
newAlertDialog.Builder(SenderNotificationActivity.this).setTitle("选择语言")
.setSingleChoiceItems(items,1, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int item) {
Toast.makeText(getApplicationContext(), items[item],
Toast.LENGTH_SHORT).show();
dialog.cancel(); }
}).show();//显示对话框
setSingleChoiceItems()的第二个参数是设置默认选项,
选项索引从0开始,-1代表不选择任何选项。
创建带多选项列表的对话框:
下面代码将打开一个如右下图所示的多选项列表对话框:
final String[] items = {"java",".net", "php"};
newAlertDialog.Builder(SenderNotificationActivity.this).setCancelable(false)
.setTitle("选择语言")
.setMultiChoiceItems(items, newboolean[]{false,true,false}, new DialogInterface.OnMultiChoiceClickListener() {
@Override
publicvoid onClick(DialogInterface dialog, int which, boolean isChecked) {
if(isChecked){
Toast.makeText(getApplicationContext(),items[which],
Toast.LENGTH_SHORT).show(); } } })
.setPositiveButton("确认",
newDialogInterface.OnClickListener(){
publicvoid onClick(DialogInterface dialoginterface, int i){
dialoginterface.dismiss(); }})
.show();//显示对话框
进度对话框(ProgressDialog)
使用代码ProgressDialog.show(ProgressDialogActivity.this,"请稍等", "数据正在加载中...", true);创建并显示一个进度对话框。
调用setProgressStyle()方法设置进度对话框风格。有两种风格:
ProgressDialog.STYLE_SPINNER 旋体进度条风格 (为默认风格)
ProgressDialog.STYLE_HORIZONTAL 横向进度条风格
单选框(RadioButton)
完成单选框显示,我们需要使用到RadioGroup和RadioButton(单选框),RadioGroup用于对单选框进行分组,相同组内的单选框只有一个单选框能被选中。(例子代码请见下方备注栏)
RadioGroup.check(R.id.dotNet);将id名为dotNet的单选框设置成选中状态。
(RadioButton)findViewById(radioGroup.getCheckedRadioButtonId());//获取被选中的单选框。
RadioButton.getText();//获取单选框的值
调用setOnCheckedChangeListener()方法,处理单选框被选择事件,把RadioGroup.OnCheckedChangeListener实例作为参数传入
多选框(CheckBox)
每个多选框都是独立的,可以通过迭代所有多选框,然后根据其状态是否被选中再获取其值。
CheckBox.setChecked(true);//设置成选中状态。
CheckBox.getText();//获取多选框的值
调用setOnCheckedChangeListener()方法,处理多选框被选择事件,把CompoundButton.OnCheckedChangeListener实例作为参数传入
下拉列表框(Spinner)
Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值
调用setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入
下拉列表框—采用javabean作为Adapter元素
很多时候显示在下拉列表框的值并不是希望得到的值,如果要做一个联系人下拉列表框,列表框列出的是联系人的姓名,因为姓名有可能相同,所以我们希望得到的值应该为该联系人的id,要实现这种需求我们需要自定义Adapter,当然自定义Adapter需要我们编写一小段代码,如果我们不想编写Adapter,又能实现我们的需求,那是最好不过的了。通过观察ArrayAdapter中getView(int position, View convertView,ViewGroup parent)的内部代码发现,如果为ArrayAdapter指定的实际泛型参数类型没有实现CharSequence(字符串)接口,将会调用该类型对象的toString()向下拉列表框输出显示值。利用这个特点我们可以重写javaBean的toString()向下拉列表框提供显示值。
下拉列表框--自定义选项界面样式
Spinner.getItemAtPosition(Spinner.getSelectedItemPosition());获取下拉列表框的值
调用setOnItemSelectedListener()方法,处理下拉列表框被选择事件,把AdapterView.OnItemSelectedListener实例作为参数传入
拖动条(SeekBar)
SeekBar.getProgress()获取拖动条当前值
调用setOnSeekBarChangeListener()方法,处理拖动条值变化事件,把SeekBar.OnSeekBarChangeListener实例作为参数传入
菜单(Menu)
重写Activity的onCreateOptionsMenu(Menumenu)方法,该方法用于创建选项菜单,在用户按下手机的“Menu”按钮时就会显示创建好的菜单,在onCreateOptionsMenu(Menu menu)方法内部可以调用Menu.add()方法实现菜单的添加。
重写Activity的onMenuItemSelected()方法,该方法用于处理菜单被选择事件
进度条(ProgressBar)
在布局xml文件中添加进度条代码:
<ProgressBar
android:layout_width="fill_parent"
android:layout_height="20px"
style="?android:attr/progressBarStyleHorizontal"
android:id="@+id/downloadbar"/>
在代码中操作进度条:
ProgressBar.setMax(100);//设置最大刻度
ProgressBar.setProgress(0);//设置进度条的当前刻度,如果进度条的最大刻度为100,当前刻度为50,进度条将进行到一半。
通过手机上提供的“MENU”按钮可以打开菜单,如果希望通过代码打开菜单,可以调用Activity的openOptionsMenu()方法。
输入内容自动完成文本框(AutoCompleteTextView)
AutoCompleteTextView和EditText组件类似,都可以输入文本。
但AutoCompleteTextView组件可以和一个字符串数组或List对象
绑定,当用户输入两个及以上字符时,系统将在
AutoCompleteTextView组件下方列出字符串数组中所有以输入
字符开头的字符串,这一点和www.google.com的搜索框非常相似,
当输入某一个要查找的字符串时,google搜索框就会列出以这个
字符串开头的最热门的搜索字符串列表。
<AutoCompleteTextView
android:layout_width="fill_parent“ android:layout_height="wrap_content“
<!– completionThreshold 指定至少输入几个字符后才会出现自动提示功能
android:completionThreshold="1“
android:id="@+id/name" />
public void onCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String[]names = {"老张","老方", "老毕", "李明" , "李丽", "陈江", "abc","acc"};
AutoCompleteTextViewnameText = (AutoCompleteTextView)this.findViewById(R.id.name);
ArrayAdapter<String>adapter = new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line, names);
nameText.setAdapter(adapter);
多次输入-内容自动完成文本框(MultiAutoCompleteTextView)
除了AutoCompleteTextView控件外,我们还可以使用MultiAutoCompleteTextView控件来完成连续输入的功能。也就是说,当输入完一个字符串后,在该字符串后面输入一个逗号(,),在逗号前后可以有任意多个空格,然后再输入一个字符串,仍然会显示自动提示列表。
使用MultiAutoCompleteTextView时,需要为它的setTokenizer方法指定MultiAutoCompleteTextView.CommaTokenizer类对象实例,
该对象表示采用逗号作为输入多个字符串的分隔符。
nameText.setTokenizer(newMultiAutoCompleteTextView.CommaTokenizer());
定义相应的文件夹,
判定SIM运营商
<uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/>
TelephonyManagertelManager = (TelephonyManager)
getSystemService(Context.TELEPHONY_SERVICE);
//移动(46000,46002),联通(46001),电信(46003)
Stringimsi = telManager.getSubscriberId();
imsi.startsWith("46002")
Stringoperator = telManager.getSimOperator();
operator.equals("46000");
Line1Number:手机号
NetworkOperatorName:网络运行商名称
SimSerialNumber:Sim卡序列号
提取SIM联系人
Uriuri = Uri.parse("content://icc/adn");
String[] projection = {"_id","name", "number"};
Cursor cursor = managedQuery(uri, projection,null, null, "name");
if(cursor!=null){
while(cursor.moveToNext()){
Stringname = cursor.getString(cursor.getColumnIndex("name"));
Stringphone = cursor.getString(cursor.getColumnIndex("number")); } }
在文件AndroidManifest.xml中添加权限
<uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/>
Android系统内部通过Contentprovider对外共享Sim卡存放的联系人等信息,你可以通过
操作Contentprovider来实现Sim卡信息的添删改查操作.
删除呼叫记录
在文件AndroidManifest.xml中添加权限
<uses-permissionandroid:name="android.permission.READ_CONTACTS" />
<uses-permissionandroid:name="android.permission.WRITE_CONTACTS" />
负责存放呼叫记录的内容提供者源码在ContactsProvider项目下:
源码路径:
com\android\providers\contacts\CallLogProvider.java
CallLog.Calls.URI:
使用到的数据库在:
/data/data/com.android.providers.contacts/databases/contacts2.db
表名:calls
呼叫记录有三种类型:
来电:CallLog.Calls.INCOMING_TYPE(常量值:1)
外拔:CallLog.Calls.OUTGOING_TYPE(常量值:2)
未接:CallLog.Calls.MISSED_TYPE(常量值:3)
使用ndk开发android程序(本地文件开发包)
NDK不是替换掉SDK,而是增强他们,不能使用NDK创建独立的应用程序,NDK编译C的代码到类库中供java程
序调用,NDK处理打包过程,确保APK文件既包含java代码又包含类库.
绝大多数程序不需要考虑NDK开发,但如果执行大量按位运算,像原始信号转换,图像压缩,加密比较适合NDK开发,
NDK具有高效的内存使用和快捷的原始数据处理.通过c访问openGL库也能够得到更好的性能.
除了以上的情况外,许多linux程序是c编程实现,使用NDK可以对遗留的程序进行重用.
NDK编写的代码不保证在同样算法条件下比java代码执行更快,NDK不应被视为提升程序性能的自动选择,NDK是
问题复杂化,应全面考虑后再使用.NDK适合于自包含和CPU敏感型操作.这样,内存分配可保持在最小的状态.
查看NDK
1.下载ndk[http://developer.android.com/sdk/ndk]
查看${NDK解压目录}/toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\
2.使用NDK开发步骤
创建android项目
创建类库源文件夹
创建c源文件
创建Android.mk文件
改变目录到源文件夹,之心NDK命令
执行NDK到项目build中(可选)
查看任何编译/链接错误.
注: 文档中的案例在linux环境下运行的,在windows下不能执行ndk命令,需要单独下载cygwin才可以.
${ndk解压目录}/doc/INSTALL.html
windows需要安装Cygwin1.7.
ndk构建项目参考doc-->sdk-->androidndk1.4-->Getting Started with the NDK.
1.${project}/jni/c代码
2.创建${project}/jni/Android.mk文件
3.创建${project}/jni/Applicaiton.mk文件(可选)
4.在${project}目录下运行ndk-build脚本build本地代码.位于项目的定级目录
$cd <project>
$<ndk>/ndk-build
注: windows下需要进入到Cygwin.exe中进行ndk-build命令的执行
1.开始-->Cygwin
2.cdD:\eclipse-xxx\..\lsn_hellojni
3.d:\android-ndk-r6\ndk-build
4.完成
5.ide中刷新android项目
6.自动生成libs + obj文件夹,并生成so类库文件
7.运行.
android 软件列表读取 软件读取应用列表
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
android开发 读取应用列表权限 安卓9.0读取应用列表权限
首先系统介绍一下6.0权限以及初步处理方法,下一遍文章将会使用更简单易懂的方法去解决安卓6.0权限问题。Android6.0带来了新的权限管理方式,本文主要来源于官方文档,加入了自己的理解,目的是想总结Android6.0权限管理的新方式,其他部分可能主要是总结式的带过,后续再详细分析。一.Security Architecture(安全体系结构) Android安全体系结构的核心是:默认情况下没
android开发 读取应用列表权限 安卓6.0权限 Android6.0权 运行时权限 android Android