赞
踩
第一层 Linux内核层
安卓是 Linux 内核的,这一层为Android设备的各种硬件提供了底层的驱动,如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等。
第二层 系统运行库层
这一层通过C/C++库来为安卓系统提供了主要的特性支持。如SQLite库提供了数据库的支持,OpenGL|ES库提供了3D绘图的支持,Webkit库提供了浏览器内核的支持等。
这一层还有Android运行时库提供了一些核心库,能让开发者使用Java来写Android,Android运行时库中还包含了Dalvik虚拟机(5.0系统之后改为 ART运行环境
,就是 Android Runtime
),它使得每一个Android应用都能运行在独立的进程当中,并且拥有一个自己的Dalvik虚拟机实例。相较于Java虚拟机,Dalvik是专门为移动设备定制的,针对手机内存、CPU性能有限等情况做了优化处理。
Dalvik
模式的特点: 运行内存大、占用空间小、加载慢、省电、兼容性好。Art相反。
第三层 应用框架层
提供了构建应用程序时用的API, Android自带的一些核心应用就是用这些API,开发者也可以通过使用这些API来构建自己的应用程序。
第四层 应用层
所有安装在手机上的应用程序都是属于这一层的。
整个应用的全局描述文件,作为一个前端的理解,manifest文件相当于 package.json的作用。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.project" android:versionCode="1" android:versionName="1.0"> // 权限和application是同级的 <uses-permission android:name="android.permission.CAMERA" /> // 这里的android是设置app的名字,就是在手机桌面上的名字 <application android:label="@string/app_name" android:icon="@drawable/icon"> // 这里的label设置的是活动的标题 <activity android:name=".MyActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
/app
项目源代码
/build
它主要包含了一些在编译时自动生成的文件
/gradle
包含了gradle wrapper 的配置文件,使用gradle wrapper的方式不需要提前将gradle下载好,而是会自动根据本地的缓存情况决定是否需要联网下载gradle
/build.gradle
项目全局的gradle构建脚本
gradle.properties
全局的gradle配置文件,这里配置的属性会影响到项目中所有gradle编译脚本
/gradlew, /gradlew.bat
这两个文件是用来在命令行界面中执行gradle命令的,其中 gradlew
是在Linux或Mac系统中使用的,gradlew.bat
是在Windows系统中使用的
/local.properties
用于指定本机中的Android SDK路径,通常内容都是自动生成的,并不需要修改
/settings.gradle
用于指定项目中所有引入的模块。由于一般项目中就只有一个app模块,因此该文件中也就只引入了app这一个模块
/app/build
这个目录和外层的build目录类似,主要也是包含了一些在编译时自动生成的文件
/app/libs
如果你的项目中使用到了第三方jar包,就需要把这些jar包都放在libs目录下,放在这个目录下的jar包都会被自动添加到构建路径里去
/app/AndroidManifest.xml
这是你整个Android项目的配置文件,你在程序中定义的所有四大组件都需要在这个文件里注册,另外还可以在这个文件中给应用程序添加权限声明
/app/build.gradle
这是app模块的gradle构建脚本
/app/res/drawable*
都是用来放图片
/app/res/mipmap*
都是用来放应用图标的
/app/res/values
用来放字符串、样式、颜色等配置的
/app/res/layout
文件夹是用来放布局文件
// 首先第一行应用了一个插件, // 一般有两种值可选:com.android.application 表示这是一个应用程序模块, // com.android.library表示这是一个库模块 // 应用程序模块和库模块的最大区别在于,一个是可以直接运行的,一个只能作为代码库依附于别的应用程序模块来运行 apply plugin: 'com.android.application' android { // 指定项目的编译版本 compileSdkVersion 29 // buildToolsVersion用于指定项目构建工具的版本 buildToolsVersion "29.0.3" defaultConfig { // 指定项目的包名 applicationId "com.example.myapplication1" // 指定项目最低兼容的Android系统版本 minSdkVersion 28 // targetSdkVersion指定的值表示你在该目标版本上已经做过了充分的测试,系统将会为你的应用程序启用一些最新的功能和特性 targetSdkVersion 29 // versionCode用于指定项目的版本号 versionCode 1 // versionName用于指定项目的版本名 versionName "1.0.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } // 指定生成安装文件的相关配置 buildTypes { // 指定生成正式版安装文件的配置 release { // 是否对项目的代码进行混淆 minifyEnabled true // proguardFiles用于指定混淆时使用的规则文件,这里指定了两个文件, // 第一个proguard-android.txt是在Android SDK目录下的,里面是所有项目通用的混淆规则, // 第二个proguard-rules.pro是在当前项目的根目录下的,里面可以编写当前项目特有的混淆规则 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } dependencies { // Android Studio项目一共有3种依赖方式:本地依赖、库依赖和远程依赖 // 添加一个库依赖 implementation project(':helper') // implementation fileTree是一个本地依赖声明, // 它表示将libs目录下所有.jar后缀的文件都添加到项目的构建路径当中 implementation fileTree(dir: 'libs', include: ['*.jar']) // 远程依赖声明,androidx.appcompat:appcompat:1.2.0就是一个标准的远程依赖库格式, // 其中androidx.appcompat是域名部分,用于和其他公司的库做区分; // appcompat是组名称,用于和同一个公司中不同的库做区分; // 1.2.0是版本号,用于和同一个库不同的版本做区分 // 加上这句声明后,Gradle在构建项目时会首先检查一下本地是否已经有这个库的缓存, // 如果没有的话则会去自动联网下载,然后再添加到项目的构建路径当中 implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'com.google.android.material:material:1.0.0' // testImplementation 是用于声明测试用例库 testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' }
Activicy
活动,标识一个具有用户界面的单一屏幕。例如,一个邮件应用程序可以包含一个活动用于显示新邮件列表,另一个活动用来编写邮件,再一个活动来阅读邮件。当应用程序拥有多个活动,其中一个会被标记为主活动,在app启动时显示。
Service
在主线程,运行在后台执行长时间操作的组件。举个例子,服务可以是用户在使用不同的程序时在后台播放音乐,或者在活动中通过网络获取数据但不阻塞用户交互。
Broadcast
广播接收器简单地响应从其他应用程序或者系统发来的广播消息。举个例子,应用程序可以发起广播来让其他应用程序知道一些数据已经被下载到设备,并且可以供他们使用。因此广播接收器会拦截这些通信并采取适当的行动。广播接收器是BroadcastReceiver类的一个子类,每个消息以Intent对象的形式来广播。
Content Providers
内容提供者组件通过请求从一个应用程序到另一个应用程序提供数据。这些请求由ContentResolver类的方法来处理。这些数据可以是存储在文件系统、数据库或者其他其他地方。内容提供者是ContentProvider类的子类,并实现一套标准的API,以便其他应用程序来执行事务
Android 应用程序架构包括组件(使用 Intent
通信)、资源(通常在用户界面上下文中使用)、
manifest(描述了应用程序组件等)、应用程序包(用于存储组件、资源和manifest内容),Android 使用 Intent 对象与 Activity、服务和广播接收器进行通信。
Intent 对象是 android.content.intent 类的实例,可以分为显式或隐式声明。
显式 Intent 明确指定了组件的名称,隐式 Intent 则不指定目标名称(组件名没有赋值)。
隐式 Intent 通常用于启动其他应用中的组件。
如果组件没有 Intent 过滤器,那就只能接受显式 Intent,有过滤器的组件则既能接收显式 Intent 也能接收隐式 Intent。Android 在过滤 Intent 时,会参考 Intent 对象的 Action
、Catejory
、Data
和 Type
,而不会参考 Extra 和 Flag。
Android 提供了发送电子邮件的 Intent。你的app发送此 Intent 即可以激活标准邮件应用程序,或者也可以注册一个 Activity 来响应该 Intent 对象,从而使用该 Activity 取代标准的邮件应用程序这种面向组件的架构允许一个应用程序重用其他应用程序的组件,只要其他应用程序允许重用自身的组件。组件重用减少内存占用率对于有限存储空间的设备尤其重要。
当应用程序的任何组成部分需要执行,Android会启动一个进程并实例化该组成部分的 Java 对象。这就是为什么 Android 的应用程序没有单一入口点 (例如没有 C 程序中的 main函数)的原因。因为应用程序会根据需要使用实例化的组件并运行。
R.( string | drawable | layout | id ).name
可以获得该字符串的引用。@+id/id_name
这种语法 是定义一个idapp/build.gradle
比如说 Android 6.0
系统中引入了运行时权限这个功能,如果你将targetSdkVersion指定成23或者更高,那么系统就会为你的程序启用运行时权限功能Android中的日志工具类是Log(android.util.Log
), 在logcat下边看日志,还可以根据标签过滤。不要使用System.out 打印日志!
Log.v()。用于打印那些最为琐碎的、意义最小的日志信息。对应级别verbose,是Android日志里面级别最低的一种。
Log.d()。用于打印一些调试信息,这些信息对你调试程序和分析问题应该是有帮助的。对应级别debug,比verbose高一级。
Log.i()。用于打印一些比较重要的数据,这些数据应该是你非常想看到的、可以帮你分析用户行为数据。对应级别info,比debug高一级。
Log.w()。用于打印一些警告信息,提示程序在这个地方可能会有潜在的风险,最好去修复一下这些出现警告的地方。对应级别warn,比info高一级。
Log.e()。用于打印程序中的错误信息,比如程序进入到了catch语句当中。当有错误信息打印出来的时候,一般都代表你的程序出现严重问题了,必须尽快修复。对应级别error,比warn高一级。
android:gravity
可以指定布局的对齐方式,是左对齐还是水平对齐,还是上下左右居中。
setVisibility
修改View的可见性,View可用性如下三种状态:View.VISIBLE
可见,View.INVISIBLE
不可见,但仍然占据可见时的大小和位置。View.GONE
不可见,且不占据空间。
android:ems=“10” 设置TextView或EditText为10个字符的宽度,超出部分不显示。android:ellipsize="end" android:lines="3"
多行超出显示省略号。
线性布局,就是按照vertical或者horizontal平铺的布局,新手必备。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingTop="2dp" tools:context=".Main4Activity"> // android:layout_height为0,切android:layout_weight为1, //表示高度不是height决定,而是vertical方向 flex 1 的效果 <LinearLayout android:layout_width="fill_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_weight="1" > <Button android:id="@+id/btn11" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="haha1" /> <Button android:id="@+id/btn12" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="haha2" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_weight="2" > <Button android:id="@+id/btn13" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="haha11" /> <Button android:id="@+id/btn14" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="haha22" /> </LinearLayout> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".RelativeLayoutDemoActivity"> <!-- relative_btn1 对其父元素中的左边和Top --> <Button android:id="@+id/relative_btn1" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:text="relative_btn1" /> <!-- relative_btn1 对其父元素中的右边和Top --> <Button android:id="@+id/relative_btn2" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:text="relative_btn2" /> <!-- relative_btn3 控件在父元素中的中间位置 --> <Button android:id="@+id/relative_btn3" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_centerInParent="true" android:text="relative_btn3" /> <!-- relative_btn4 相当于 relative_btn3 的上边 ,并且在 relative_btn3 的左边--> <Button android:id="@+id/relative_btn4" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_above="@id/relative_btn3" android:layout_toLeftOf="@id/relative_btn3" android:text="relative_btn4" /> <!-- relative_btn5 相当于 relative_btn3 的上边 ,并且在 relative_btn3 的右边--> <Button android:id="@+id/relative_btn5" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_above="@id/relative_btn3" android:layout_toRightOf="@id/relative_btn3" android:text="relative_btn5" /> <!-- relative_btn5 相当于 relative_btn3 的下边 ,并且在 relative_btn3 的右边--> <Button android:id="@+id/relative_btn6" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_below="@id/relative_btn3" android:layout_toRightOf="@id/relative_btn3" android:text="relative_btn6" /> <!-- relative_btn7 相当于 relative_btn3 的下边 ,并且和relative_btn4 的左边对齐 --> <Button android:id="@+id/relative_btn7" android:layout_width="200dp" android:layout_height="40dp" android:layout_below="@id/relative_btn3" android:layout_alignLeft="@id/relative_btn4" android:text="relative_btn7" /> <!-- relative_btn8 和 relative_btn3 的top 对齐--> <Button android:id="@+id/relative_btn8" android:layout_width="wrap_content" android:layout_height="50dp" android:background="@color/blue" android:layout_alignTop="@id/relative_btn3" android:text="b8" /> </RelativeLayout>
又称作帧布局,它相比于前面两种布局就简单太多了,因此它的应用场景也少了很多。这种布局没有方便的定位方式,所有的控件都会默认摆放在布局的左上角。
约束布局号称一层布局实现所有效果,约束布局 ConstraintLayout
是一个 ViewGroup
,可以在Api9以上的Android系统使用它,它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整小部件。嵌套布局是布局内的布局,会增加绘制界面所需的时间。
添加依赖 app/build.gradle
中添加 implementation 'com.android.support.constraint:constraint-layout:1.1.3'
,由于约束布局并不是内置在系统SDK当中的,所以需要把完整的包路径写出来。
元素宽度100%
<Button
android:layout_width="fill_parent"
android:layout_marginStart="0dp"
>
元素宽度怎么设置百分比
<Button
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.6"
>
元素怎么左右居中,怎么垂直也居中
设置左右两个约束,在正中间那么设置4个约束。
margin-left 怎么做
如果是 marginLeft
是确定的就是 android:layout_marginStart="156dp"
, app:layout_constraintHorizontal_bias
可以实现左右margin是百分比的效果, 就是marginLeft/marginLeft + marginRight,如果是0.5代表水平居中, app:layout_constraintVertical_bias
原理相同。
一个按钮固定宽度,一个填满剩余
当多个控件除了头和尾之外彼此之间互相约束,他们之间就形成了一条链,由头和尾决定链的约束位置。
<Button android:id="@+id/button6" android:layout_width="140dp" android:layout_height="wrap_content" android:layout_marginTop="64dp" android:text="button6" app:layout_constraintEnd_toStartOf="@+id/button7" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button7" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="64dp" android:layout_weight='1' android:text="button77" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.8" app:layout_constraintStart_toEndOf="@+id/button6" app:layout_constraintTop_toTopOf="parent" />
LinearLayout本身已经支持按比例指定控件的大小了,因此百分比布局只为Frame-Layout和RelativeLayout进行了功能扩展。
LinearLayout支持百分比不是直接写 50%
这样,而是 android:layout_weight="1"
添加依赖 app/build.gradle
中添加 implementation 'com.android.support:percent:24.2.1'
此布局是一个调度者,中心指挥者,在它布局下的所有的直接子View可以通过Behavior来和CoordinatorLayout中心指挥者通信。中心指挥者就可以根据Behavior来为子View指定依赖的同级View、嵌套滑动、事件拦截。
它是一种可以包含用户界面的组件
,主要用于和用户进行交互。Activity是一个Android应用程序组件,它提供一个屏幕,用户可以通过该屏幕进行交互以执行某些操作,例如拍照。每个活动都有一个窗口,用于绘制其用户界面。窗口通常填满屏幕也可能比屏幕小,并漂浮在其他窗口的顶部。
Android中的活动是可以层叠的。我们每启动一个新的活动,就会覆盖在原活动之上,然后点击Back键会销毁最上面的活动,下面的一个活动就会重新显示出来。
Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。在默认情况下,每当我们启动了一个新的活动,它会在返回栈中入栈,并处于栈顶的位置。而每当我们按下Back键或调用finish()方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈的活动就会重新处于栈顶的位置。系统总是会显示处于栈顶的活动给用户。
使用Activity时,在manifest中声明此Activity,并设置为主活动。如果没设置,无法在启动器中看到这应用程序,这种程序通常作为第三方服务供其它应用在内部进行调用。
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
java代码中的活动
// 基本活动定义 import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.os.Bundle; public class MainActivity2 extends AppCompatActivity { // 在Activity创建时被系统调用 @Override protected void onCreate(Bundle savedInstanceState) { // Bundle类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的 // savedInstanceState 也就是保存Activity的状态 super.onCreate(savedInstanceState); // 加载布局文件 setContentView(R.layout.activity_main2); } @Override protected void onStart() { Log.v("start", "act start"); super.onStart(); } }
点击事件
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
Button button1 = findViewById(R.id.demo1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast toast=Toast.makeText(getApplicationContext(), "默认的Toast", Toast.LENGTH_SHORT);
toast.show();
}
});
// 跳转活动
Intent intent = new Intent(MainActivity.this,Main2Activity.class);
startActivity(intent);
Activity 的前台生命周期就是调用 onResume()到调用 onPause()之间的时间段。在这 段时间内,Activity 处于屏幕上的最前台,正处于跟用户交互的状态。当设备休眠或有新 Activity 启动时 调用 onPause()。
当用户按下返回键时,当前的 Activity 就被弹出栈(Activity 被销毁),前 一个 Activity 重新进入运行状态,恢复操作(之前的用户界面状态也会还原)。
Activity 的用户界面是基于视图(用户界面组件Widget)、ViewGroup(由相关视图构成的集合)和事件监听器(用来监听视图或 ViewGroup 事件的对象)的,android.widget包中包 括各种 View 的子类,如 Button等,android.widget包中包括了不同的ViewGroup的子类,如 LinearLayout。
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout layout = new LinearLayout(this); final EditText et = new EditText(this); et.setEms(10); layout.addView(et); Button btnOK = new Button(this); btnOK.setText("OK"); layout.addView(btnOK); View.OnClickListener ocl; ocl = new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(class.this, et.getText(), Toast.LENGTH_SHORT).show(); } }; btnOK.setOnClickListener(ocl); setContentView(layout); }
运行状态当一个活动位于返回栈的栈顶时,这时活动就处于运行状态。系统最不愿意回收的就是处于运行状态的活动,因为这会带来非常差的用户体验
暂停状态当一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态。你可能会觉得既然活动已经不在栈顶了,还怎么会可见呢?这是因为并不是每一个活动都会占满整个屏幕的,比如对话框形式的活动只会占用屏幕中间的部分区域,你很快就会在后面看到这种活动。处于暂停状态的活动仍然是完全存活着的,系统也不愿意去回收这种活动(因为它还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会去考虑回收这种活动。
停止状态当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。系统仍然会为这种活动保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的活动有可能会被系统回收。
销毁状态当一个活动从返回栈中移除后就变成了销毁状态。系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足。
应用中有一个活动A,用户在活动A的基础上启动了活动B,活动A就进入了停止状态,这个时候由于系统内存不足,将活动A回收掉了,然后用户按下Back键返回活动A,会出现什么情况呢?
其实还是会正常显示活动A的,只不过这时并不会执行onRestart()方法,而是会执行活动A的onCreate()方法,因为活动A在这种情况下会被重新创建一次。
关于 savedInstanceState,来保存状态
// savedInstanceState 是保存的状态,这里可以直接拿过来
@Override
protected void onCreate(Bundle savedInstanceState) {
// savedInstanceState 也就是保存Activity的状态
super.onCreate(savedInstanceState);
// 加载布局文件
setContentView(R.layout.activity_main2);
}
// 在这个活动结束之前,会调用次方法,来保存状态
@Override
public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
}
启动模式分别是standard、singleTop、singleTask和singleInstance,可以在AndroidManifest.xml中通过给标签指定android:launchMode属性来选择启动模式
standard
模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。
singleTop
在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例
singleTask
每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例
SingleInstance
这种模式是最特殊的模式,这种模式是为了让不同的app之间可以共享同一个活动,如果你的app想让别的app调用你的某一个界面,就可以用这种模式,这种模式会为你想共享的界面单独创造出一个单独使用的返回栈,不会与别的返回栈共同使用
通过注册scheme可在App页面内跳转,从H5页面跳转到App,从一个App跳转到另一个App
使用Fragment能实现一个界面的多次使用,能加快效率。Fragment可以被认为是Activity界面的一个布局,其依赖于Activity,但是拥有自己的活动事件与生命周期。可以通过替换Activity中的Fragment实现界面的优化处理。
Fragment相比Activity更节省内存,UI切换更舒适。
Activity里面可以没有 Fragment,但是Fragment不能脱离Activity而存在。
Activity 间接继承 Context,Fragment 继承Object。
设备屏幕一层只一个Activity, 但是Activity里面可以有多个Fragment。
Activity需要在AndroidManifest.xml中注册,可以作为接收intent的载体。使用Fragment不需要在AndroidManifest.xml文件中注册,Fragment也不能作为intent跳转的对象。
生命周期不同: Fragment相对Activity,增加了5个生命周期方法: onAttach():当fragment和activity建立关联的时候调用 onCreateView():为fragment创建视图时调用 onActivityCreated():与fragment相关联的activity已经创建完毕 onDestroyView():当与fragment关联的视图被移除的时候调用 onDetach():当fragment与activity解除关联时调用。
为了让Android兼容平板,3.0系统(API 11)中加入了Fragment功能。以前的老系统中也想使用这个功能该怎么办?于是Android团队推出了一个鼎鼎大名的 Android Support Library,用于提供向下兼容的功能。比如我们每个人都熟知的support-v4库,appcompat-v7库都是属于Android Support Library的。AndroidX本质上其实就是对Android Support Library进行的一次升级。
2019年Google I/O大会上公布的一款Android视图绑定工具:ViewBinding。使用方式类似DataBinding,但相比DataBinding,ViewBinding是一个更轻量级、更纯粹的findViewById的替代方案。它具有如下优点:
类型安全: ViewBinding会基于布局中的View生成类型正确的属性。比如,在布局中放入了一个 TextView ,视图绑定就会暴露出一个 TextView 类型的属性供开发中使用。
空安全:ViewBinding会检测某个视图是否只在某些配置下存在,并依据结果生成带有 @Nullable 注解的属性,所以即使在多种配置下定义的布局文件,视图绑定依然能够保证空安全。
ViewBinding生成的绑定类是一个Java类,并且添加了Kotlin注解,可以很好地支持 Java 和 Kotlin 两种编程语言。
项目开启,在build.gradle 下
android {
...
buildFeatures {
viewBinding = true
}
}
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 之前是 setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.textView1.text = "textView1"
}
}
首选,添加依赖。
implementation 'androidx.navigation:navigation-fragment:2.4.1'
implementation 'androidx.navigation:navigation-ui:2.4.1'
构成的三个要素。
和Activity一样,都是Android框架的一个系统组件,activity是UI界面的抽象,而application是应用程序的抽象。
应用程序每次启动时,系统会为其创建一个application对象且只有一个(单例类),用来存储系统的一些信息,相当于一个容器。
启动application时,系统会创建一个PID(进程ID),所有的activity都在这个进程上运行,在application创建时会初始化一个全局变量,同一个应用的activity,都可以获取到这个变量,也就是说,某一个activity中改变了这个变量,其他activity里也会改变。
Service(服务)是运行在后台的组件,其运行不限时间,且不提供用户界面,Service是运行在主线程中的,它必须创建另一个线程以执行耗时操作,例如服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进。服务有两种状态。使用service也需要在manifest中声明。
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
</service>
Service 分为本地 Service 或远程 Service 两类:本地 Service 与应用程序其他部分运行在相同的进程中,这种 Service 很容易执行 后台任务。远程 Service 运行在独立的进程中,这种 Service 可以用来执行进程间的相互通信。
比如用户可利用 Activity 来选择播放歌曲,并启动一个服务来响应用户选择。服务会在另一个线程中进行音乐播放,防止应用程序出现 ANR(Application Not Responding)
。
在调用 stopService(Intent)
、stopSelf()
或 stopSelfResult(int)
方法之后,Android 会调用 onDestroy()
,让 Service 执行清理任务
public class MyService extends Service { // onCreate()方法不会被反复调用 @Override public void onCreate() { super.onCreate(); } // intent 是传递给 startService(Intent)的 Intent 对象 // flags 用于提供关于启动请求的其他信息,但通常设置为 0。 // startId 是用于描述该启动请求的唯一整数编号,可以将这个值传递给Service的 // boolean stopSelfResult(int startId)来将自己停止。 @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } // onDestroy()方法是一定会被调用的,来释放资源 @Override public void onDestroy() { super.onDestroy(); } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } }
启动状态
当应用组件通过调用 startService
启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响,除非手动调用才能停止服务, 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。
// 启动service的代码
Intent intent = new Intent(MainActivity.this, MyService.class);
MainActivity.this.startService(intent);
绑定状态
当应用组件通过调用 bindService()
绑定到服务时,服务处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
远程service
远程Service是通过Context类的 boolean bindService(Intentservice, ServiceConnection conn, int flags)
方法来启动的,它会连接到一个正在运行的服务(如果需要,则创建该服务), 如果成功连接返回true。
调用 bindService(Intent, ServiceConnection, int)
会导致调用 onCreate()方法随后会调用 onBind(Intent)函数,该函数会返回一个用于跟 Service 交互的通信通道(实现 android.os.IBinder 接口的类的实例)。
// 服务 public class MyBinder extends Binder { public BindService getService() { return BindService.this; } } private MyBinder myBinder = new MyBinder(); public void MyMethod(){ Log.i("BindService", "BindService-->MyMethod()"); } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return myBinder; } } // 活动 public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub BindService.MyBinder binder = (BindService.MyBinder)service; BindService bindService = binder.getService(); bindService.MyMethod(); } @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); binding.fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, MyService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); } }); } private void unBind(){ unbindService(conn); } }
Intent
是Android程序中各组件之间进行交互的一种重要方式,
可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。
Intent一般可被用于启动活动、启动服务以及发送广播等场景
// 都是在活动的onCreate方法,传递数据
intent.putExtra("name", "intent-data1");
// 接收数据
Intent intent = getIntent();
String name = intent.getStringExtra("name");
返回上级 数据带回去
// 活动1 // 接收返回结果 startActivityForResult(intent, 1); // 活动1 重写方法 @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if(requestCode == 1){ if(resultCode == RESULT_OK){ String returnData = data.getStringExtra("data-return"); Log.i("main", returnData); } } super.onActivityResult(requestCode, resultCode, data); } // 活动2 // 点击返回 和按一下Back键就可以销毁当前的活动一样 button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.putExtra("data-return", "data-return"); setResult(RESULT_OK, intent); finish(); } }); // 重写back键 public void onBackPressed() { Intent intent = new Intent(); intent.putExtra("data-return", "data-return"); setResult(RESULT_OK, intent); finish(); super.onBackPressed(); }
http 是无状态的请求响应的协议,http2 使用二进制格式,而不是文本格式 多路复用 多重请求响应
HttpUrlConnect是java标准类,用于安卓网络请求。
所有控件都是直接或间接继承自View的,所有布局都是直接或间接继承自ViewGroup的。
自定义控件,实现一个公用的头部。
// 布局文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:background="@color/blue" android:layout_width="match_parent" android:layout_height="36dp"> <Button android:id="@+id/title_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="5dp" android:text="Back" android:textColor="#fff" android:textSize="14sp" android:background="@color/blue"/> <TextView android:id="@+id/title_text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="1" android:gravity="center" android:text="Title Text" android:textColor="#fff" android:textSize="16sp" /> <Button android:id="@+id/title_edit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="5dp" android:text="edit" android:textSize="14sp" android:textColor="#fff" android:background="@color/blue"/> </LinearLayout> // 布局主文件 <?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ConstraintLayoutDemo2Activity"> <com.hua.huade001android.TitleLayout android:layout_width="match_parent" android:layout_height="36dp"> </com.hua.huade001android.TitleLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout> // java代码 public class TitleLayout extends LinearLayout { public TitleLayout(Context context, @Nullable AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.title, this); Button back = findViewById(R.id.title_back); back.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { ((Activity)getContext()).finish(); } }); } }
Listview
缺点,性能不好,只能纵向滚动,所以以后要使用 RecyclerView
。
RecyclerView是Android 5.0推出的
广播是一种可以跨进程的通信方式。
标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
有序广播是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。
Android内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。如手机开机完成后会发出一条广播、电池的电量发生变化会发出一条广播,时间或时区发生改变也会发出一条广播。
注册广播的方式一般有两种,在代码中注册被称为动态注册,缺点是必须要在程序启动之后才能接收到广播,在AndroidManifest.xml中注册被称为静态注册
// 活动中发送广播
Intent intent = new Intent(SimpleActivity.this, SimpleBroadcastReceiver.class);
intent.putExtra("message", "Hello, broadcast receiver!"); SimpleActivity.this.sendBroadcast(intent);
// 接受广播
public class SimpleBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
System.out.println("onReceive(Context, Intent) called");
}
}
// 1 实现网络接收器 // 网络接收器,每当网络变化,系统发送一个广播,都会执行onReceive方法 public class NetworkReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show(); boolean success = false; //获得网络连接服务 ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE); NetworkInfo info = connectivityManager.getActiveNetworkInfo(); //获取wifi连接状态 NetworkInfo.State state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState(); //判断是否正在使用wifi网络 if (state == NetworkInfo.State.CONNECTED) { Toast.makeText(context, "using wifi", Toast.LENGTH_SHORT).show(); success = true; } //获取GPRS状态 state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState(); //判断是否在使用GPRS网络 if (state == NetworkInfo.State.CONNECTED) { success = true; } //如果没有连接成功 if(!success){ Toast.makeText(context,"当前网络无连接",Toast.LENGTH_SHORT).show(); } } } // 2 在活动中使用 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String type = "android.net.conn.CONNECTIVITY_CHANGE"; intentFilter = new IntentFilter(); intentFilter.addAction(type); networkReceiver = new NetworkReceiver(); registerReceiver(networkReceiver, intentFilter); } @Override protected void onDestroy() { super.onDestroy(); // 销毁活动,要结束广播接收 unregisterReceiver(networkReceiver); }
在 android studio 中 新建一个广播,勾选 exported 和 enabled ,Exported属性表示是否允许这个广播接收器接收本程序以外的广播,Enabled属性表示是否启用这个广播接收器,并会自动在manifest文件中添加声明。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name=".broadcast.BootReceiver"
android:enabled="true"
android:exported="true"></receiver>
</application>
// 1 创建接收者 public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "MyReceiver get", Toast.LENGTH_SHORT).show(); } } // 2 配置到 android manifest <receiver android:name=".broadcast.MyReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.tecent.chat.MY_BROADCAST" /> </intent-filter> </receiver> // 3. 活动中,加一个按钮点击事件,触发广播 // 点击按钮,发送广播 Button btn = findViewById(R.id.btn_b); btn.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { Intent intent = new Intent("com.tecent.chat.MY_BROADCAST"); sendBroadcast(intent); } });
sendOrderedBroadcast()方法接收两个参数,第一个参数仍然是Intent,第二个参数是一个与权限相关的字符串,这里传入null就行了
为了处理顺序,可以加优先级字段
<receiver
android:name=".broadcast.MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.tecent.chat.MY_BROADCAST" />
</intent-filter>
</receiver>
导包 implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
1.发送本地广播比发送系统全局广播将会更加高效
2.本地广播无法静态广播
3.本地广播不会数据泄露安全问题
Context类中提供了一个openFileOutput()方法,可以用于将数据存储到指定的文件中。方法接收两个参数,
第一个是文件名,在文件创建的时候使用的就是这个名称,注意这里指定的文件名不可以包含路径,因为所有的文件都是默认存储到/data/data//files/目录下的。
第二个参数是文件的操作模式,主要有两种模式可选,MODE_PRIVATE和MODE_APPEND。其中MODE_PRIVATE是默认的操作模式,表示当指定同样文件名的时候,所写入的内容将会覆盖原文件中的内容,而MODE_APPEND则表示如果该文件已存在,就往文件里面追加内容,不存在就创建新文件
// 保存数据到本地文件 public void save(){ FileOutputStream out = null; BufferedWriter writer = null; try { out = openFileOutput("data", Context.MODE_PRIVATE); writer = new BufferedWriter(new OutputStreamWriter(out)); writer.write("huahuadavids"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(writer != null){ try { writer.close(); Log.v("main", "write end"); } catch (IOException e) { e.printStackTrace(); } } } }
SharedPreferences是使用键值对的方式来存储数据的
SharedPreferences文件都是存放在/data/data//shared_prefs/目录下的
// 将数据存储到SharedPreferences public void save1(){ // getShared-Preferences()方法指定SharedPreferences的文件名为data, // 生产文件的路径为 /shared_prefs/data.xml // 并得到了SharedPreferences.Editor对象 SharedPreferences.Editor editor = getSharedPreferences("data", 0).edit(); editor.putString("name", "huahuadavids"); editor.putInt("age", 34); editor.putBoolean("newbee", true); editor.apply(); Toast.makeText(LoginActivity.this, "success!!", Toast.LENGTH_SHORT).show(); } // 从SharedPreferences中取数据 public void get1(){ SharedPreferences share = getSharedPreferences("data", 0); String name = share.getString("name", ""); Log.v("main", name); }
SQLite 一个非常流行的嵌入式数据库,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。Android 运行时环境包含了完整的 SQLite。JDBC 会消耗太多的系统资源,所以 JDBC 对于手机这种内存受限设备来说不合适。数据库文件会存放在/data/data/package name/databases/
目录下。
SQLiteOpenHelper
是一个抽象类,使用它需要创建一个自己的帮助类去继承它。有两个抽象方法onCreate()和onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。
getReadableDatabase()和getWritableDatabase()
。这两个实例方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而getWritableDatabase()方法则将出现异常。
可以直接使用 execSQL
和 rawQuery
方法执行sql
public class DatabaseHelper extends SQLiteOpenHelper { //创建数据库sql语句 并 执行 public static final String sql = "create table user(id integer primary key, name text)"; private Context mcontext; //带全部参数的构造函数,此构造函数必不可少 public DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); mcontext = context; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(sql); Toast.makeText(mcontext, "create success!!", Toast.LENGTH_SHORT).show(); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } public class DemoActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { dbHelper = new DatabaseHelper(this, "db-hua", null, 1); // 多次点,不会重复提示,数据库创建成功,因为oncreate只会执行一次 sql.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 返回一个SQLiteDatabase对象,借助这个对象就可以对数据进行CRUD操作了。 SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues val = new ContentValues(); val.put("id", 1); val.put("name", "nina"); db.insert("user", null, val); val.clear(); val.put("id", 2); val.put("name", "tina"); db.insert("user", null, val); Toast.makeText(LoginActivity.this, "插入数据成功", Toast.LENGTH_SHORT).show(); // 更新数据 ContentValues val = new ContentValues(); val.put("name", "sasa"); db.update("user", val, "id = ?", new String[]{"1"}); // 删除数据 db.delete("user", "id = ?", new String[]{"1"}); // 查询数据 Cursor cursor = db.rawQuery("select * from user", null); if(cursor.moveToFirst()){ do { String name = cursor.getString(cursor.getColumnIndex("name")); Log.v("main", name); }while (cursor.moveToNext()); } cursor.close(); } }); } }
是一款开源的Android数据库框架,它采用了对象关系映射(ORM)的模式
dependencies {
implementation 'org.litepal.guolindev:core:3.2.1'
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ptrprograms.androidpermissionsdemo" >
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
public class MainActivity extends Activity { private final int REQUEST_CODE_SOME_FEATURES_PERMISSIONS = 0; private final int REQUEST_CODE_ALL = 42; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); int hasLocationPermission = checkSelfPermission( Manifest.permission.ACCESS_FINE_LOCATION ); int hasSMSPermission = checkSelfPermission( Manifest.permission.SEND_SMS ); List<String> permissions = new ArrayList<String>(); if( hasLocationPermission != PackageManager.PERMISSION_GRANTED ) { permissions.add( Manifest.permission.ACCESS_FINE_LOCATION ); } if( hasSMSPermission != PackageManager.PERMISSION_GRANTED ) { permissions.add( Manifest.permission.SEND_SMS ); } if( !permissions.isEmpty() ) { requestPermissions( permissions.toArray( new String[permissions.size()] ), REQUEST_CODE_SOME_FEATURES_PERMISSIONS ); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch ( requestCode ) { case REQUEST_CODE_SOME_FEATURES_PERMISSIONS: { for( int i = 0; i < permissions.length; i++ ) { if( grantResults[i] == PackageManager.PERMISSION_GRANTED ) { Log.d( "Permissions", "Permission Granted: " + permissions[i] ); } else if( grantResults[i] == PackageManager.PERMISSION_DENIED ) { Log.d( "Permissions", "Permission Denied: " + permissions[i] ); } } } break; default: { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } } }
运行时权限
public class contentActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_content); Button btn1 = findViewById(R.id.rper); bindClick1(btn1); } public void bindClick1(Button btn) { btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (ContextCompat.checkSelfPermission(contentActivity.this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) { call(); }else { ActivityCompat.requestPermissions(contentActivity.this, new String[]{ Manifest.permission.CALL_PHONE }, 1); } } }); } private void call() { Toast.makeText(contentActivity.this, "xiaohua", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 1: if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { call(); }else { Toast.makeText(contentActivity.this, "您拒绝了权限哦", Toast.LENGTH_SHORT).show(); } } } }
内容提供器用于不同app之间实现数据共享,允许一个程序访问另一个的数据,还能保证被访数据的安全性。数据可以存储在 Android 的文件系统、SQLite 数据库中或其他方式进行存储。
使用内容提供器是Android实现跨程序共享数据的标准方式。只需要获取到该应用程序的内容URI,然后借助ContentResolver进行CRUD操作就可以了。
一个标准的URI,比如 content://com.demo.app.provider/table1
content://com.demo.app.provider/*
匹配任意表
content://com.demo.app.provider/table1/#
匹配任意表任意一行数据
Bundle类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的
Bundle data = new Bundle();
data.putString("Data", "data from TestBundle");
// bundle 放入 intent
Intent intent = new Intent();
intent.setClass(TestBundle.this, Target.class);
intent.putExtras(mBundle);
主题(Theme)就是一种应用到整个应用程序或某个 Activity 的外观风格,在没有任何自定义时,Android 应用程序的 Activity 会加载默认的系统主题,application和activity的android:theme="THEME_NAME"
属性,都可以指定主题。
自定义主题
在 res/values/styles.xml 文件中,声明两个主题
<resources>
<style name="MyTheme.One" parent="@android:style/Theme">
<item name="android:windowNoTitle">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="MyTheme.Two" parent="@android:style/Theme">
<item name="android:windowBackground">@drawable/window_bg</item>
<item name="android:windowFullscreen">true</item>
</style>
</resources>
SDK
SDK (Software Development Kit),Android SDK 就是 Android 专属的软件开发工具包。
AVD
android virtual device manager 安卓虚拟设备管理器
NDK
NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。NDK的发布,使“Java+C”的开发方式成为官方支持的。使用NDK,我们可以将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。使用NDK,我们可以将需要保密的应用逻辑使用C开发。毕竟,Java包都是可以反编译的。
ADB
Android Debug Bridge,是 Android SDK 里的一个是一个多功能命令行工具,就是一个调试桥,用这个工具可直接操作管理Android模拟器、虚拟机或者真实的Android设备。
它是一个客户端 - 服务器程序,包括三个组件:
主要作用有:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。