历史
- 2008年推出android1.0。
- 2011年10月,发布android4.0
概要
android系统架构
4层架构,5块区域
1. linux内核层
基于linux2.6内核,提供底层的驱动。
2. 系统运行库层
通过C/C++库提供主要特性支持。如sqlite,opengl,webkit,android运行时库(包括dalvik虚拟机)
3. 应用框架层
为应用程序提供api
4. 应用层
所有安装在手机上的应用程序,包括系统自带的。
搭建开发环境
需要的软件
- jdk
- android sdk
- android studio
分析android程序
android studio基本项目结构
- app/build
app模块build编译输出的目录 - app/build.gradle
app模块的gradle编译文件 - app/app.iml
app模块的配置文件 - app/proguard-rules.pro
app模块proguard文件 - build.gradle
项目的gradle编译文件 - settings.gradle
定义项目包含哪些模块 - gradlew
编译脚本,可以在命令行执行打包 - local.properties
配置SDK/NDK - MyApplication.iml
项目的配置文件 - External Libraries
项目依赖的Lib, 编译时自动下载的 - app/main/java
源码目录 - app/main/res
资源文件目录
核心文件解析
- AndroidManifest.xml
- 注册activity,设置主活动。
- Activity的java源文件
- 继承自Activity。
- 设置各阶段的业务代码
- res目录
- res/layout目录
存放所有的布局文件 - res/mip*
用来存放图片 - res/menu
用来放菜单文件 - res/values
用来存放字符串
如何引用资源:
- res/layout目录
- 代码中用R.string.string_name
- xml中用@string/string_name
使用日志
android中的日志工具类是Log(android.util.Log),提供了如下几种方法:
1. Log.v()
最琐碎,意义最小的日志
2. Log.d()
调试信息
3. Log.i()
info,打印一些比较重要的数据
4. Log.w()
警告信息
5. Log.e()
错误信息
活动(Activity)
包含用户界面的组件,主要用于和用户进行交互。一个应用程序中可以包含0个或者多个活动。
创建活动
- 新建一个类,继承自Activity,并重写onCreate()方法。
public class FirstActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
2.创建布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 1"
/>
</LinearLayout>
3.修改Activity代码
public class FirstActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
}
}
4.在AndroidManifest文件中注册activity
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest" >
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".FirstActivity"
android:label="This is FirstActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /><!--设置项目入口-->
<category android:name="android.intent.category.LAUNCHER" /><!--设置为启动程序-->
</intent-filter>
</activity>
</application>
</manifest>
5.销毁Activity,修改button对应的事件。
Button b1 = (Button)findViewById(R.id.t1);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
目的(Intent)
使用显式intent
通过intent启动另一个activity。
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});
使用隐式intent
1.通过activity标签的intent-filter指定当前activity可以响应的action和category。Action为系统中已经定义的一系列常用动作。Category属性用于指定当前动作(Action)被执行的环境。
<activity android:name=".SecondActivity" >
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" /><!-- 自定义的action-->
<category android:name="android.intent.category.DEFAULT" /><!--必须加上这个,否则下面无法直接使用自定的action-->
</intent-filter>
</activity>
2.修改按钮的点击事件。
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
}
});
更多隐式intent的用法
调用系统浏览器访问一个网页。
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
}
});
ACTION_VIEW是android系统内置的动作。
向下一个活动传递数据
intent提供了一系列putExtra()方法的重载,用来暂存需要传递的数据。启动另一个intent后,从intent中取出数据即可。
传递方:
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String data = "Hello SecondActivity";
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("extra_data", data);
startActivity(intent);
}
});
接收方
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.second_layout);
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity", data);
}
}
这里的getStringExtra可以用getIntExtra(),getBooleanExtra()等方法代替。
返回数据给上一个活动
接收方
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(intent, 1);
}
});
....
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity", returnedData);
}
break;
default:
}
}
startActivityForResult的第二个整数用来唯一标识一次请求,传递方处理完数据后会传回给onActivityResult作为第一个参数。onActivityResult函数的第二个参数为返回码,用来判断处理是否成功,第三个参数为携带详细数据的intent。处理时一般先检查requestCode,判断数据来源。
传递方
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.second_layout);
Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("data_return", "Hello FirstActivity");
setResult(RESULT_OK, intent);
finish();
}
});
}
}
setResult的值一般只使用RESULT_OK或RESULT_CANCLED。
活动的生命周期
返回栈
Android是用任务来管理活动。一个任务就是一组存放在栈里的活动的集合,称作返回栈。栈后进先出,默认启动的新活动位于栈顶,当按下back键或者调用finish()方法时,栈顶活动出栈,前一个活动处于栈顶,并显示给用户。
活动状态
每个活动生命周期中会有4种状态。
1.运行状态
当一个活动位于返回栈的栈顶时,处于运行状态
2.暂停状态
活动不再处于栈顶位置,但是仍然可见。内存极低时,有可能被系统回收资源。
3.停止状态
不处于栈顶,并且完全不可见。有可能被系统回收资源。
4.销毁状态
活动从返回栈移除后。系统最倾向于回收这类活动的资源。
活动的生存期
activity类定义了七个回调方法,覆盖了活动生命周期的每个环节。
1.onCreate()
活动第一次创建时调用,一般用来完成初始化等操作。
2.onStart()
在活动由不可见变成可见时调用
3.onResume()
在活动准备好和用户进行交互时调用。此时活动一定处于运行状态。
4.onPause()
在系统准备启动或者恢复另一个活动时调用。通常用来释放资源和保存数据。
5.onStop()
在活动完全不可见时调用。
6.onRestart()
在活动由停止变成运行状态前调用。
活动回收前的数据保存
activity提供了一个onSaveInstanceState()回调方法,保证一定在活动被回收之前调用。可以通过这个方法来保存数据。
1.保存数据
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String tempData = "Something you just typed";
outState.putString("data_key", tempData);
}
2.提取数据
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG, tempData);
}
......
}
活动的启动模式
1.standard
默认模式,每次都会重新创建活动,并放在栈顶。同一个activity会出现多个实例。
2.singleTop
创建活动时如果发现该活动已经是栈顶,则直接返回。
3.singleTask
如果返回栈里有该活动,则直接返回。
4.singleInstance
新建一个返回栈来管理该活动。
5.退出程序的做法
使用队列,将所有activity出队列。
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<Activity>();
public static void addActivity(Activity activity) {
activities.add(activity);
}
public static void removeActivity(Activity activity) {
activities.remove(activity);
}
public static void finishAll() {
for (Activity activity : activities) {
if (!activity.isFinishing()) {
activity.finish();
}
}
}
}
分别在oncreate和ondestroy中调用方法。
public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
}
如果需要退出程序,调用ActivityCollector.finishAll()即可。
public class ThirdActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("ThirdActivity", "Task id is " + getTaskId());
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.third_layout);
Button button3 = (Button) findViewById(R.id.button_3);
button3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ActivityCollector.finishAll();
}
});
}
}
UI开发
常用android控件
1.textview
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is TextView" />
2.button
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
3.edittext
<EditText
android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
4.imageview显示图片
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
/>
5.progressbar进度条
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
6.alertdialog弹出对话框
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("This is Dialog");
dialog.setMessage("Something important.");
dialog.setCancelable(false);
dialog.setPositiveButton("OK", new DialogInterface.
OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.
OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.show();
break;
7.progressdialog缓冲对话框
ProgressDialog progressDialog = new ProgressDialog
(MainActivity.this);
progressDialog.setTitle("This is ProgressDialog");
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(true);
progressDialog.show();
3)
四种基本布局
1.linearlayout
线性布局,垂直或者水平方向布局。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
......
</LinearLayout>
2.relativelayout
相对布局。指定它们相对于其父元素或兄弟元素的位置。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="Button 2" />
...
</RelativeLayout>
3.framelayout
所有控件都放在左上角。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
/>
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
/>
</FrameLayout>
4.tablelayout
使用表格的方式来排列控件。
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TableRow>
<TextView
android:layout_height="wrap_content"
android:text="Account:" />
<EditText
android:id="@+id/account"
android:layout_height="wrap_content"
android:hint="Input your account" />
</TableRow>
...
</TableLayout>
自定义控件
所有控件继承自view,所有布局继承自viewgroup。
view是android最基本的UI组件,可以在屏幕上绘制一块矩形区域并响应这块区域的各种事件,所有的控件都是在view的基础上添加了各自特有的功能。
viewgroup是一种特殊的view,可以包含很多子view和子viewgroup,是一个用于放置控件和布局的容器。
引入布局
为了避免布局文件大量重复。
1.创建一个布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/title_bg" >
<Button
android:id="@+id/title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dip"
android:background="@drawable/back_bg"
android:text="Back"
android:textColor="#fff" />
</LinearLayout>
2.在需要的地方导入布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include layout="@layout/title" />
</LinearLayout>
自定义控件
1.新建控件类
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title, this);
Button titleBack = (Button) findViewById(R.id.title_back);
Button titleEdit = (Button) findViewById(R.id.title_edit);
titleBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((Activity) getContext()).finish();
}
});
titleEdit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(), "You clicked Edit button",
Toast.LENGTH_SHORT).show();
}
});
}
}
2.在布局文件中使用新建的控件。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.uicustomviews.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
></com.example.uicustomviews.TitleLayout>
</LinearLayout>
单位和尺寸
px表示像素,pt表示磅(1/72英寸)都会收到分辨率的影响。所以google引入了dp和sp。
dp是密度无关像素的意思,也称dip,在不同密度的屏幕中显示比例保持一致。
sp表示可伸缩像素,和dp概念一样,解决了文字大小适配问题。
android碎片
主要是用来处理大屏幕的访问问题,比如在平板上使用碎片显示更多的内容。
全局大喇叭
android中每个应用程序都可以对自己感兴趣的广播进行注册。
广播的类型
1.标准广播
是一种完全一部执行的广播,广播发出后,所有的广播接收器几乎同时收到广播消息,没有先后顺序,无法被截断。
2.有序广播
是同步执行的广播,发出后同一时刻只会有一个广播接收器能收到这条广播消息,该接收器的逻辑执行完毕后,广播继续传递。可以截断正在传递的广播。
接受系统的广播
1.动态注册广播
新建一个类,继承自BroadcastReceiver,并重写父类的onreceive()方法。oncreate中使用registerReceiver进行注册,在ondestroy方法中调用unregisterreceiver方法取消注册。动态注册的广播一定要取消注册。
public class MainActivity extends Activity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "network changes",
Toast.LENGTH_SHORT).show();
}
}
}
2.静态注册实现开机启动
动态注册的问题在于必需要启动后才能接受到广播。静态注册可以在程序未启动时接收广播。
1)新建类,继承自BootCompleteReceiver。
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
}
}
2)在AndroidManifest.xml 中将这个广播接收器的类名注册进去。
这里出现了新的标签,所有静态注册的广播接收器都在这里进行注册。别忘了还要申请相应的权限。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcasttest"
android:versionCode="1"
android:versionName="1.0" >
......
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
......
<receiver android:name=".BootCompleteReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
发送自定义的广播
1.发送标准广播
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);
2.发送有序广播
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent, null);
阻止有序广播继续传播
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in MyBroadcastReceive",Toast.LENGTH_SHORT).show();
abortBroadcast();
}
}
3.使用本地广播
android引入了一套本地广播机制,所发出的广播只能在应用程序内部进行传递,并且本地广播接收器也只能接收来自本应用程序发出的广播,避免了安全性的问题。
区别:使用LocalBroadcastManager获取实例,发送和注册广播接收器时均使用该实例的方法。
localBroadcastManager = LocalBroadcastManager.getInstance(this);
// 获取实例
...
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
// 注册本地广播监听器
...
Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent); // 发送本地广播
...
localBroadcastManager.unregisterReceiver(localReceiver);//注销广播
...
class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received local broadcast",
Toast.LENGTH_SHORT).show();
}
}
数据存储全方案
android提供了3种方式用于简单地实现数据持久化功能。
1.文件存储
2.sharedpreference存储
3.数据库存储
文件存储
写文件
context类提供了一个openFileOutput方法,接收2个参数。
1.文件名,不包含路径。文件默认存储到/data/data/”package-name”/files/目录下。
2.模式。MODE_PRIVATE 和 MODE_APPEND。覆盖写和追加写。
FileOutputStream out = null;
BufferedWriter writer = null;
try {
out = openFileOutput("data", Context.MODE_PRIVATE);
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(data);
} catch (IOException e) {
e.printStackTrace();
}
读文件
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
in = openFileInput("data");
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
content.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return content.toString();
SharedPreferences存储
使用键值的方式来存储数据。SharedPreferences文件都是存放在/data/data/”package-name”/shared_prefs/目录下的,以xml格式进行管理。
三种获取SharedPreferences对象的方法
1.context类的getSharedPreferences()方法
第一个参数指定文件名。
第二个参数指定操作模式,MODE_PRIVATE 和MODE_MULTI_PROCESS。MODE_PRIVATE 是默认的操作模式,和直接传入 0 效果是相同的,表示只有当前的应用程序才可以对这个SharedPreferences 文件进行读写。 MODE_MULTI_PROCESS 则一般是用于会有多个进程中对同一个 SharedPreferences 文件进行读写的情况。
2.Activity 类中的 getPreferences()方法
只接收一个参数,指定操作模式。文件名默认为当前活动的类名。
3.PreferenceManager 类中的 getDefaultSharedPreferences()方法
只接收一个参数,指定操作模式。文件名默认为当前应用程序包名。
写入
1.调用SharedPreferences对象的edit方法获取Editor对象。
2.向edit对象添加数据
3.调用commit方法提交数据,完成存储。
SharedPreferences.Editor editor =getSharedPreferences("data",
MODE_PRIVATE).edit();
editor.putString("name", "Tom");
editor.putInt("age", 28);
editor.putBoolean("married", false);
editor.commit();
读取
SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
String name = pref.getString("name", "");
int age = pref.getInt("age", 0);
boolean married = pref.getBoolean("married", false);
Log.d("MainActivity", "name is " + name);
Log.d("MainActivity", "age is " + age);
Log.d("MainActivity", "married is " + married);
sqlite数据库存储
SharedPreferences存储只适用于保存一些简单的数据,当需要进行大量复杂的存储时,需要使用sqlite。
数据库文件会存放在/data/data/”package-name”/databases/目录下。
1.创建数据库
1)新建类,继承自SQLiteOpenHelper,重写oncreate和onupgrade方法。
oncreate方法只会在创建数据库时执行一次,onupgrade在每次修改数据库版本号后执行一次。
SQLiteOpenHelper 构造方法中接收四个参数,
第一个参数是 Context,
第二个参数是数据库名,
第三个参数允许我们在查询数据的时候返回一个自定义的 Cursor,一般都是传入 null。
第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。(新建或者修改表等操作后,增加该值。)
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "price real, "
+ "pages integer, "
+ "name text)";
private Context mContext;
public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Book");
onCreate(db);
}
}
2)调用该类,创建库。
private MyDatabaseHelper dbHelper;
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
2.插入数据
private MyDatabaseHelper dbHelper;
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
...
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// 开始组装第一条数据
values.put("name", "The Da Vinci Code");
values.put("author", "Dan Brown");
values.put("pages", 454);
values.put("price", 16.96);
db.insert("Book", null, values); // 插入第一条数据
values.clear();
// 开始组装第二条数据
values.put("name", "The Lost Symbol");
values.put("author", "Dan Brown");
values.put("pages", 510);
values.put("price", 19.95);
db.insert("Book", null, values); // 插入第二条数据
3.更新数据
values.put("price", 10.99);
db.update("Book", values, "name = ?", new String[] { "The DaVinci Code" });
4.删除数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "pages > ?", new String[] { "500" });
5.查询数据
query参数详情:
1)表名
2)需要查询的列
3)指定where的约束条件
4)为where中占位符提供具体的值
5)指定需要group by的列
6)对group by后的结果进一步约束
7)指定查询结果的排序方式
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 查询Book表中所有的数据
Cursor cursor = db.query("Book", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
// 遍历Cursor对象,取出数据并打印
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.d("MainActivity", "book name is " + name);
Log.d("MainActivity", "book author is " + author);
Log.d("MainActivity", "book pages is " + pages);
Log.d("MainActivity", "book price is " + price);
} while (cursor.moveToNext());
}
cursor.close();
6.使用sql操作数据库
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",new String[] { "The Lost Symbol", "Dan Brown", "510", "19.95" });
db.rawQuery("select * from Book", null);
7.使用事务
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction(); // 开启事务
....
db.endTransaction(); // 结束事务
跨程序共享数据
内容提供器
主要用于在不同应用程序之间实现数据共享的功能。
1.现有的内容提供器
android系统自带的电话薄等程序都提供了类似的访问接口。
内容 URI 是内容提供器中数据的唯一标识符,由两部分组成:权限(authority)和路径(path)。
权限是用于区分不同的应用程序,为了避免冲突,都会采用程序包名的方式来进行命名。比如某个程序的包名是 com.example.app,那么该程序对应的权限就可以命名为com.example.app.provider。
路径则是用于对同一应用程序中不同的表做区分的,通常都会添加到权限的后面。
最后,还需要在字符串的头部加上协议声明。
1)声明权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.contactstest"
android:versionCode="1"
android:versionName="1.0" >
......
<uses-permission android:name="android.permission.READ_CONTACTS" />
......
</manifest>
2)获取数据
Cursor cursor = null;
// 查询联系人数据
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, null, null, null);
while (cursor.moveToNext()) {
// 获取联系人姓名
String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
// 获取联系人手机号
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactsList.add(displayName + "\n" + number);
}
cursor.close();
2.创建自己的内容提供器
1)新建一个类,继承自ContentProvider,重写6个抽象方法。
public class MyProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {
return 0;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
}
运用手机多媒体
1.使用通知
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "This is ticker text", System.currentTimeMillis()); //第一个参数指定图片,第二个指定ticker内容,第三个指定通知创建时间
....
Intent intent = new Intent(this,NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent,PendingIntent.FLAG_CANCEL_CURRENT);//创建延迟intent
....
Uri soundUri = Uri.fromFile(new File("/system/media/audio/ringtones/Basic_tone.ogg"));
notification.sound = soundUri;//让通知发生的时候播放一段音频
notification.setLatestEventInfo(this, "This is content title","This is content text", pi);//第二个参数指定标题,第三个指定内容,第四个
manager.notify(1, notification);
2.接收和发送短信
使用intent和系统提供的功能进行交互
3.调用摄像头和相册
File outputImage = new File(Environment.
getExternalStorageDirectory(), "tempImage.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
imageUri = Uri.fromFile(outputImage);
Intent intent = new Intent("android.media.action. IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO); // 启动相机程序
4.播放多媒体文件(音频和视频)
后台服务
服务的生命周期
1.context调用startService方法,服务启动。
2.如果服务未创建过,oncreate方法执行。
3.执行onStartCommand方法
4.服务处理完毕,调用stopService或者stopSelf方法。
5.ondestroy方法执行
注意,只有服务取消绑定后才能被销毁。
context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop
服务的基本使用
1)定义server
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
2)修改 AndroidManifest.xml文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.servicetest"
android:versionCode="1"
android:versionName="1.0" >
......
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
......
<service android:name=".MyService" >
</service>
</application>
</manifest>
3)启动服务
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 启动服务
4)停止服务
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服务
活动与服务通信
1)server类中新建binder类的子类
public class MyService extends Service {
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder {
public void startDownload() {
Log.d("MyService", "startDownload executed");
}
public int getProgress() {
Log.d("MyService", "getProgress executed");
return 0;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
......
}
2)定义一个connection类。提供一个ServiceConnection的实现,用以监控与服务Service间的连接情况。
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
};
3)绑定服务
bindService()无返回值,但系统在客户端与服务端连接之间,会调用在ServiceConnect对象中的onServiceConnected()方法
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
前台服务
在通知栏显示服务进程,避免因内存不足导致进程关闭。