android 知识点汇总 这一篇就够了

释放双眼,带上耳机,听听看~!

废话不多说,直接上图:
在这里插入图片描述

Activity

什么是Activity?

Activity是一个Android的应用组件,它提供屏幕进行交互。每个Activity都会获得一个用于绘制其用户界面的窗口,窗口可以充满哦屏幕也可以小于屏幕并浮动在其他窗口之上

Activity的生命周期

在这里插入图片描述

如何保存Activity的状态

1.一般来说, 调用 onPause()和 onStop()方法后的 activity 实例仍然存在于内存中, activity 的所有信息和状态数据不会消失, 当 activity 重新回到前台之后, 所有的改变都会得到保留。
但是当系统内存不足时, 调用onPause()和onStop()方法后的activity可能会被系统摧毁, 此时内存中就不会存有
该 activity 的实例对象了。如果之后这个 activity 重新回到前台, 之前所作的改变就会消失。为了避免此种情况的发生,我们可以覆写 onSaveInstanceState()方法 onSaveInstanceState()方法接受一个 Bundle 类型的参数, 开发者可以将状态数据存储到这个 Bundle 对象中, 这样即使 activity 被系统摧毁, 当用户重新启动这个 activity 而调用它的onCreate()方法时, 上述的 Bundle 对象会作为实参传递给 onCreate()方法,(或者是onRestoreInstanceState) 开发者可以从 Bundle 对象中取出保存的数据, 然后利用这些数据将 activity 恢复到被摧毁之前的状态。
2.需要注意的是, onSaveInstanceState()方法并不是一定会被调用的, 因为有些场景是不需要保存状态数据的.如按下back键退出当前活动

两个Activity之间跳转时必然会执行的是哪几个方法?

当在A 里面激活B 组件的时候, A会调用onPause()方法,然后B调用onCreate() ,onStart(), onResume()。
这个时候B覆盖了A的窗体, A会调用onStop()方法。
如果B是个透明的窗口,或者是对话框的样式, 就不会调用A的onStop()方法。
如果B已经存在于Activity栈中,B就不会调用onCreate()方法。

横竖屏切换时Activity的生命周期

第一次运行Activity : onCreate–>onStart–>onResume–>
切换成横屏时:onSaveInstanceState–>onPause–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume–>
在切换成竖屏时:onSaveInstanceState–>onPause–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume–>
onSaveInstanceState–>onPause–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume–>

如何将一个Activity设置成窗口的样式

activity中配置android:theme=”@android:style/Theme.Dialog”,另外
android:theme=”@android:style/Theme.Translucent”是设置透明

如何退出Activity?如何安全退出已调用多个Activity的Application?

退出Activity 直接调用 finish () 方法即可,退出activity 会执行 onDestroy()方法

多个Activity的Application退出方法:

1.记录打开的Activity:
每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
2、发送特定广播:
在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
3、递归退出
在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。

Activity的四种启动模式,singletop和singletask区别是什么?一般书签的使用模式是singletop,那为什么不使用singletask?

Activity的四种启动模式

在 AndroidManifest.xml 文件中 Activity 元素的 android:launchMode 属性。
Activity的四种启动模式:standard:这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中。
singleTop: 如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的
onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例
singleTask:如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
singleInstance:在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。

singletop和singletask区别是什么:

singleTop要求如果创建intent的时候栈顶已经有要创建的Activity的实例,则将intent发送给该实例,而不发送给新的实例。(注意是栈顶,不在栈顶照样创建新实例!)
singleTask模式:当intent到来,需要创建singleTask模式Activity的时候,系统会检查栈里面是否已经有该Activity的实例。如果有直接将intent发送给它。

一般书签的使用模式是singletop,那为什么不使用singletask?

singletask属性是如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。彻底改变了栈内的位置顺序

Android中的Context, Activity,Appliction有什么区别?

相同:Activity 和 Application 都是 Context 的子类。
Context 从字面上理解就是上下文的意思,在实际应用中它也确实是起到了管理 上下文环境中各个参数和变量的总用,方便我们可以简单的访问到各种资源。
不同:维护的生命周期不同。Context 维护的是当前的 Activity 的生命周期, Application 维护的是整个项目的生命周期。使用 context 的时候,小心内存泄露,防止内存泄露,注意一下几个方面:
不要让生命周期长的对象引用 activity context,即保证引用 activity 的对 象要与 activity 本身生命周期是一样的。
对于生命周期长的对象,可以使用 application,context.
避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类 对外部对象引用导致的生命周期变化。

两个Activity之间传递数据,除了intent,广播接收者,content provider还有啥?

1.利用static静态数据,public static成员变量
2.利用外部存储的传输,
3. 例如 File 文件存储
4. SharedPreferences首选项
5. Sqlite 数据库

Context 是什么?

1.它描述的是一个应用程序环境的信息,即上下文。
2、该类是一个抽象(abstract class)类,Android 提供了该抽象类的具体实 现类(ContextIml)。
3、通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作, 例如:启动一个 Activity,发送广播,接受 Intent,信息,

Service

Service是否在main thread中执行, service里面是否能执行耗时的操作?

默认情况,如果没有显示的指 service 所运行的进程, Service 和 activity 是运行在当前 app 所在进程的 main
thread(UI 主线程)里面。
service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )

Activity怎么和Service绑定,怎么在Activity中启动自己对应的Service?

Activity通过bindService(Intent service, ServiceConnection conn, int flags)跟Service进行绑定

private class myconn implements ServiceConnection
{
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
//可以通过IBinder的对象 去使用service里面的方法
}
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
Service生命周期

只调用 startService() 启动服务:onCreate() -> onStartCommand() -> onDestory()
只调用 bindService() 绑定服务:onCreate() -> onBind() -> onUnBind() -> onDestory()
同时使用startService()与bindService():onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory。

什么是IntentService?有何优点?

IntentService 是 Service 的子类,比普通的 Service 增加了额外的功能。
优点:
会创建独立的worker线程来处理所有的Intent请求;
会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
为Service的onBind()提供默认实现,返回null;
为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;

Activity、Intent、Service是什么关系

一个 Activity 通常是一个单独的屏幕,每一个 Activity 都被实现为一个单独的类,这些类都是从 Activity 基类中继承而来的。
Activity 类会显示由视图控件组成的用户接口,并对视图控件的事件做出响应。
Intent 的调用是用来进行屏幕之间的切换。Intent 描述应用想要做什么。Intent 数据结构中两个最重要的部分是动作和动作对应的数据,一个动作对应一个动作数据。
Service 是运行在后台的代码,不能与用户交互,可以运行在自己的进程里,也可以运行在其他应用程序进程的上下文里。需要一个Activity 或者其他 Context 对象来调用。
联系:
Activity 跳转 Activity,Activity 启动 Service,Service 打开 Activity 都需要 Intent 表明意图,以及传递参数,Intent 是这些组件间信号传递的承载着

Service和Activity在同一个线程吗

一般来说:同一个包内的activity和service,如果service没有设定属性android:process=”:remote”的话,service会和activity跑在同一个进程中,由于一个进程只有一个UI线程,所以,service和acitivity就是在同一个线程里面的。

Service里面可以弹吐司么

Service不仅可以弹Toast还能弹出对话框,第一,Service是运行在主线程当中;第二,弹吐司有个条件就是得有一个 Context 上下文,而 Service 本身就是 Context 的子类;因此在 Service 里面弹吐司是完全可以的。

Service里面可以弹吐司么

Context.startService() 和 Context.bindService()。 区别 为
Context.startService():Service 会经历 onCreate -> onStart(如果 Service 还没有运行, 则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(), 所以一个 Service 的 onStart 方法可能会重复调用多次 ); stopService 的时候直接 onDestroy,如果是调用者自己直接退出而没有调用 stopService 的话,Service 会一直在后 台运行。该 Service 的调用者再启动起来后可以通过 stopService 关闭 Service

Service有哪些启动方法,有什么区别,怎样停用Service?

Service 的方式 Context.startService() 和 Context.bindService()。 区别 为 Context.startService():Service 会经历 onCreate -> onStart(如果 Service 还没有运行, 则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(), 所以一个 Service 的 onStart 方法可能会重复调用多次 ); stopService 的时候直接 onDestroy,如果是调用者自己直接退出而没有调用 stopService 的话,Service 会一直在后 台运行。该 Service 的调用者再启动起来后可以通过 stopService 关闭 Service
Context.bindService():Service 会经历 onCreate() -> onBind(),onBind 将返回给客户端 一个 IBind 接口实例,IBind 允许客户端回调服务的方法,比如得到 Service 运行的状态或其 他操作。这个时候把调用者(Context,例如 Activity)会和 Service 绑定在一起,Context 退出了,Srevice 就会调用 onUnbind -> onDestroyed 相应退出,所谓绑定在一起就共存亡 了 。
停用 service 使用 context.stopService()

service的生命周期方法onstartConmand()可不可以执行网络操作?如何在service中执行网络操作?

可以直接在Service中执行网络操作

Broadcast Receiver
描述一下BroadcastReceiver

用于监听(接收)应用发出的广播消息,并做出响应

在manifest和代码中如何注册和使用BroadcastReceiver

首先写一个类要继承 BroadcastReceiver
第一种:在清单文件中声明,添加
第二种使用代码进行注册如:
创建IntentFilter ,并将要广播接收器接收的参数传进去
创建广播接收器,New出一个广播接收器
接着使用registerReceiver()方法,将上述创建的两个参数传进去

BroadCastReceiver的生命周期

每次广播到来时 , 会重新创建 BroadcastReceiver 对象 , 并且调用 onReceive() 方法 , 执行完以后 , 该对象即 被销毁

ContentProvider
请介绍下ContentProvider是如何实现数据共享的

使用 ContentProvider 可以将数据共享给其他应用,让除本应用之外的应用也可以访问本应用的数据。它的底层是用 SQLite 数据库实现的,所以其对数据做的各种操作都是以 Sql 实现,只是在上层提供的是 Uri,用户只需要关心操作数据的 uri 就可以了,ContentProvider 可以实现不同 app 之间共享

请介绍下Android的数据存储方式

五种 SharePreferences、SQLite、Contert Provider、File、网络存储

为什么要用ContentProvider?它和sql的实现上有什么差别?

ContentProvider实现了不同APP之间数据共享,ContentProvider为其他应用程序提供了访问本应用程序的接口,其他应用程序可以通过ContentResolver来操作ContentProvider提供的数据,同时ContentProvider保证了被访数据的安全性,用户只需要关心操作数据的uri就可以了。
sql也有增删改查的方法,单sql只能操作本应用下的数据库。

说说ContentProvider、ContentResolver、ContentObserver之间的关系

ContentProvider——内容提供者, 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。
ContentResolver——内容解析者, 其作用是按照一定规则访问内容提供者的数据(其实就是调用内容提供者自定义的接口来操作它的数据)。
ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。

Intent
Intent传递数据时,可以传递哪些类型数据?

Intent/Bundle支持传递基本类型的数据和基本类型的

Serializable和Parcelable的区别

两者区别在于存储媒介的不同。
Serializable使用IO读写存储在硬盘上。序列化过程使用了反射技术,并且期间产生临时对象。优点代码少。
Parcelable是直接在内存中读写,我们知道内存的读写速度肯定优于硬盘读写速度,所以Parcelable序列化方式性能上要优于Serializable方式很多。但是代码写起来相比Serializable方式麻烦一些。

请描述一下Intent 和 IntentFilter

filter一般不会在java代码中设置,而是在应用的manifest文件中作为元素的方式声明。一个例外是,为broadcast
receiver注册动态的filter,可以调用Context.registerReceiver()方法,通过直接实例化IntentFilter对象创建。

Fragment
Fragment跟Activity之间是如何传值的

fragment跳转activity传值 采用Bundle

Intent intent = new Intent(getActivity(), FirstActivity.class);
Bundle bundle = new Bundle();
bundle.putString("address", address);
intent.putExtras(bundle);
startActivity(intent);
描述一下Fragment的生命周期

被创建到用户可见: onAttach()->onCreate()->onCreateView()->onActivityCreated()onStart()->onResume()
后台模式:onPause()->onStop()
销毁: onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()

Fragment的replace和add方法的区别

可以看到add()方法添加的Fragment没有发生销毁对象的情况,怎么切换还是原来的Fragment
而replace()方法,会销毁前一个Fragment1,重新创建Fragment2

Fragment如何实现类似Activity栈的压栈和出栈效果的?

Fragment的事物管理器内部维持了一个双向链表结构,该结构可以记录我们每次add的Fragment和replace的Fragment,然后当我们点击back按钮的时候会自动帮我们实现退栈操作。

如何切换fragement,不重新实例化

正确的切换方式是add(),切换时hide(),add()另一个Fragment,再次切换时,只需hide()当前,show()另一 个。

扩展
在单线程模型中Message,Handler,Message Queue,Looper之间的关系。

拿主线程来说,主线程启动时会调用Looper.prepare()方法,会初始化一个Looper,放入Threadlocal中,接着调用Looper.loop()不断遍历Message Queue, Handler的创建依赖与当前线程中的Looper,如果当前线程没有Looper则必须调用Looper.prepare()。Handler , sendMessage到MessageQueue,Looper不断从MessageQueue中取出消息,回调handleMessage方法。

内存泄漏有哪些场景以及解决方法
  1. 类的静态变量持有大数据对象 静态变量长期维持到大数据对象的引用,阻止垃圾回收。
  2. 非静态内部类存在静态实例 非静态内部类会维持一个到外部类实例的引用,如果非静态内部类的实例是静态的,就会间接长期维持着外部类的引用,阻止被回收掉。
    3.资源对象未关闭 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们, 以便它们的缓冲及时回收内存。它们的缓冲不仅存在于java虚拟机内,还存在于java虚拟机外。 如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄露。 解决办法: 比如SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭), 如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。 因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null. 在我们的程序退出时一定要确保我们的资源性对象已经关闭。 程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小, 对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险,记得try catch后,在finally方法中关闭连接
    4.Handler内存泄漏 Handler作为内部类存在于Activity中,但是Handler生命周期与Activity生命周期往往并不是相同的,比如当Handler对象有Message在排队,则无法释放,进而导致本该释放的Acitivity也没有办法进行回收。 解决办法:
    5.一些不良代码习惯 有些代码并不造成内存泄露,但是他们的资源没有得到重用,频繁的申请内存和销毁内存,消耗CPU资源的同时,也引起内存抖动 解决方案 如果需要频繁的申请内存对象和和释放对象,可以考虑使用对象池来增加对象的复用。 例如ListView便是采用这种思想,通过复用converview来避免频繁的GC
如何避免 OOM 问题的出现

1.使用更加轻量的数据结构 例如,我们可以考虑使用ArrayMap/SparseArray而不是HashMap等传统数据结构。通常的HashMap的实现方式更加消耗内存,因为它需要一个额外的实例对象来记录Mapping操作。另外,SparseArray更加高效,在于他们避免了对key与value的自动装箱(autoboxing),并且避免了装箱后的解箱。
2.避免在Android里面使用Enum Android官方培训课程提到过“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”,具体原理请参考
3. 减小Bitmap对象的内存占用 Bitmap是一个极容易消耗内存的大胖子,减小创建出来的Bitmap的内存占用可谓是重中之重,,通常来说有以下2个措施: inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入。 decode format:解码格式,选择ARGB_6666/RBG_545/ARGB_4444/ALPHA_6,存在很大差异
4. Bitmap对象的复用 缩小Bitmap的同时,也需要提高BitMap对象的复用率,避免频繁创建BitMap对象,复用的方法有以下2个措施 LRUCache : “最近最少使用算法”在Android中有极其普遍的应用。ListView与GridView等显示大量图片的控件里,就是使用LRU的机制来缓存处理好的Bitmap,把近期最少使用的数据从缓存中移除,保留使用最频繁的数据, inBitMap高级特性:利用inBitmap的高级特性提高Android系统在Bitmap分配与释放执行效率。使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域,新解码的Bitmap会尝试去使用之前那张Bitmap在Heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放Bitmap。利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕所能够显示的图片数量的内存大小
5.使用更小的图片 在涉及给到资源图片时,我们需要特别留意这张图片是否存在可以压缩的空间,是否可以使用更小的图片。尽量使用更小的图片不仅可以减少内存的使用,还能避免出现大量的InflationException。假设有一张很大的图片被XML文件直接引用,很有可能在初始化视图时会因为内存不足而发生InflationException,这个问题的根本原因其实是发生了OOM。
6.StringBuilder 在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”。避免在onDraw方法里面执行对象的创建 类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动。

Android 中常用的五种布局

Android 布局是应用界面开发的重要一环,在 Android 中,共有五种布局方式,分别是: FrameLayout (框架布局),LinearLayout (线性布局),AbsoluteLayout (绝对布局), RelativeLayout (相对布局), TableLayout (表格布局)。

handler机制的原理

andriod提供了Handler和Looper来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。
1.Looper:一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
2.Handler:你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从MessageQueue取出)所送来的消息。
3.MessageQueue(消息队列):用来存放线程放入的消息。
4.线程:UIthread通常就是mainthread,而Android启动程序时会替它建立一个MessageQueue。

AsyncTask使用在哪些场景?它的缺陷是什么?如何解决?

解析 AsyncTask 运用的场景就是我们需要进行一些耗时的操作,耗时操作完成后更新主线程,或者在操作过程中对主线程的UI进行更新。 缺陷:AsyncTask中维护着一个长度为128的线程池,同时可以执行5个工作线程,还有一个缓冲队列,当线程池中已有128个线程,缓冲队列已满时,如果 此时向线程提交任务,将会抛出RejectedExecutionException。 解决:由一个控制线程来处理AsyncTask的调用判断线程池是否满了,如果满了则线程睡眠否则请求AsyncTask继续处理。

人已赞赏
Android文章

Android最最最简单的仿微信图片选择器

2020-3-11 20:01:03

Android文章

Android开发glide加载到自定义圆形CircleImageView不显示的最终解决办法

2020-3-11 21:33:40

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
有新消息 消息中心
搜索