安卓期末考点整理

前言

临近考试,根据老师发的考试说明和例题整理出如下的复习资料

安卓的平台架构

安卓期末考点整理_第1张图片
安卓的基本架构

由下至上分别是:

  1. linux内核
  2. Android运行时
  3. 应用程序框架
  4. 应用程序

下面简述每层的作用:

linux内核

Android 平台的基础是 Linux 内核。例如,Android Runtime (ART) 依靠 Linux 内核来执行底层功能,例如线程和低层内存管理。
使用 Linux 内核可让 Android 利用主要安全功能,并且允许设备制造商为著名的内核开发硬件驱动程序。

Android运行时

Android 包括了一个核心库,该核心库提供了JAVA编程语言核心库的大多数功能。

程序库

Android包含一些C/C++库,这些库能被Android系统中不同的组件使用。它们通过Android应用程序框架为开发者提供服务。

应用程序框架

Android系统提供给应用开发者的本身就是一个框架,所有的应用开发都必须遵守这个框架的原则。

应用程序

所有的应用程序都是使用JAVA语言编写的,每一个应用程序由一个或者多个活动组成,活动必须以Activity类为超类,活动类似于操作系统上的进程,但是活动比操作系统的进程要更为灵活,与进程类似的是,活动在多种状态之间进行切换。

安卓的四大组件

  1. 活动----Activity

他是一种可以包含用户界面的组件,主要用于和用户进行交互

  1. 服务----Service

Service是在一段不定的时间运行在后台,不和用户交互应用组件。

  1. 广播----Broadcast Receiver
  2. 内容提供者----Content Provider

用于在不同的应用程序之间实现数据共享的功能。提供了一套完整的机制,允许一个程序访问俩一个程序中的数据,同时还能保证被访问数据的安全性

安卓清单文件的作用

  • 它为应用指定Java包。此包名称唯一标识应用
  • 它描述了应用的不同组件。它指定了实现这些组件并公布它们的功能。这些声明帮助Android系统识别和组件及它们可以启动的条件。
  • 它指定应用访问API的受保护部分和其他应用交换所需的权限。
  • 它指定应用可在其上运行的API的最低级别
  • 它指定链接应用所必须依据的库

常用的布局和控件以及其使用方法

四种最基本的布局

总共有四种最基本的布局,分别是:

线性布局(LinearLayout)
相对布局(RelativeLayout)
帧布局(FrameLayout)
百分比布局

因为考试说明里面只有两种,所以接下来只介绍两种

LinearLayout(线性布局)

  • 指定各个节点的排列方向
android:orientation="horizontal"
  • 设置右对齐
android:layout_gravity="right"
  • 当竖直布局时,只能左右对齐和水平居中,顶部底部对齐竖直居中无效
  • 当水平布局时,只能顶部底部对齐和竖直居中
  • 使用match_parent时注意不要把其他组件顶出去
  • 线性布局非常重要的一个属性:权重
android:layout_weight="1"

权重设置的是按比例分配剩余的空间

RelativeLayout
  • 组件默认左对齐、顶部对齐
  • 设置组件在指定组件的右边
android:layout_toRightOf="@id/tv1"
  • 设置在指定组件的下边
android:layout_below="@id/tv1"
  • 设置右对齐父元素
android:layout_alignParentRight="true"
  • 设置与指定组件右对齐
android:layout_alignRight="@id/tv1"

常用的控件

TextView、EditText、Button、ImageButton、ToggleButton、RadioButton、RadioGroup、Checkbox、Spinner、ListView、ImageView、WebView、ScrollView

重要的属性有:

android:id:指明控件id
android:layout_width::指明控件的宽度
android:layout_height:指明控件的高度

相关控件及其使用方法可以参考
Android笔记---常用控件以及用法

创建一个活动(Activity)的步骤

  1. 创建活动,编写自己的Acivity类,继承Activity类
  2. 将UI与活动关联。调用setContentView方法
  3. 在清单文件中注册活动

活动(Activity)的生命周期

活动的状态

  1. 运行状态

当一个活动处于返回栈的栈顶,也就是在屏幕的前台显示时,称为运行状态

  1. 暂停状态

如果一个Activity失去焦点(不在栈顶),但是依然可见(一个新的非全屏的Activity,例如一个对话框形式的活动,或者一个透明的Activity 被放置在栈顶),叫做暂停状态(Paused)

  1. 停止状态

如果一个Activity被另外的Activity完全覆盖掉(不在栈顶且不可见),叫做停止状态(Stopped)

  1. 销毁状态(了解)
    当一个活动从返回栈移除之后就变成的销毁状态

活动的7个生命周期的方法

安卓期末考点整理_第2张图片
7个生命周期的方法

活动的生命周期的图

安卓期末考点整理_第3张图片
活动的生命周期

Intent的使用

  1. 显式Intent
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);

上述代码的作用是打开活动SecondActivity

  1. 隐式Intent

相比隐式Intent,隐式Intent并不明确指出想要启动哪一个活动,而是指定了一系列抽象的action和category等信息,然后交由系统去分析这个Intent,并找到合适的活动去启动

使用隐式Intent
首先打开AndroidManifest.xml,添加代码:


        
            
            
        

指定好当前活动可以相应的action和category
回到MainActivity.java中

Intent intent=new Intent("com.lyy.intent.ACTION_START");
startActivity(intent);

将Intent传入我们自定义的action字符串即可

  1. Intent的系统action


    安卓期末考点整理_第4张图片
    Android系统广播action
  2. 利用Intent传值的两种方式

利用Intent直接传值
MainActivity.java —— 负责传递数据

Intent intent1=new Intent(MainActivity.this,Main2Activity.class);
intent1.putExtra("extra","hello");
startActivity(intent1);

Main2Activity —— 负责接收数据

Intent intent = getIntent();
String data = intent.getStringExtra("extra");
Log.d(TAG, "onCreate: " + data);

利用Bundle和Intent传值
MainActivity.java —— 负责传递数据

Intent intent2 = new Intent(MainActivity.this, Main2Activity.class);
Bundle bundle = new Bundle();
bundle.putString("name", "lyy");
bundle.putInt("age", 18);
bundle.putString("address", "China");
intent2.putExtras(bundle);
startActivity(intent2);

Main2Activity —— 负责接收数据

Intent intent = getIntent();
Bundle bundle = intent.getExtras();
String nameString = bundle.getString("name");
int age = bundle.getInt("age");
String addressString = bundle.getString("address");

原生方法操作SQLite数据库

创建一个类用于继承SQLiteOpenHelper类,并重写两个方法onCreate()和onUpgrade()方法用于创建和升级数据库,代码示例如下:

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)";

    public static final String CREATE_CATEGORY = "create table Category(" +
            "id integer primary key autoincrement," +
            "category_name text," +
            "category_code integer)";

    private Context mContext;

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
        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");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }
}

对数据库的数据进行增删改查(CRUD)操作

添加数据

先实例化之前创建的DatabaseHelper对象,并调用其getWritableDatabase()方法,设置该数据库可写

SQLiteDatabase db = databaseHelper.getWritableDatabase();

随后创建ContentValues对象,用来添加数据

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()方法

db.insert("Book", null, values);//插入第一条数据

更新数据

创建ContentValues对象,并组装要更新的数据

ContentValues values1 = new ContentValues();
values1.put("price", 10.99);

调用update()方法

db.update("Book", values1, "name = ?", new String[]{"The Da Vinci Code"});

第一个参数指定表名,第二个指定要更新的数据,第三个指定要更新的行,如果没有,则默认更新所有行。

删除数据

直接调用delete方法即可

db.delete("Book", "pages > ?", new String[]{"500"});

查询数据(最复杂)

通过调用db的query()方法,获得一个cursor对象

//查询Book表中的所有数据
Cursor cursor = db.query("Book", null, null, null, null, null, null);

在这里需要传入7个参数,作用分别如下:


安卓期末考点整理_第5张图片
query的7个参数及其作用

然后在对cursor对象进行遍历,获得查询到的值

while (cursor.moveToFirst()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                }

最后,一定记得要回收cursor对象

cursor.close();

文件存储

写文件

public void save() {
        String data = "Data to save";
        try {
            FileOutputStream fos = openFileOutput("data", Context.MODE_PRIVATE);
            fos.write(data.getBytes());
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

读文件

public void load() {
        String fileName = "abc.txt";
        try {
            FileInputStream fis = openFileInput(fileName);
            byte[] reader = new byte[fis.available()];
            if (fis.read(reader) != -1) {
                String data = new String(reader);
                System.out.println(data);
            }
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

共享首选项(SharedPreferences)

利用键值对的方式来存储数据,文件都是存放在/data/data//shared_prefs/目录下的,主要提供了三种方式用于得到SharedPreferences对象


安卓期末考点整理_第6张图片
三种方式获得SharePreferences对象

内容提供器

主要用于在不同的应用程序之间实现数据的共享功能。目前是Android实现跨程序共享数据的标准方式。一般有两种:
1.使用现有的内容提供其来读取和操作相应程序中的数据

  1. 创建自己的内容提供器给我们的程序的数据提供外部访问接口

使用本机内容提供者

Android平台提供了一些本机内容提供者有:浏览器、联系人、通话记录、媒体存储、设置。
联系人内容提供者的URI各部分:

  • content://contacts/people/20
  • content:// 指定数据受内容提供者控制。它是标准前缀
  • contacts:指原生Contacts内容提供者
  • people指contacts列表可用记录
  • 20指Contacts列表中的第二十条记录。它是指定记录的ID
  • 使用getContentResolver()方法获取ContentResolver对象,通过该对象的以下方法访问内容提供者
public final Uri insert(Uri url, ContentValues values)
public final int delete(Uri url, String where, String[] selectionArgs)
public final int update(Uri uri, ContentValues values, String where,String[] selectionArgs)
public final Cursor query(Uri uri, String[] projection,String selection, String[] selectionArgs, String sortOrder)

使用自定义内容提供器

创建内容提供器

新建一个类去继承ContentProvider,并重写其6个方法,代码如下:

public class MyProvider extends ContentProvider {
    @Override
    public boolean onCreate() {
        return false;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        return null;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        return null;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
}
  1. onCreate()
    初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,
    返回 true 表示内容提供器初始化成功,返回 false 则表示失败。注意,只有当存在
    ContentResolver 尝试访问我们程序中的数据时,内容提供器才会被初始化。
  2. query()
    从内容提供器中查询数据。使用 uri 参数来确定查询哪张表,projection 参数用于确
    定查询哪些列,selection 和 selectionArgs 参数用于约束查询哪些行,sortOrder 参数用于
    对结果进行排序,查询的结果存放在 Cursor 对象中返回。
  3. insert()
    向内容提供器中添加一条数据。使用 uri 参数来确定要添加到的表,待添加的数据
    保存在 values 参数中。添加完成后,返回一个用于表示这条新记录的 URI。
  4. update()
    更新内容提供器中已有的数据。使用 uri 参数来确定更新哪一张表中的数据,新数
    据保存在 values 参数中,selection 和 selectionArgs 参数用于约束更新哪些行,受影响的
    行数将作为返回值返回。
  5. delete()
    从内容提供器中删除数据。使用 uri 参数来确定删除哪一张表中的数据,selection
    和 selectionArgs 参数用于约束删除哪些行,被删除的行数将作为返回值返回。
  6. getType()
    根据传入的内容 URI 来返回相应的 MIME 类型。

指定内容提供者的URI

public class MyProvider extends ContentProvider {

    public static final int TABLE1_DIR = 0;
    public static final int TABLE1_ITEM = 1;
    public static final int TABLE2_DIR = 2;
    public static final int TABLE2_ITEM = 3;
    private static UriMatcher uriMatcher;

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
        uriMatcher.addURI("com.example.app.provider ", "table1/#", TABLE1_ITEM);
        uriMatcher.addURI("com.example.app.provider ", "table2", TABLE2_ITEM);
        uriMatcher.addURI("com.example.app.provider ", "table2/#", TABLE2_ITEM);
    }

    ..........

}

实现查询方法

public class MyProvider extends ContentProvider {
    ..........

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        switch (uriMatcher.match(uri)) {
            case TABLE1_DIR:
                // 查询table1表中的所有数据
                break;
            case TABLE1_ITEM:
                // 查询table1表中的单条数据
                break;
            case TABLE2_DIR:
                // 查询table2表中的所有数据
                break;
            case TABLE2_ITEM:
                // 查询table2表中的单条数据
                break;
            default:
                break;
        }
        return null;
    }
    ....
}

处理对MINE类型数据的请求

public class MyProvider extends ContentProvider {

    ...........

    @Nullable
    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case TABLE1_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.app.provider. table1 ";
            case TABLE1_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.app.provider. table1 ";
            case TABLE2_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.app.provider. table2 ";
            case TABLE2_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.app.provider. table2 ";
            default:
                break;
        }
        return null;
    }
................
}

注册自定义内容提供器



广播接收者(BroadcastReceiver)

广播分为两种:普通广播和有序广播

  1. 普通广播

完全异步执行的广播,在广播发出后,所有的广播接收器几乎在同一时刻都会受到这条广播,没有先后顺序之分,无法被截断,效率较高


安卓期末考点整理_第7张图片
普通广播图示
  1. 有序广播

同步执行的广播,在广播发出后,同一时刻只会有一个广播接收器可以收到消息,且只有当该广播接收器中的逻辑执行完毕后,这条广播才会继续传递下去,有先后顺序之分,可以被截断。


安卓期末考点整理_第8张图片
有序广播图示

注册广播接收器的方式有两种:

  1. 动态注册

在代码中注册,新建一个类,并让其继承BroadcastReceiver类,同时重新其父类中的onReceive()方法即可,这样当有广播到来的时候,onReceive()方法便会得到执行,同时需要主活动中进行广播的注册,因为全程是在代码中运行,灵活性强,便被成为动态注册,示例如下:

private class NetWorkChangeReceiverextends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            // do something......
        }
    }

在onCreate()方法中执行:

intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
netWorkChangeReceiver = new NetWorkChangeReceiver();
registerReceiver(netWorkChangeReceiver, intentFilter);

在onDestory()方法中执行:

unregisterReceiver(netWorkChangeReceiver);//注销广播
  1. 静态注册

和动态注册相同的是,静态注册也需要创建一个类去继承BroadcastReceiver类并实现其中的onReceive()方法,但是注册的过程被放到了AndroidManifest.xml文件中了,示例如下:

MyBroadcastReceiver.java

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
    }
}

AndroidManifest.xml


       
           
       

动态注册和静态注册的区别:

动态注册不是常驻型广播,也就是说广播跟随程序的生命周期。
静态注册是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行

服务

创建一个服务

新建一个类MyService集成Service,并重写其onBind()方法即可

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

当然,最为四大组件之一的Service,服务在创建的时候需要在AndroidManifest.xml文件中进行注册才能生效



启动一个服务

调用startService()方法即可启动服务,传入一个intent参数即可

Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);

关闭一个服务

调用stopService()方法即可

Intent intent = new Intent(MainActivity.this, MyService.class);
stopService(intent);

绑定一个服务

  1. 定义一个内部类,该内部类实现接口”ServiceConnection”,同时实现接口里的两个方法:”onServiceConnection”(在这个方法方法体里得到Binder对象,由该对象就能得到服务实例)、”onServiceDisConnection”(当服务被意外断开,系统将会回调这个方法)。
  2. 分别创建服务类变量、内部类变量(内部类变量需要实例化),在”onServiceConnection”方法里面用得到的服务实例将服务类变量实例化
  3. 在需要绑定服务的地方,调用bindService()方法,将内部类变量传入。
public class MainActivity extends Activity implements View.OnClickListener {  
    //第二步:创建内部类变量以及服务类的变量  
    //同时实例化内部类变量  
    private MService mService = null;    
    private MServiceConnection mServiceConnection =   
    new MServiceConnection();  
   
    //窗体的初始化方法  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        findViewById(R.id.bt_bind_the_service)  
         .setOnClickListener(this);        
    }  
    //点击事件响应函数  
    @Override  
    public void onClick(View v) {  
  
        switch (v.getId()){  
            case R.id.bt_bind_the_service:  
                Intent intent =  
             new Intent(MainActivity.this, MService.class);  
                //第三步:绑定服务那个时候将接口的实例传入  
                bindService(intent, mServiceConnection,  
                  Context.BIND_AUTO_CREATE);  
                break;  
        }  
    }  
  
    //第一步:定义一个内部类去实现接口”ServiceConnection”  
  
    class MServiceConnection implements ServiceConnection{  
        //这个方法里面那个service  
        //就是服务类里面的onBind()方法所返回的IBinder变量了  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service) {  
        //还是第二步:将服务类的变量实例化:  
            //将IBinder向下转型  
            MService.MyBinder myBinder = (MService.MyBinder)service;  
            //调用公有方法就能获得服务类的实例  
            mService = myBinder.getService();  
            Log.i("test","连接服务");  
        }  
  
        @Override  
        public void onServiceDisconnected(ComponentName name) {  
            Log.i("test", "意外断开");  
        }  
    }  
  
}  

解绑一个服务

相对于绑定一个服务和活动来说,解除服务和活动之间的绑定就显得容易很多,只需要执行unbindService()方法,并传入一个ServiceConnection()对象即可。

unbindService(connection);

服务的生命周期

详见 Android:Service生命周期最全面解析

你可能感兴趣的:(安卓期末考点整理)