Android基础知识点学习总结

Posted 呓夏v

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android基础知识点学习总结相关的知识,希望对你有一定的参考价值。

android基础知识点学习总结

安卓基础知识个人学习笔记分享~

一、Android系统架构

Linux内核层→系统运行层→应用框架层→应用层

1、Linux内核层:Android系统是基于Linux内核的,这一层为硬件提供了底层的驱动,例如显示驱动,音频驱动,电源管理等等

2、系统运行库层:这一层主要通过C/C++实现,为Android系统提供支持,例如SQLite库提供了数据库的支持,Webkit提供了浏览器内核的支持(SQLite数据库:轻量级,嵌入式关系型数据库)

3、应用框架层:这一层提供了应用程序可能用到的各种API,我们开发者可以使用这些API来构建自己的应用程序

4、应用层:所有安装在手机上的应用程序都是属于这一层,当然也包括我们自己开发的应用程序

二、四大组件

Activity→Service→BroadcastReceiver→ContentProvider

1、Activity:所有看的到东西都是放在Activity中的

2、Service:我们无法看见他,他只会在后台默默运行,即使我们退出了应用,也是可以继续运行的

3、BroadcastReceiver:他允许应用接收来自各处的广播消息,例如电话,短信等,我们开发的程序也可以通过他向外发出广播消息

4、ContentProvider:为应用程序之间共享数据提供了可能,例如读取系统通讯录中的联系人,我们可以使用他来实现

三、目录结构各文件含义

.gradle和.idea

放置的都是Android Studio自动生成的一些文件

gradlew和gradle.bat

这两个文件是用来在命令行界面中执行gradle命令的,其中gradlew是在Linux或Mac系统中使用的,gradlew.bat是在Windows中使用的

HelloWorld.iml

这个文件是IntelliJ IDEA自动生成的(Android Studio是基于IntelliJ IDEA的),用于标识这是一个IntelliJ IDEA项目

local.properties

用于指定本机中的Android SDK路径,通常是自动生成的,如果SDK位置改变了,我们需要将文件中的路径改成新的位置即可。

setting.gradle

用于指定项目中所有引入的模块,通常都会自动完成

app目录下

libs目录

如果我们使用了第三方jar包,就需要将这些jar包都放在这个目录下,然后他会自动添加到项目的构建路径里

AndroidManifest.xml

这是整个Android项目的配置文件,我们在程序中定义的四大组件都需要在这个文件里注册,还可以在这个文件中给应用程序添加权限声明。****没有在这个文件中注册的组件是不能使用的!****MainActivity是我们编写的门面,然后将这个MainActivity注册进AndroidManifest.xml中才可以使用。

android.intent.action.MAIN决定应用程序最先启动的Activity ,android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里。Main和LAUNCHER同时设定才有意义。

Proguard-rules.pro

用于指定项目代码的混淆规则,让破解者难以阅读

res目录

以drawable开头的都是用来放图片的

以mipmap开头的都是用来放应用图标的(一般放在drawable-xxhdpi目录下)

以layout开头的都是用来放布局文件的

以values开头的都是用来放字符串,样式,颜色等配置的

String.xml中的字符串引用方式有两种:

代码中:R.string.name名

Xml中:@string/name名

如果引用的是图片资源可以替换成drawable,应用图标替换成mipmap,布局文件替换成layout,等等以此类推(相同类型不同目录下的xml文件引用前缀都是一样的,不一样的只有文件名)

四、日志工具

Android有五个日志级别,分别是log.v()、log.d()、log.i()、log.w()、log.e().级别依次递增

Log.v():打印最琐碎的日志信息,对应级别是verbose

Log.d():打印一些调试信息,对应级别debug

Log.i():打印一些比较重要的信息,对应级别info

Log.w():打印一些警告信息,对应级别warn

Log.e():打印一些错误信息,对应级别error

使用方法:例如Log.d(“MainActivity”,”onCreate execute”);

这个方法中有两个参数,第一个参数是tag,一般传入当前的类名,用于对打印出来的信息过滤,第二个参数是msg,即我们想要打印的内容。

五、Activity

1、Activity的启动方式分为两种:显式启动和隐式启动

显式启动:使用Intent对象,直接在Intent构造函数里指明要启动的activity

例如Intent intent = new Intent(getApplicationContext(),SecondActivity.class);

startActivity(intent);

隐式启动:匹配action和category

例如:Intent intent = new Intent(“com.example.activitytest.ACTION_START”);

intent.addCategory(“com.example.activitytest.MY_CATEGORY”);

startActivity(intent);

Intent可以添加多个category,但是只能指定一个action

2、使用intent在activity传递数据:

FirstActivity中的代码:

Intent intent = new Intent(getApplicationContext(),SecondActivity.class);

​ String data = “Hello SecondActivity!”;

​ intent.putExtra(“extra_data”,data);

​ startActivity(intent);

//使用putExtra方法,将信息装进intent中

SecondActivity中的代码:

Intent intent = super.getIntent();

​ String extraData = intent.getStringExtra(“extra_data”);

​ Log.d(“SecondActivity”,“extra data is :”+extraData);

//首先调用父类的方法得到intent,然后使用getStringExtra方法解析键为"extra_data"的字符串

3、返回数据给上一个activity:

Firstactivity中:

Intent intent = new Intent(SecondActivity.class);

​ startActivityForResult(intent,1);

//使用 startActivityForResult(intent,1);这个方法来启动activity,并传入一个请求码(唯一值)

@Override

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)

​ super.onActivityResult(requestCode, resultCode, data);

​ while (requestCode = 1)//判断这个是不是我们之前传出去的请求码

​ if (resultCode == RESULT_OK)//判断返回数据时传入的处理结果

​ String returnData = data.getStringExtra(data_return);

​ Log.d(“FirstActivity”,“return data is :”+returnData);

//然后重写onActivityResult方法,然后调用父类的这个方法,在这个方法里面有3个参数,第一个就是请求码,第二个是第二个activity返回的处理结果,第三个就是响应的数据了,我们需要对请求码和处理结果进行判断,再来接收数据

SeconActivity中:

Intent intent1 = new Intent();

​ intent1.putExtra(“data_return”,“Hello FirstActivity”);

​ setResult(RESULT_OK,intent1);//第一个参数用于向上一个activity返回处理结果即resultCode,一般只使用RESULT_OK或RESULT_CANCELED

​ finish();

//使用putExtra方法往intent里传值,使用setResult方法返回处理结果和intent,最后调用finish()方法来结束这个activity

/*如果是按返回键来返回到上一个activity,我们可以重写onBackPressed()方法/

4、Activity的4种状态:

1、*运行状态*:当activity位于栈顶的时候,activity就是运行状态,系统最不愿意回收的就是运行状态的activity

2、*暂停状态*:当activity不处于栈顶的时候,但仍然可见的时候,activity就是暂停状态(例如对话框形式的activity),系统也不愿意去回收他,只有在内存极低的时候才会去回收他

3、*停止状态*:当activity不处于栈顶,且完全不可见的时候,就是停止状态,此时系统仍然会保留这种activity的状态和成员变量,但是并不一定,当系统需要内存的时候,这中activity就很有可能会被回收。

4、*销毁状态*:当activity从栈中被移出的时候,就是销毁状态,系统最喜欢回收这种状态的activity,以保证内存的充足

5、Activity的生存期:

Activity类中定义了7个回调方法,对应了Activity生命周期的每一个环节,分别是

onCreat()、onStart()、onResume()、onPause()、onStop()、onDestroy()、onRestart()方法

1、onCreat():activity第一次创建的时候被调用

2、onStart():在activity由不可见为可见的时候被调用

3、onResume():在activity准备与用户交互的时候被调用,并且此时Activity一定位于栈顶,且处于运行状态

4、onPause():准备去启动或者恢复另一个activity时候调用,这时候系统会将一些消耗CPU的资源释放掉,以及保存一些关键数据,这个方法执行要快,不然会影响新的栈顶activity的使用

5、onStop():在activity完全不可见的时候调用(如果启动的是对话框式的新activity则不会执行,但onPause()会执行,这是他俩的区别)

6、onDestroy():在activity被销毁之前调用,然后activity状态变成销毁状态

7、onRestart():在activity又停止状态变为运行状态的时候调用

6、Activity的启动模式:

Standard、singleTop、singleTask、singleInstance

1、Standard:标准的启动模式,activity每次启动都是一个新的,然后再入栈

2、singleTop:当activity位于栈顶的时候,再去启动这个activity不会再创建一个新的activity,而是直接去使用之前那个activity

3、singleTask:当去启动一个activity的时候,回去检查栈中是否有这个activity,如果有则将这个activity以上的activity全部出栈

4、singleInstance:这个模式下的activity会启用一个新的返回栈来管理这个activity(使用案例:使用这个启动模式的activity可以被其他程序共享,因为这个activity的返回栈是独立出来的)

UID进程之间可以相同,但是PID不一样,他是唯一标识的,UID相同的进程可以实现相互之间的数据共享,但是其他的比如类还是不可以共享的

六、AndroidManifest.xml文件

权限声明

Android将将权限分成了三类,普通权限和危险权限,以及以一类特殊权限(暂时不讨论),

普通权限:系统会帮用户自动申请此类权限(例如广播权限等)

危险权限:需要用户自己手动授权(联系人信息,地理位置等)

权限是按组划分的,有可能好几个权限名在一个组里,*原则上,用户同意某一个权限申请之后,同组其他的权限也会被自动授权*,但是Android系统可能随时调整权限的分组,所以我们不能基于此规则来实现功能逻辑。

使用危险权限时必须进行运行时权限处理

首先我们需要在AndroidManifest.xml文件中声明这个权限

首先我们需要判断用户是不是以及对应用受过权了

借助ContextCompat.checkSelfPermission(ThirdActivity.this,Manifest.permission.CALL_PHONE) 方法,传入两个参数,其中第一个参数为当前activity,第二个参数是我们请求的权限名(常量),然后将这个方法的返回值与PackageManager.PERMISSION_GRANTED做比较,如果相等则已授权,否则就是还没有授权,

如果没授权的话我们需要向用户申请权限,调用 ActivityCompat.requestPermissions(ThirdActivity.this,new String[]Manifest.permission.CALL_PHONE,2);方法,这个方法传入三个参数,第一个参数是activity实例,第二个参数是string数组,我们可以把权限名放在这个数组里面,第三个参数是请求码,要求是唯一值就行。

如果我们需要请求用户授权,调用requestPermissions方法后,需要重写 onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)方法,并在这个方法里判断用户是否授权

清单注册

四大组件Activity,Service,BroadcastReceiver,ContentProvider的使用必须在Androidmanifest.xml中注册,其中BroadcastReceiver分为动态注册和静态注册

Activity注册:

Service注册:<service android:name=“.SecondService”

BroadcastReceiver注册:

静态注册:

动态注册:

通过继承 BroadcastReceiver在activity内建立一个内部动态广播接收器类(TimeChangeReceiver),然后重写onReceive方法

然后在activity的onCreate()方法中实例化一个IntentFilter()对象,通过addAction()往这个对象传入一个常量,比如我们这里可以传入一个”android.intent.action.TIME_TICK”值,当系统时间发生变化的时候,系统发的正是一个值为这个的广播,也就是说我们想要监听什么广播,就往这里面添加相应的action,然后再把我们之前建立的广播接收器类实例化,最后调用registerReceiver(timeChangeReceiver,intentFilter)方法,这个方法需要接收两个参数,第一个就是我们自定义的广播接收器类的实例,第二个就是intentFilter实例。

*动态注册一定要记得取消注册!*

这里我们可以在onDestroy()中调用unregisterReceiver(timeChangeRe ceiver)

ContentProvider注册:注意android:authorities代表了权限,要和你设置ContentProvider的uri路径格式中:中的authority一致,否者会出现问题。

七、Service服务

1、了解Service在Android的定位

Service是Android中实现程序后台运行的解决方案,他不依赖于任何用户界面,他也不是运行在一个独立的进程中,而是依赖于创建service时所在的应用程序进程,当这个应用程序进程被杀掉时,service也会停止运行

Service不会自动开启线程,默认是运行在主线程中的,我们需要在service内部创建子线程,将执行的任务放在子线程中执行,否则容易导致主线程被阻塞

2、startService()和bindService()区别

  1. 启动方式:都是用来启动service的,但是bindService()获得的是一个持久连接

  2. 和activity联系:startService()启动的service如果activity销毁,仍可以保持运行,除非整个应用程序被杀掉,bindService()启动的service会跟activity一起销毁

  3. 数据交换方面:startService()启动的service不可以和activity进行数据交换,而bindService()可以

  4. 回调函数方面:startService()启动的service的回调函数是onStartCommand(),而bindService()是onBind()

  5. 结束service的方式:startService()是启动的service是调用stopService()或者stopSelf()方法,而bindService()是调用unBindService()方法。当同时调用startservice()和bindService()的时候,要同时满足上面两种结束方式,这个service才会被停止

3、Service生命周期

startService()→onCreat()(service创建)→onstartCommand()(service运行)→stopService()(service停止运行)→onDestroy()(service销毁)

bindService()→onCreat()(service创建)→onBind()(绑定service)→unBindService()→onUnBind()(解除绑定,service停止运行)→onDestroy()(service销毁)

生命周期理解

StartService,然后oncreate,onstartcommand,再绑定bindServic,然后onbind,onServiceConnection,再stopService方法,此时不回调任何方法,再unBindService,然后onDestroy

*StartService,然后oncreate,onstartcommand,,再绑定bindServic,然后onbind,onServiceConnection,再unBindService方法,此时不回调任何方法,再stopService,然后onDestroy

bindService,然后onCreat,onBind,onServiceConnection,再startService,然后onstartcommand,再stopService方法,此时不回调任何方法,再unBindService,然后onDestroy

bindService,然后onCreat,onBind,onServiceConnection,再startService,然后onstartcommand,再unBindService方法,此时不回调任何方法,再stopService,然后onDestroy

4、service的使用

1.关于startService的使用

首先在Androidmanifest.xml文件中注册这个service

首次创建时的代码放进MyService中的onCreat()方法中,要执行的业务逻辑代码放进onStartCommand()方法里

在TestActivity里使用这个service

//开启这个服务

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

startService(intent);

//关闭这个服务

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

stopService(intent);

\\2. bindService的使用

同样需要在Androidmanifest.xml中注册这个service

然后在MyService中新建一个内部类MyBinder继承Binder,在这个类里面执行业务代码,然后在onBind()方法中返回这个MyBinder内部类的实例

在TestActivity里使用这个service

首先创建一个匿名类new ServiceConnection()实现,并重写onServiceConnected(),onServiceDisconnected()方法,在onServiceConnected()方法中先获取MyBinder的实例,然后调用MyBinder内部类中的业务代码,这个匿名类的返回值类型为ServiceConnection

然后将这个类型的变量conn传进bindService方法和unBindService方法中,实现绑定和解绑操作

八、广播机制(broadcast)

标准广播和有序广播

标准广播:无序,异步执行,发送出去广播所有可以接收的broadcastReceiver几乎同时收到,效率高,且无法被拦截,

有序广播:有序,同步执行,一次只能被一个接收器接收,只有这个接收器逻辑执行完毕才会向下一个broadcastReceiver传送,效率低,可以被拦截

\\1. 学习broadcast的注册方式。

静态注册和动态注册

静态注册:在AndroidManifest.xml中注册,

在Androidmanifest.xml中的intentFilter标签中添加一个要监听的action标签,如果是“危险”的广播还需要进行权限申明

动态注册:在代码中注册

使用intentFilter过滤器,然后添加一个action值,然后实例化一个broadcastReceiver对象(此处测试类中重写的onReceive方法中只实现了一个Toast),再调用registerReceiver()方法将这两个参数传递进去。然后就实现了动态广播注册

2. broadcast使用的注意事项

标准广播和有序广播的实现方式基本一致,只是最后发送调用的方法不同

发送标准广播:sendBoardcast(intent)

发送有序广播:sendOrderedBroadcast(intent,null)

在标签里面设置优先级,android:priority越高的接收器越先收到,同等优先级情况下,谁先启动的快谁先收到广播

静态注册的广播接收者无法收到隐式广播,此时我们需要指定包名,将这条隐式广播变成显式广播

*动态注册的广播要手动移出广播接收器*

3. 外部broadcast以及本地广播的使用

外部broadcast:程序之外的广播,例如系统广播等等,如前面动态注册和静态注册的使用

本地广播:需要使用到LocalBroadcastManager的实例(instance = LocalBroadcastManager.getInstance(this);),然后通过这个实例再去调用registerReceiver,即instance.registerReceiver(),里面传递的参数跟前面动态注册的参数是一样的。

4. SharePrefence(轻量级存储)的使用方式

适合单进程,小批量的数据存储与访问,因为他是基于单个xml文件的,一次性加载进内存的。属于全局可读写。

使用方式:我们首先需要获取一个SharedPreferences对象,有两种方式可以得到这个对象

Context类中的getsharedPreferences()方法,两个参数,第一个指定文件名(若文件不存在则会创建一个),第二个指定操作模式

Activity类中的getPreferences()方法,只有一个操作模式参数,文件名默认使用当前activity的类名

存储数据:

使用以上方式获得一个sharedPreferences对象后,调用edit()方法,然后获得一个SharedPreferences.Editor对象,这个对象中提供了putString,putInt,putBoolean等一系列方法,都是以键值对的形式存储数据,然后使用apply()或者commit()方式提交,apply()是异步的,commit()是同步的,推荐使用apply()方法

文件放在了Device File Explorer文件管理器下面的data/data//shared_prefs下了

取出数据:

也是先获得一个sharedPreferences对象,然后再调用这个对象的getString(),getInt(),getBoolean()方法,这些方法需要两个参数,第一个参数是键,第二参数指定若是取出数据失败返回的默认值

5.SharePrefence数据共享

两个应用(A和B)数据共享的前提是有 相同的sharedUserId,即首先我们需要在manifest.xml文件中配置这个属性android:sharedUserId=“com.xxx”.

然后在A应用中使用sharedPreferences存储数据(参考上面的存储数据)

接着在B应用中取出这些数据

首先创建一个Context 类型的对象packageText,然后调用createPackageContext(“com.netease.nim.demo”, CONTEXT_IGNORE_SECURITY);方法创建一个包上下文,把返回值赋值给packageText(此处操作需要在try catch中捕获异常)

然后通过这个packageText去调用getSharedPreferences(“userlists”, Context.MODE_MULTI_PROCESS);这个方法,返回值是SharedPreferences类型的,然后再通过这个返回值调用getString(),getBoolean()等方法得到A应用中存储的值(一样需要传入一个键,即A中存数据使用的键)

九、ContentProvider

ContentProvider概念:

翻译成中文是内容提供者,他可以实现应用之间的内容共享,可以指定哪部分具体的数据进行共享,而文件存储和sharePreferences是两种全局的可读写模式,相比较来说ContentProvider就可以保证数据没有泄露的风险。

ContentProvider使用表的形式来组织数据,类似一个单数据库表

每个ContentProvider都有一个唯一的公开的内容URI,用来指定他的数据集

一个标准的URI格式如下:

Content://com.example.contentProvider.accessProvider/table

1. contentProvider的使用

用法:用法一般有两种

①一种是使用现有的ContentProvider读取和操作相应的应用程序中的数据

查询:

ContentResolver.query( URI, projection, selection, selectionArgs, sortArgs)或者Activity.managedQuery(URI, projection, selection, selectionArgs, sortArgs)方法,这两个方法的参数一模一样,返回值也是相同的,不同的是activity可以对cursor对象管理,比如activity暂停的时候卸载cursor对象,restart的时候再重新查询。还可以调用Activity.startManaginCursor()方法来管理一个没有activity管理的cursor对象

参数解读:

第一个参数:URI指定某个应用程序下的某一张表

第二个参数:projection指定查询的列名

第三个参数:selection指定约束条件(对应SQL中where的约束条件)

第四个参数:selectionArgs给where中的占位符提供具体的值

第五个参数:sortOrder指定查询结果的排序方式

查询指定行的值,需要用到ID值,如果我们不想手动去拼接URI可以使用ContentUris.withAppendedId(URI,ID)方法

示例代码如下:


public class ForthActivity extends AppCompatActivity 

    private List<String> contactList = new ArrayList<String>();
    private ArrayAdapter<String> adapter;

    private static final String ForthActivity = "ForthActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.forth_activity);
        Log.d(ForthActivity, "执行了ForthActivity中的onCreate方法");
        Button readContacts = findViewById(R.id.readContacts);
        readContacts.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                if (ContextCompat.checkSelfPermission(ForthActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED)
                    ActivityCompat.requestPermissions(ForthActivity.this, new String[]Manifest.permission.READ_CONTACTS, 1);
                else
                    readContacts();
                    
                
        );

        Button accessProvider = findViewById(R.id.accessProvider);
        accessProvider.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                ContentResolver contentResolver = ForthActivity.this.getContentResolver();

                Uri uri = Uri.parse("com.example.contentProvider.provider1/table1/1");
                Cursor cursor = contentResolver.query(uri, null, null, null, null);
                while (cursor.moveToNext())
                    int num = cursor.getColumnIndex("1");
                    Log.d("forthActivity", "num"+num);
                
                cursor.close();
            
        );
    

    private void  readContacts()
        ContentResolver contentResolver =getContentResolver();
        Uri uri1 = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        Cursor cursor = contentResolver.query(uri1, null, null, null, null);

        while (cursor.moveToNext()) 
            @SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
            @SuppressLint("Range") String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            Log.d("forthActivity", "name:"+name+"电话号码:"+number);
        

        cursor.close();
    

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode)
            case 1:
            
                if (permissions.length!=0 && grantResults[0] != PackageManager.PERMISSION_GRANTED)
                    Toast.makeText(ForthActivity.this, "获取权限后重试", Toast.LENGTH_SHORT).show();
                
            break;
        
    

readContacts()方法解读:首先获得一个URI,然后再获得一个contenResolver对象,再通过这个对象调用相关的查询方法,将URI和其他参数传进这个查询方法里,返回一个cursor对象(游标、指针),然后通过这个指针去遍历这个结果集

增加:

调用contentResolver().insert(URI, values)方法

ContentValues values = new ContentValues();

values.put(“ID”, “Abraham Lincoln”);

Uri uri = ContentResolver().insert(URI, values);

解读:创建一个contentvalue对象,然后以键值对的形式往里面put值,键是列名,然后调用insert()方法,传入URI和这个put了值的values对象作为参数,这个插入方法会有一个返回结果,我们可以根据这个返回结果来判断是否插入成功,一般插入成功会返回该行的URI

修改:

Update()方法

int rowsUpdated = contentResolver().update(

URI,

updateValues,

selectionClause,

selectionArgs);

参数含义:URI,更新的值,约束条件,给where中的占位符提供具体的值

删除:delete()方法

②另一种是创建自己的ContentProvider,给程序的数据提供外部访问接口

在自定义的ContentProvider中有六个需要重写的方法,其他五个比较常见,分别是创建和增删改查,最后还有一个getType()方法,这个方法用来返回uri对象所对应的MIME类型

指定对应的uri地址,然后这写uri地址做逻辑判断,等到其他程序来调用的时候,通过这些逻辑判断来进行安全控制和访问内容的限制

public class AccessProvider extends ContentProvider 
    public AccessProvider() 
    

    private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static 
        uriMatcher.addURI("com.example.contentProvider.provider1",
                "table1", 1);
        uriMatcher.addURI("com.example.contentProvider.provider1",
                "table1/#", 2);
        uriMatcher.addURI("com.example.contentProvider.provider1",
                "table2", 3);
        uriMatcher.addURI("com.example.contentProvider.provider1",
                "table2/#", 4);
    

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) 
        // Implement this to handle requests to delete one or more rows.
        throw new UnsupportedOperationException("Not yet implemented");
    

    @Override
    public String getType(Uri uri) 
        // TODO: Implement this to handle requests for the MIME type of the data
        // at the given URI.
        throw new UnsupportedOperationException("Not yet implemented");
    

    @Override
    public Uri insert(Uri uri, ContentValues values) 
        // TODO: Implement this to handle requests to insert a new row.
        throw new UnsupportedOperationException("Not yet implemented");
    

    @Override
    public boolean onCreate() 
        // TODO: Implement this to initialize your content provider on startup.
        return false;
    

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) 
        switch (uriMatcher.match(uri))
            case 1:
                Log.d("AccessProvider", "进入了第一个判定条件");break;
            case 2:
                Log.d("AccessProvider", "进入了第二个判定条件");break;
            case 3:
                Log.d("AccessProvider", "进入了第三个判定条件");break;
            case 4:
                Log.d("AccessProvider", "进入了第四个判定条件");break;
            default:
                break;
        
        throw new UnsupportedOperationException("Not yet implemented");
    

    @RequiresApi(api = Build.VERSION_CODES.O)


    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) 
        // TODO: Implement this to handle requests to update one or more rows.
        throw new UnsupportedOperationException("Not yet implemented");
    

如何使用,见①中代码

  1. contentProvider进程间通信

访问危险权限需要在manifest.xml中申明,提供接口和访问数据上面有提到

十、五大布局的使用以及约束布局的使用

1、了解各个布局的区别以及如何使用

布局包含控件,布局与布局之间是可以嵌套使用的,可以理解成控件是布局里面的最小组成单元。

Android的五大布局+后来的constraintLayou(约束布局)

五大布局分别是:LinearLayout,relativeLayout,frameLayout,tableLayou(淘汰),absoluteLayou(淘汰)

2、LinearLayout(线性布局):

这个布局有horizontal(水平排列)和vertical(垂直排列)两种方式,默认就是垂直排列,水平排列的时候,控件的宽度不能指定为match_parent,垂直排列的时候控件的高度不能指定为match_parent

里面比较常用的属性:

layout_gravity:他是用来指定控件在布局中的对齐方式的,值得注意的是当linearLayout的布局方式为水平的时候,这个属性只有垂直对齐才有效,当linearLayout的布局方式为垂直的时候,这个属性只有水平对齐才有效

Layout_weight=”1”:以LinearLayout的水平布局为例,如果有三个按钮,我们可以将这三个按钮的宽度属性指定为”0dp”,然后再使用这个属性,意思是说这三个按钮水平分布平分水平的宽度,这个1其实就是权重

3、relativeLayout(相对布局):

这个布局他可以通过相对定位的方式来让控件出现在任何位置

比较常用的属性:

layout_alignParentleft,layout_alignParenttop…和哪边一直这里是左边和上边一致

Layout_above=”@id/button1” 在哪个控件的上面

Layout_below=”@id/button1” 在哪个控件的下面

Layout_toLeftOf=”id/button1” 在哪个控件的左边

Layout_toRightOf=”@id/button1” 在哪个控件的右边

4、frameLayout(帧布局):

这里面的控件默认会摆放在布局的左上角,他的定位方式比较少,比如:

Layout_gravity=”left”:指定控件居左对齐

Layout_gravity=”right”:指定控件居右对齐

十一、自定义Shape资源,drawable资源等

1、了解drawable文件夹中可自定义的文件种类

Drawable是什么,翻译成中文意思是说能画的东西,专业的解释是:一种可以在Canvas上进行绘制的抽象的概念,颜色,图片都可以说是drawable,可以通过xml文件定义,也可以通过代码创建,所有的实现的drawable都是Drawable这个抽象类的子类。

drawable文件下可以存放图片资源,例如*.jpg,.png,.gif,

还可以放xml文件,其中常用xml类型的资源文件有:

ShapeDrawable:通过颜色构造的图形,可以是纯色的图形,也可

Android 面试题总结之Android 基础

Android 面试题总结之Android 基础Activity(一)

转眼间毕业好久了,写程序也很久了,从高中就一直写到现在好多年了啊,学习了很多东西,把之前整理的资料和知识点慢慢分享出来。这里主要总结Android可能出的面试的题目比较全面\\详细,持久更新,也欢迎大家补充,纠正,批评。

在阅读过程中有任何问题,请及时联系。
本章系《Android 之美 从0到1 – 高手之路》Android基础Activity 总结了Android 开发者面试比较常见的Activity面试问题。希望对广大Android 开发者,有所帮助。