【Android春招每日一练】(八) 剑指4题+Android基础

文章目录

    • 概览
    • 剑指offer
        • 1.29 栈的压入、弹出序列
        • 1.30 从上到下打印二叉树
        • 1.31 从上到下打印二叉树Ⅱ
        • 1.32 二叉搜索树的后序遍历序列
    • Android基础
        • Activity
        • Service
        • Broadcast
        • ContentProvider
    • 总结

概览

剑指offer:栈的压入、弹出序列、从上到下打印二叉树、从上到下打印二叉树Ⅱ、二叉搜索树的后序遍历序列;
Android基础:四大组件

剑指offer

1.29 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

示例:
输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
//用栈模拟
//遍历pushed数组,依次压栈,循环判断 “栈顶元素 == 弹出序列的当前元素” 是否成立,将符合弹出序列顺序的栈顶元素全部弹出。
class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Stack<Integer> stack = new Stack<>();
        int i = 0;
        for(int x : pushed){
            stack.push(x);
            while(!stack.isEmpty() && stack.peek() == popped[i]){
                stack.pop();
                i++;
            }
        }
        return stack.isEmpty();		//如果栈元素全部弹出则为真
    }
}

1.30 从上到下打印二叉树

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

例如:
给定二叉树: [3,9,20,null,null,15,7],
	3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]
//广度优先(BFS)
//建立一个辅助队列,每层节点加入队列,再循环出队加入值并加入子节点;
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root != null) queue.add(root);
        while(!queue.isEmpty()){
            List<Integer> tmp = new ArrayList<>();
            //精髓,不能写成for(int i=0;i
            for(int i=queue.size();i>0;i--){	
                TreeNode tNode = queue.poll();
                tmp.add(tNode.val);
                if(tNode.left != null) queue.add(tNode.left);
                if(tNode.right != null) queue.add(tNode.right);
            }
            res.add(tmp);
        }
        return res;
    }
}

1.31 从上到下打印二叉树Ⅱ

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

例如:
给定二叉树: [3,9,20,null,null,15,7],
	3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [20,9],
  [15,7]
]
//方法同Ⅰ,tmp改为LinkedList,方便头尾插入,使用res.size() % 2判断奇偶层;
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root != null) queue.add(root);
        while(!queue.isEmpty()){
            LinkedList<Integer> tmp = new LinkedList<>();
            for(int i = queue.size();i > 0 ;i--){
                TreeNode tNode = queue.poll();
                if(res.size() % 2 == 0){	//偶,插入尾
                    tmp.addLast(tNode.val);
                }else{						//奇,插入头
                    tmp.addFirst(tNode.val);
                }
                if(tNode.left != null) queue.add(tNode.left);
                if(tNode.right != null) queue.add(tNode.right);
            }
            res.add(tmp);
        } 
        return res;
    }
}

1.32 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

参考以下这颗二叉搜索树:

  5
 / \
2   6
   / \
  1   3
  
示例 1:
输入: [1,6,3,2,5]
输出: false

示例 2:
输入: [1,3,2,6,5]
输出: true

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OPtJml11-1642755913904)(D:\Typora\img\4a2780853b72a0553194773ff65c8c81ddcc4ee5d818cb3528d5f8dd5fa3b6d8-Picture1.png)]

/*
划分左右子树: 遍历后序遍历的[left, right]区间元素,寻找 第一个大于根节点 的节点,索引记为mid此时,可划分出左子树区间 [left,mid-1] 、右子树区间 [mid, right- ]、根节点索引right。
判断是否为二叉搜索树:
左子树区间 [left, mid- 1]内的所有节点都应 < postorder[right]。
右子树区间 [mid, right-1]内的所有节点都应 > postorder[right] 。
t == right:判断此树是否正确;
*/

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        return recur(postorder,0,postorder.length-1);
    }

    boolean recur(int[] postorder,int left,int right){
        if(left >= right) return true;
        int t = left;
        while(postorder[t] < postorder[right]) t++;
        int mid = t;
        while(postorder[t] > postorder[right]) t++;
        return t == right && recur(postorder,left,mid-1) && recur(postorder,mid,right-1);
    }
}

Android基础

Activity

Activity生命周期

onSaveInstanceStateonRestoreInstanceState

在Activity由于异常情况下终止时,系统会调用onSaveInstanceState来保存当前Activity的状态。这个方法的调用是在onStop之前,它和onPause没有既定的时序关系,该方法只在Activity被异常终止的情况下调用。当异常终止的Activity被重建以 后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象参数同时传递给onRestoreInstanceState和onCreate方法。因此,可以通过onRestoreInstanceState方法来恢复Activity的状态,该方法的调用时机是在onStart之后。其中onCreateonRestoreInstanceState方法来恢复Activity的状态的区别: onRestoreInstanceState回调则表明其中Bundle对象非空,不用加非空判断。onCreate需要非空判断。建议使用onRestoreInstanceState。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-azyxpMvA-1642755824249)(D:\Typora\img\image-20220120141744405.png)]

横竖屏切换的生命周期:onPause()->onSaveInstanceState()-> onStop()- >onDestroy()->onCreate()->onStart()->onRestoreInstanceState->onResume()

可以通过在AndroidManifest文件的Activity中指定如下属性:

android:configChanges = "orientation| screenSize" 

来避免横竖屏切换时,Activity的销毁和重建,而是回调了下面的方法:

@Override 

public void onConfigurationChanged(Configuration newConfig) { 
	super.onConfigurationChanged(newConfig); 
} 

Activity优先级的划分和下面的Activity的三种运行状态是对应的。

(1) 前台Activity——正在和用户交互的Activity,优先级最高。

(2) 可见但非前台Activity——比如Activity中弹出了一个对话框,导致Activity可见但是位于后台无法和用户交互。

(3) 后台Activity——已经被暂停的Activity,比如执行了onStop,优先级最低。当系统内存不足时,会按照上述优先级从低到高去杀死目标Activity所在的进程。

**Activity的三种运行状态 **

Resumed(活动状态) 又叫Running状态,这个Activity正在屏幕上显示,并且有用户焦点。就是用户正在操作的那个界面。

Paused(暂停状态) 这是一个比较不常见的状态。这个Activity在屏幕上是可见的,但是并不是在屏幕最前端的那个Activity。比如有另一个非全屏或者透明的Activity是Resumed状态,没有完全遮盖这个Activity。

Stopped(停止状态) 当Activity完全不可见时,此时Activity还在后台运行,仍然在内存中保留Activity的状态,并不是完全销毁。这个也很好理解,当跳转的另外一个界面,之前的界面还在后台,按回退按钮还会恢复原来的状态,大部分软件在打开的时候,直接按 Home键,并不会关闭它,此时的Activity就是Stopped状态。

**Activity的启动模式 **

Android提供了四种Activity启动方式:

标准模式(standard)

每启动一个Activity创建一个实例压栈,适用于绝大多数Activity;

栈顶复用模式(singleTop)

启动的Activity位于栈顶则重用栈顶实列,并回调onNewIntent方法

@Override protected void onNewIntent(Intent intent) { 
    super.onNewIntent(intent); 
}

适用于在通知栏点击收到的通知,然后需要启动一个Activity,这个Activity就可以用singleTop,否则每次点击都会新建一个Activity。

实际的开发过程中,某个场景下连续快速点击,启动了两个Activity。 如果这个时候待启动的Activity使用 singleTop模式可以避免这个Bug。

栈内复用模式(singleTask)

该模式是一种单例模式,即一个栈内只有一个该Activity实例。该模式,可以通过在 AndroidManifest文件的Activity中指定该Activity需要加载到那个栈中,即singleTask 的Activity可以指定想要加载的目标栈。singleTask和taskAffinity配合使用,指定开启的Activity加入到哪个栈中。

启动一个Activity如果其中有该Activity实例,则把该Activity实例之上的Activity杀死清除出栈,重用并让该Activity实例处在栈顶,然后调用onNewIntent()方法。

适用于App首页。

单例模式(singleInstance)

作为栈内复用模式(singleTask)的加强版,打开该Activity时,直接创建一个新的任务栈,并创建该Activity实例放入新栈中。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例。

适用于呼叫来电页面。

ActivityFlags

在启动Activity时,通过Intent的addFlags()方法设置。

(1)FLAG_ACTIVITY_NEW_TASK 其效果与指定Activity为singleTask模式一致。

(2)FLAG_ACTIVITY_SINGLE_TOP 其效果与指定Activity为singleTop模式一致。

(3)FLAG_ACTIVITY_CLEAR_TOP 具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。如果和singleTask模式一起出现,若被启动的Activity已经存在栈中,则清除其之上的Activity,并调用该Activity的onNewIntent方法。如果被启动的Activity采用standard模式,那么该Activity连同之上的所有Activity出栈,然后创建新的Activity实例并压入栈中。

Service

启动/停止服务

 Intent startIntent = new Intent(this, MyService.class); 
 startService(startIntent); // 启动服务

 Intent stopIntent = new Intent(this, MyService.class);
 stopService(stopIntent); // 停止服务

活动和服务通信

​ 新建了一个 DownloadBinder 类,并让它继承自 Binder,然后在它的内部提供了开始下载以及查看下载进度的方法。接着,在 MyService 中创建了 DownloadBinder 的实例,然后在 onBind()方法里返回了这个实例.

//Service
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; 
 } 
 ... 
}

​ 首先创建了一个 ServiceConnection 的匿名类,在里面重写了 onServiceConnected()方法和 onServiceDisconnected()方法,这两个方法分别会在活动与服务成功绑定以及活动与服务的连接断开的时候调用。

​ 建出了一个 Intent 对象,然后调用 bindService()方法将 MainActivity 和 MyService 进行绑定。bindService()方法接收 3 个参数,第一个参数就是刚刚构建出的 Intent 对象,第二个参数是前面创建出的 ServiceConnection 的实例,第三个参数则是一个标志位.

private MyService.DownloadBinder downloadBinder;
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(); 
	 } 
 };
 Button bindService = (Button) findViewById(R.id.bind_service); 
 Button unbindService = (Button) findViewById(R.id.unbind_service); 
 bindService.setOnClickListener(this); 
 unbindService.setOnClickListener(this);

 @Override 
 public void onClick(View v) { 
 	switch (v.getId()) { 
	 ... 
	 case R.id.bind_service: 
 		Intent bindIntent = new Intent(this, MyService.class); 
 		bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
 		break; 
	 case R.id.unbind_service: 
 		unbindService(connection); // 解绑服务
		break; 
 	 default: 
 		break; 
 	 } 
 }

**Service的几种典型使用实例 **

1.不可交互的后台服务

不可交互的后台服务即是普通的Service,通过startService()方式开启。Service的生命周期很简单,分别为onCreate、onStartCommand、onDestroy这三个。

public class MyService extends Service {
    private Thread mThread;
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    	mThread = new Thread() {
            @Override
            public void run() {
                try {
                    while (true) {
                        //等待停止线程
                        if (this.isInterrupted()) {
                                throw new InterruptedException();
                            }
                        //耗时操作。
                        System.out.println("执行耗时操作");
                     }
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }
            }
        };
        mThread.start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mThread.interrupt();
    }
}

配置服务:

  

配置远程服务,加如下代码:

android:process="remote" 

配置好Service类,只需要在前台,调用startService()方法,就会启动耗时操作。

注意:

①不运行在一个独立的进程中,它同样执行在UI线程中,因此,在Service中创建了子线程来完成耗时操作。

②当Service关闭后,如果在onDestory()方法中不关闭线程,你会发现我们的子线程进行的耗时操作是一直存在的,此时关闭该子线程的方法需要直接关闭该应用程序。因此,在**onDestory()**方法中要进行必要的清理工作。

2.可交互的后台服务

可交互的后台服务是指前台页面可以调用后台服务的方法,通过bindService()方式开启。Service的生命周期很简单,分别为onCreate、onBind、onUnBind、 onDestroy这四个。

可交互的后台服务实现步骤是和不可交互的后台服务实现步骤是一样的,区别在于启动的方式和获得Service的代理对象

public class BackService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
	//返回MyBinder对象
        return new MyBinder();
    }

    //需要返回给前台的Binder类
    class MyBinder extends Binder {
        public void showTip() {
            System.out.println("我是来此服务的提示");
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

前台调用 ,通过以下方式绑定服务:

bindService(mIntent,con,BIND_AUTO_CREATE);

其中需要一个ServiceConnection作为第二个参数

private ServiceConnection con=new ServiceConnection(){
    @Override
    public void onServiceConnected(ComponentName name,IBinder service){
        BackService.MyBinder myBinder=(BackService.MyBinder)service;
        myBinder.showTip();
    }
    @Override
    public void onServiceDisconnected(ComponentName name){
        
        }
};

当建立绑定后,onServiceConnected中的service便是Service类中onBind的返回值。如此便可以调用后台服务类的方法,实现交互。

当调用unbindService()停止服务,同时要在onDestory()方法中做好清理工作。

注意:通过bindService启动的Service的生命周期依附于启动它的Context。因此当前台调用bindServiceContext销毁后,那么服务会自动停止。

3.前台服务

所谓前台服务只不是通过一定的方式将服务所在的进程级别提升了。前台服务会一直有一个正在运行的图标在系统的状态栏显示,非常类似于通知的效果。

在Service的基础上创建一个Notification,然后使用Service的startForeground()方法即可启动为前台服务。

Broadcast

作用

用于监听 / 接收 应用发出的广播消息,并做出响应应用场景

  • 不同组件之间通信(包括应用内 / 不同应用之间)

  • 与 Android 系统在特定情况下的通信如当电话呼入时、网络可用时

  • 多线程通信

实现原理

Android 中的广播使用了设计模式中的观察者模式:基于消息的发布/订阅事件模型。因此,Android将广播的发送者 和 接收者 解耦,使得系统方便集成,更易扩展

模型中有3个角色:

  1. 消息订阅者(广播接收者)

  2. 消息发布者(广播发布者)

  3. 消息中心( AMS ,即 Activity Manager Service )

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9llU4Q1p-1642755824251)(D:\Typora\img\image-20220120164747683.png)]

原理描述:

  1. 广播接收者 通过 Binder 机制在 AMS 注册

  2. 广播发送者 通过 Binder 机制向 AMS 发送广播

  3. AMS 根据 广播发送者 要求,在已注册列表中,寻找合适的广播接收者 寻找依据: IntentFilter / Permission

  4. AMS 将广播发送到合适的广播接收者相应的消息循环队列中;

  5. 广播接收者通过 消息循环 拿到此广播,并回调 onReceive()

注意:广播发送者 和 广播接收者的执行 是 异步的,发出去的广播不会关心有 无接收者接收,也不确定接收者到底是何时才能接收到;

使用

1.自定义广播接收者BroadcastReceiver

  • 继承自BroadcastReceivre基类

  • 必须复写抽象方法onReceive()方法

  1. 广播接收器接收到相应广播后,会自动回调onReceive()方法

  2. 一般情况下,onReceive方法会涉及与其他组件之间的交互,如发送Notification、启动service等

  3. 默认情况下,广播接收器运行在UI线程,因此,onReceive方法不能执行耗时操作,否则将导致ANR。

public class mBroadcastReceiver extends BroadcastReceiver {
    //接收到广播后自动调用该方法 
    @Override 
    public void onReceive(Context context, Intent intent) { 
        //写入接收广播后的操作 
    } 
}

2.广播接收器注册

注册的方式分为两种:静态注册、动态注册

静态注册

在AndroidManifest.xml里通过 标签声明

<receiver 
    android:name=".mBroadcastReceiver" > //此广播接收者类是mBroadcastReceiver
    //用于接收网络状态改变时发出的广播 
    <intent-filter> 
        <action android:name="android.net.conn.CONNECTIVITY_CH ANGE" />
    intent-filter> 
receiver>

当此App首次启动时,系统会自动实例化mBroadcastReceiver类,并注册到系 统中。

动态注册

在代码中通过调用Context的registerReceiver()方法进行动态注册

注意:动态广播最好在Activity的onResume()注册、onPause()注销。

对于动态广播,有注册就必然得有注销,否则会导致内存泄露 ,重复注册、重复注销也不允许。

区别:

广播类型

广播的类型主要分为5类:

普通广播(Normal Broadcast) :

即开发者自身定义intent的广播(最常用)

系统广播(System Broadcast) :

Android中内置了多个系统广播:只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播 ;当使用系统广播时,只需要在注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作时会自动进行系统广播

有序广播(Ordered Broadcast) :

定义发送出去的广播被广播接收者按照先后顺序接收

广播接受者接收广播的顺序规则(同时面向静态和动态注册的广播接受者)

  1. 按照Priority属性值从大-小排序;

  2. Priority属性相同者,动态注册的广播优先;

特点

  1. 接收广播按顺序接收

  2. 先接收的广播接收者可以对广播进行截断,即后接收的广播接收者不再接收到此广播;

  3. 先接收的广播接收者可以对广播进行修改,那么后接收的广播接收者将接收到被修改后的广播

具体使用

有序广播的使用过程与普通广播非常类似,差异仅在于广播的发送方式:

sendOrderedBroadcast(intent); 

App应用内广播(Local Broadcast) :

App应用内广播可理解为一种局部广播,广播的发送者和接收者都同 属于一个App。 相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高

使用

1.注册广播时将exported属性设置为false,使得非本App内部发出的此广播

2.在广播发送和接收时,增设相应权限permission,用于权限验证;

3.发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。不被接收;

ContentProvider

作用

进程间 进行数据交互 & 共享,即跨进程通信

原理

ContentProvider的底层原理 = Android中的Binder机制

URI

// 设置URI
Uri uri = Uri.parse("content://com.carson.provider/User/1") 
// 上述URI指向的资源是:名为 `com.carson.provider`的`ContentProvider` 中表名 为`User` 中的 `id`为1的数据

// 特别注意:URI模式存在匹配通配符* & #
    
// *:匹配任意长度的任何有效字符的字符串
// 以下的URI 表示 匹配provider的任何内容
content://com.example.app.provider/* 
// #:匹配任意长度的数字字符的字符串
// 以下的URI 表示 匹配provider中的table表的所有行
content://com.example.app.provider/table/# 

MIME数据类型

MIME:全称Multipurpose Internet Mail Extensions,多功能Internet 邮件扩充服务。它是一种多用途网际邮件扩充协议,在1992年最早应用于电子邮件系统,但后来也应用到浏览器。MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

作用:指定某个扩展名的文件用某种应用程序来打开
如指定.html文件采用text应用程序打开、指定.pdf文件采用flash应用程序打开

ContentProvider类

组织数据方式

ContentProvide`主要以 表格的形式 组织数据,同时也支持文件数据,只是表格形式用得比较多

每个表格中包含多张表,每张表包含行 & 列,分别对应记录 & 字段(同数据库)

主要方法

  • 进程间共享数据的本质是:添加、删除、获取 & 修改(更新)数据
  • 所以ContentProvider的核心方法也主要是上述4个作用
<-- 4个核心方法 -->
  public Uri insert(Uri uri, ContentValues values) 
  // 外部进程向 ContentProvider 中添加数据

  public int delete(Uri uri, String selection, String[] selectionArgs) 
  // 外部进程 删除 ContentProvider 中的数据

  public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
  // 外部进程更新 ContentProvider 中的数据

  public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,  String sortOrder)  
  // 外部应用 获取 ContentProvider 中的数据

// 注:
// 1. 上述4个方法由外部进程回调,并运行在ContentProvider进程的Binder线程池中(不是主线程)
// 2. 存在多线程并发访问,需要实现线程同步
	// a. 若ContentProvider的数据存储方式是使用SQLite & 一个,则不需要,因为SQLite内部实现好了线程同步,若是多个SQLite则需要,因为SQL对象之间无法进行线程同步
	// b. 若ContentProvider的数据存储方式是内存,则需要自己实现线程同步

<-- 2个其他方法 -->
public boolean onCreate() 
// ContentProvider创建后 或 打开系统后其它进程第一次访问该ContentProvider时 由系统进行调用
// 注:运行在ContentProvider进程的主线程,故不能做耗时操作

public String getType(Uri uri)
// 得到数据类型,即返回当前 Url 所代表数据的MIME类型

Android为常见的数据(如通讯录、日程表等)提供了内置了默认的ContentProvider

但也可根据需求自定义ContentProvider,但上述6个方法必须重写

ContentProvider类并不会直接与外部进程交互,而是通过ContentResolver类;

ContentResolver类

作用

统一管理不同 ContentProvider间的操作,即通过 URI 即可操作 不同的ContentProvider中的数据

外部进程通过 ContentResolver类 从而与ContentProvider类进行交互

使用

// 外部进程向 ContentProvider 中添加数据
public Uri insert(Uri uri, ContentValues values)  

// 外部进程 删除 ContentProvider 中的数据
public int delete(Uri uri, String selection, String[] selectionArgs)

// 外部进程更新 ContentProvider 中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)  

// 外部应用 获取 ContentProvider 中的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

总结

1.初步结束了Java基础的学习,开启Android知识的学习;
2.学无止境,尽力多理解Android的各种机制,多阅读源码。

你可能感兴趣的:(春招,android,java,apache)