很全面的Android面试题
Activity
什么是Activity
- 四大组件之一,一个和用户交的互界面就是一个activity,是所有 View 的容器
- 我开发常用的的有FragmentActivitiy,ListActivity , PreferenceActivity ,TabAcitivty等…如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity.
- 有个 ActivityManager 的管理服务类,用于维护与管理 Activity 的启动与销毁;Activity 启动时,会把 Activity 的引用放入任务栈中,一个应用程序可以被别的应用程序的 activity 开启,此时,是将此应用程序的引用加入到了开启的那个 activity 的任务栈中。
- activity 是运行在自己的程序进程里面的,在一个应用程序中,可以申请单独的进程,让此应用程序中的一个组件在新的进程中运行
- 可以在 activity 里面添加 permission 标签,调用者必须加入这个权限与钱打交道的界面,都不允许被其他应用程序随意打开,如果觉得那个 activity 比较重要,可以在清单文件中配置,防止别人随意打开,需要配置一个权限。
Activity 生命周期
生命周期描述的是一个类 从创建(new出来)到死亡(垃圾回收)的过程中会执行的方法.
在这个过程中会针对不同的生命阶段会调用不同的方法
Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:
- oncreate:Activity对象创建完毕,但此时不可见
- onstart:Activity在屏幕可见,但是此时没有焦点
- onResume:Activity在屏幕可见,并且获得焦点
- onPause:Activity此时在屏幕依然可见,但是已经没有焦点
- onStop:Activity已经不可见了,但此时Activity的对象还在内存中
- onDestroy:Activity对象被销毁
其实这些方法都是两两对应的,onCreate创建与onDestroy销毁;onStart可见与onStop不可见;onResume可编辑(即焦点)与onPause;
还有一个onRestart方法了,在Activity被onStop后,但是没有被onDestroy,在再次启动此Activity时就调用onRestart(而不再调用onCreate)方法;如果被onDestroy了,则是调用onCreate方法。
两个Activity之间跳转时必然会执行的是哪几个方法。
一般情况比如说有两个activity,分别叫A,B ,当在A里面激活B组件的时候, A 会调用 onPause()方法,然后B 调用onCreate() ,onStart(), OnResume() ,这个时候B覆盖了窗体, A会调用onStop()方法. 如果B呢 是个透明的,或者是对话框的样式, 就不会调用onStop()方法。
因此,我们在两个activities中传递数据,或者共享资源时(如数据库连接),需要在前一个activity的onPause()方法而不是onStop()方法中进行
横竖屏切换时候Activity的生命周期。
这个生命周期跟清单文件里的配置有关系
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,默认首先销毁当前activity,然后重新加载
2、设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法,游戏开发中, 屏幕的朝向都是写死的.
如何将一个Activity设置成窗口的样式。
可以自定义一个activity的样式
android:theme="@android:style/Theme.Dialog"
你后台的Activity被系统 回收怎么办?如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?
除了在栈顶的activity,其他的activity都有可能在内存不足的时候被系统回收,一个activity越处于栈底,被回收的可能性越大.如果有多个后台进程,在选择杀死的目标时,采用最近最少使用算法(LRU)。
Activity中提供了一个 onSaveInstanceState()回调方法,这个方法会保证一定在活动被回收之前调用, 可以通过这个方法来解决活动被回收时临时数据得不到保存的问题。onSaveInstanceState()方法会携带一个 Bundle类型的参数,Bundle提供了一系列的方法用于保存数据,比如可以使用 putString()方法保存字符串,使用 putInt()方法保存整型数据。每个保存方法需要传入两个参数,第一个参数是键,用于后面从 Bundle中取值,第二个参数是真正要保存的内容。在 MainActivity中添加如下代码就可以将临时数据进行保存:
protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); String tempData = "Something you just typed"; outState.putString("data_key", tempData); }
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) { String tempData = savedInstanceState.getString("data_key"); }
也可以通过onRestoreInstanceState来存储和恢复数据,区别是不需要判断空了,onRestoreInstanceState调用一定是有值的
Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity,onSaveInstanceState() 会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。除非该activity是被用户主动销毁的,通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
onSaveInstanceState()被执行的场景有哪些:
系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,因此系统都会调用onSaveInstanceState(),让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
- 当用户按下HOME键时
- 长按HOME键,选择运行其他的程序时
- 锁屏时
- 从activity A中启动一个新的activity时
- 屏幕方向切换时
如何退出Activity?
退出activity 直接调用 finish () 方法
用户点击back键 就是退出一个activity ,退出activity 会执行 onDestroy()方法 。
1、抛异常强制退出:
该方法通过抛异常,使程序Force Close。不推荐使用
验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
安全结束进程 android.os.Process.killProcess(android.os.Process.myPid());
2、记录打开的Activity:
每打开一个Activity,就用集合记录下来。在需要退出时,关闭每一个Activity即可。
可以写在Application里,直接getApplication.list.add,在需要退出时遍历集合里的Activity,finish掉
也可以定义一个baseactivity里面进行操作,记得一般不用的话最后都需要把list=null
3、发送特定广播:
//在baseactivity里注册广播
registerReceiver(receiver, filter)
//想退出的时候就在onRecriver方法里finish()。
4、可以通过 intent的flag 来实现.. intent.setFlag(FLAG_ACTIVITY_CLEAR_TOP)激活一个新的activity,然后在新的activity的oncreate方法里面就可以finish掉.
讲一讲你对activity的理解
把上面的几点用自己的心得写出来
两个Activity之间怎么传递数据?
基本数据类型可以通过Intent 传递数据
//把数据封装至intent对象中 intent.putExtra("malename", "李志"); intent.putExtra("femalename", "芙蓉姐姐"); //把数据封装至bundle对象中 Bundle bundle = new Bundle(); bundle.putString("malename", "李志"); bundle.putString("femalename", "芙蓉姐姐"); //把bundle对象封装至intent对象中 intent.putExtras(bundle); startActivity(intent);
传递对象
1.让对象实现 implements Serializable 接口把对象存放到文件上.
让类实现Serializable 接口,然后可以通过 ObjectOutputStream //对象输出流
让类实现Serializable 接口,然后可以通过 ObjectOutputStream //对象输出流 File file = new File("c:\1.obj"); FileOutputStream fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fos); Student stu = new Student(); oos.writeObject(stu); //从文件中把对象读出来 ObjectInputStream ois = new ObjectInputStream(arg0); Student stu1 = (Student) ois.readObject();
2.如果要传递对象,需要把对象类序列化,然后intent.putExtra("mp3Info", mp3Info)
在另一个activity,或服务、广播中取出: Mp3Info mp3Info =(Mp3Info)intent.getSerializableExtra("mp3Info");
文件/网络
数据的uri, intent.setData() intent.getData();或者putstring("URL",URL)
实现Parcelable接口的可以用intent直接传 ,是存储在了内存中,如果是文件或者大图片就得用序列化
//Serializeable传递对象的方法 public void SerializeMethod(){ Person mPerson = new Person(); mPerson.setName("frankie"); mPerson.setAge(25); Intent mIntent = new Intent(this,ObjectTranDemo1.class); Bundle mBundle = new Bundle(); mBundle.putSerializable(SER_KEY,mPerson); mIntent.putExtras(mBundle); startActivity(mIntent); } //Pacelable传递对象方法 public void PacelableMethod(){ Book mBook = new Book(); mBook.setBookName("Android Tutor"); mBook.setAuthor("Frankie"); mBook.setPublishTime(2010); Intent mIntent = new Intent(this,ObjectTranDemo2.class); Bundle mBundle = new Bundle(); mBundle.putParcelable(PAR_KEY, mBook); mIntent.putExtras(mBundle); startActivity(mIntent); }
怎么让在启动一个Activity是就启动一个service?
在activity的onCreate()方法里面 startService();
如何返回数据
基本流程:
- 使用 startActivityForResult(Intent intent, int requestCode) 方法打开 Activity;
- 新 Activity 中调用 setResult(int resultCode, Intent data) 设置返回数据之后,关闭 Activity 就会调用onActivityResult 方法;
- 在原来的activity里重写 onActivityResult(int requestCode, int resultCode, Intent data) 方法;
- 注意:新的 Activity 的启动模式不能设置成 singleTask(如果已创建,会使用以前创建的)与 singleInstance(单
独的任务栈) ,不能被摧毁(执行不到 finish 方法) ,父 Activity 中的 onActivityResult 方法将不会执行;
请描述一下Intent 和 Intent Filter。
Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。
通过Intent 可以实现各种系统组件的调用与激活.
Intent filter:是传递的信息,这些信息不是必须的,有:
Action: 动作 view
Data: 数据uri uri
Category : 而外的附加信息
- 隐式意图跳转至指定Activity
<intent-filter > <action android:name="com.itheima.second"/> <data android:scheme="asd" android:mimeType="aa/bb"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> Intent intent = new Intent("com.example.activitytest.ACTION_START");
PendingIntent和Intent区别
它们都可以去指明某一个“意图” ,都可以用于启动活动、启动服务以及发送广播等。不同的是,Intent更加倾向于去立即执行某个动作,而 PendingIntent更加倾向于在某个合适的时机去执行某个动作。所以,也可以把 PendingIntent简单地理解为延迟执行的 Intent。
PendingIntent的用法同样很简单,它主要提供了几个静态方法用于获取 PendingIntent的实例,可以根据需求来选择是使用 getActivity()方法、getBroadcast()方法、还是 getService()方法。这几个方法所接收的参数都是相同的,第一个参数依旧是 Context,不用多做解释。
第二个参数一般用不到,通常都是传入 0即可。第三个参数是一个 Intent对象,我们可以通过这个对象构建出 PendingIntent的“意图” 。第四个参数用于确定 PendingIntent的行为,有FLAG_ONE_SHOT、 FLAG_NO_CREATE、 FLAG_CANCEL_CURRENT和 FLAG_UPDATE_
CURRENT这四种值可选,每种值的含义你可以查看文档
每8小时开启广播
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE); int anHour = 8 * 60 * 60 * 1000; // 这是8小时的毫秒数 long triggerAtTime = SystemClock.elapsedRealtime() + anHour; Intent i = new Intent(this, AutoUpdateReceiver.class); PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0); manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
Intent传递数据和Bundle传递数据是一回事,
Intent传递时内部还是调用了Bundle。
以下为源码:
public Intent putExtra(String name, boolean value) { if (mExtras == null) { mExtras = new Bundle(); } mExtras.putBoolean(name, value); return this; }
启动一个Activity有哪几种方法
startActivity
startActivityforresult
launcher的activity
widget
同一个程序,但不同的Activity是否可以放在不同的Task任务栈中?
启动模式里有个Singleinstance,可以运行在另外的单独的任务栈里面。用这个模式启动的activity,在内存中只有一份,这样就不会重复的开启。
也可以在激活一个新的activity时候, 给intent设置flag,Intent的flag添加FLAG_ACTIVITY_NEW_TASK,这个被激活的activity就会在新的task栈里面
Android中Task任务栈的分配。
1)任务栈的概念
问:一个手机里面有多少个任务栈?
答:一般情况下,有多少个应用正在运行,就对应开启多少个任务栈;
每开启一个应用程序就会创建一个与之对应的任务栈;
launchMode 为 singleInstance,就创建自己单独的任务栈;
栈:后进先出,最先进栈,就会最后出栈
Activity的启动模式就是修改任务栈的排列情况
2)任务栈的作用:
它是存放 Activity 的引用的,Activity不同的启动模式,对应不同的任务栈的存放;
可通过 getTaskId()来获取任务栈的 ID,如果前面的任务栈已经清空,新开的任务栈 ID+1,是自动增长的;
首先来看下Task的定义,Google是这样定义Task的:Task实际上是一个Activity栈,通常用户感受的一个Application就是一个Task。从这个定义来看,Task跟Service或者其他Components是没有任何联系的,它只是针对Activity而言的。
Activity有不同的启动模式, 可以影响到task的分配
Task,简单的说,就是一组以栈的模式聚集在一起的Activity组件集合。它们有潜在的前后驱关联,新加入的Activity组件,位于栈顶,并仅有在栈顶的Activity,才会有机会与用户进行交互。而当栈顶的Activity完成使命退出的时候,Task会将其退栈,并让下一个将跑到栈顶的Activity来于用户面对面,直至栈中再无更多Activity,Task结束。
事件 |
Task栈(粗体为栈顶组件) |
点开Email应用,进入收件箱(Activity A) |
A |
选中一封邮件,点击查看详情(Activity B) |
AB |
点击回复,开始写新邮件(Activity C) |
ABC |
写了几行字,点击选择联系人,进入选择联系人界面(Activity D) |
ABCD |
选择好了联系人,继续写邮件 |
ABC |
写好邮件,发送完成,回到原始邮件 |
AB |
点击返回,回到收件箱 |
A |
退出Email程序 |
null |
如上表所示,是一个实例。从用户从进入邮箱开始,到回复完成,退出应用整个过程的Task栈变化。这是一个标准的栈模式,对于大部分的状况,这样的Task模型,足以应付,但是,涉及到实际的性能、开销等问题,就会变得残酷许多。
比如,启动一个浏览器,在Android中是一个比较沉重的过程,它需要做很多初始化的工作,并且会有不小的内存开销。但与此同时,用浏览器打开一些内容,又是一般应用都会有的一个需求。设想一下,如果同时有十个运行着的应用(就会对应着是多个Task),都需要启动浏览器,这将是一个多么残酷的场面,十个Task栈都堆积着很雷同的浏览器Activity,是多么华丽的一种浪费啊。
于是你会有这样一种设想,浏览器Activity,可不可以作为一个单独的Task而存在,不管是来自那个Task的请求,浏览器的Task,都不会归并过去。这样,虽然浏览器Activity本身需要维系的状态更多了,但整体的开销将大大的减少,这种舍小家为大家的行为,还是很值得歌颂的
standard", "singleTop", "singleTask", "singleInstance"
Activity的启动模式
- standard 标准启动模式(自己启动自己会按三次才能退出)
- singleTop 单一顶部模式
- 如果任务栈的栈顶存在这个要开启的activity,不会重新的创建activity,而是复用已经存在的activity。保证栈顶如果存在,不会重复创建。
- 如在栈顶,则不会创建,会调用 onNewInstance(),复用已经存在的实例
- 应用场景:浏览器的书签
singeTask 单一任务栈,在当前任务栈里面只能有一个实例存在
- 当开启activity的时候,就去检查在任务栈里面是否有实例已经存在,如果有实例存在就复用这个已经存在的activity,并且把这个activity上面的所有的别的activity都清空,复用这个已经存在的activity。保证整个任务栈里面只有一个实例存在
- 应用场景:浏览器的activity
- 如果一个activity的创建需要占用大量的系统资源(cpu,内存)一般配置这个activity为singletask的启动模式。
singleInstance启动模式非常特殊, activity会运行在自己的任务栈里面,并且这个任务栈里面只有一个实例存在
- 如果你要保证一个activity在整个手机操作系统里面只有一个实例存在,使用singleInstance
- 应用场景: 电话拨打界面
Android下的进程
进程是被系统创建的,当内存不足的时候,又会被系统回收
内存管理:Android 系统在运行多个进程时,如果系统资源不足,会强制结束一些进程,优先选择哪个进程来结束是有优先级的。
会按照以下顺序杀死(进程级别):
①、空: 进程中没有任何组件(无组件启动,做进程缓存使用,恢复速度快),任务栈清空,意味着程序退出了,但进程留着,这个就是空进程,容易被系统回收;
②、后台:进程中只有停止状态(onStop)的 Activity;
③、服务:进程中有正在运行的服务;
④、可见:进程中有一个暂停状态(onPause)的 Activity;
⑤、前台:进程中正在运行一个 Activity;
Activity 在退出的时候进程不会销毁, 会保留一个空进程方便以后启动. 但在内存不足时进程会被销毁;
Activity 中不要在 Activity 做耗时的操作, 因为 Activity 切换到后台之后(Activity 停止了), 内存不足时, 也容易被销毁;
Service
14 .什么是Service以及描述下它的生命周期。Service有哪些启动方法,有什么区别,怎样停用Service?
在Service的生命周期中,被回调的方法比Activity少一些,只有onCreate, onStartCommand, onDestroy,onBind和onUnbind。
通常有两种方式启动一个Service,他们对Service生命周期的影响是不一样的。
1 通过startService
Service会经历 onCreate 到onStartCommand,然后处于运行状态,stopService的时候调用onDestroy方法。
如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。
2 通过bindService
Service会运行onCreate,然后是调用onBind, 这个时候调用者和Service绑定在一起。调用者退出了,Srevice就会调用onUnbind->onDestroyed方法。所谓绑定在一起就共存亡了。调用者也可以通过调用unbindService方法来停止服务,这时候Srevice就会调用onUnbind->onDestroyed方法。
3.当调用了startService()方法后,又去调用 stopService()方法,这时服务中的 onDestroy()方法就会执行,表示服务已经销毁了。类似地,当调用了 bindService()方法后,又去调用unbindService()方法,onDestroy()方法也会执行,这两种情况都很好理解。但是需要注意,我们是完全有可能对一个服务既调用了startService()方法,又调用了bindService()方法的,这种情况下该如何才能让服务销毁掉呢?根据Android系统的机制,一个服务只要被启动或者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被销毁。所以,这种情况下要同时调用stopService()和unbindService()方法,onDestroy()方法才会执行这样就把服务的生命周期完整地走了一遍。
start –> bind -> unbind -> stop 经常使用服务长期后台运行,又可以调用服务中的方法
service如何杀不死:
1.onStartCommand方法,返回START_STICKY(粘性)当service因内存不足被kill,当内存又有的时候,service又被重新创建
2.设置优先级,在服务里的ondestory里发送广播 在广播里再次开启这个服务,双进程守护
service是否在main thread中执行, service里面是否能执行耗时的操作?
默认情况,如果没有显示的指定service所运行的进程, Service和Activity是运行在当前app所在进程的main thread(UI主线程)里面
service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 ),需要在子线程中执行 new Thread(){}.start();
service里面可以弹土司吗
service里面弹toast需要添加到主线程里执行
@Override public void onCreate(){ handler = new Handler(Looper.getMainLooper()); System.out.println("service started"); handler.post(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "Test",Toast.LENGTH_SHORT).show(); }); }
Activity怎么和service绑定,怎么在activity中启动自己对应的service?
startService() 一旦被创建 调用着无关,没法使用service里面的方法
bindService () 把service 与调用者绑定 ,如果调用者被销毁, service会销毁,可以使用service 里面的方法
Service与Activity怎么实现通信
方法一:
- 添加一个继承Binder的内部类,并添加相应的逻辑方法
- 重写Service的onBind方法,返回我们刚刚定义的那个内部类实例
- Activity中创建一个ServiceConnection的匿名内部类,并且重写里面的onServiceConnected方法和onServiceDisconnected方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用,在onServiceConnected方法中,我们可以得到一个刚才那个service的binder对象,通过对这个binder对象进行向下转型,得到我们那个自定义的Binder实例,有了这个实例,做可以调用这个实例里面的具体方法进行需要的操作了
方法二
通过BroadCast(广播)的形式
当我们的进度发生变化的时候我们发送一条广播,然后在Activity的注册广播接收器,接收到广播之后更新视图
什么是IntentService?有何优点?
普通的service ,默认运行在ui main 主线程,Sdk给我们提供的方便的,带有异步处理的service类
OnHandleIntent() 处理耗时的操作,不需要开启子线程,这个方法已经在子线程中运行了
Intentservice若未执行完成上一次的任务,将不会新开一个线程,是等待之前的任务完成后,再执行新的任务,等任务完成后再次调用stopService()
startForeground(id, notification)
拥有service的进程具有较高的优先级。当内存不足时,拥有service的进程具有较高的优先级。
1. 如果service正在调用onCreate, onStartCommand或者onDestory方法,那么用于当前service的进程相当于前台进程以避免被killed。
2. 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
3. 如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
4. 如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
什么时候使用Service?
如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
1.Service的特点可以让他在后台一直运行,可以在service里面创建线程去完成耗时的操作.
2.Broadcast receiver捕获到一个事件之后,可以起一个service来完成一个耗时的操作.
广播
请描述一下Broadcast Receiver。
Android中:系统在运行过程中,会产生会多事件,那么某些事件产生时,比如:电量改变、收发短信、拨打电话、屏幕解锁、开机,系统会发送广播,只要应用程序接收到这条广播,就知道系统发生了相应的事件,从而执行相应的代码。使用广播接收者,就可以收听广播
广播分两种:有序广播、无序广播
无序广播:无序广播不可中断,不能互相传递数据;
有序广播:一个接一个的传递,广播可中断,通过调用 abortBroadcast()方法;接收者之间可以传递数据(intent);
粘性广播
无序广播(标准广播)
- 所有与广播中的action匹配的广播接收者都可以收到这条广播,并且是没有先后顺序,视为同时收到
有序广播
- 所有与广播中的action匹配的广播接收者都可以收到这条广播,但是是有先后顺序的,按照广播接收者的优先级排序
- 优先级的定义:-1000~1000
<intent-filter android:priority="100" > <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter>
- 最终接收者:所有广播接收者都接收到广播之后,它才接收,并且一定会接收
- abortBroadCast:阻止其他接收者接收这条广播,类似拦截,只有有序广播可以被拦截
- sendOrderedBroadcast(intent);
class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { String text = getResultData(); System.out.println("收到文件:" + text); } } //接收到自己发送出去的广播,最后接收(即使截断也能收到),因为在其他广播接收者可以修改数据 public class Two extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String text = getResultData(); setResultData("2"); }
如何注册广播
- 安卓中有一些广播接收者,必须使用代码注册,清单文件注册是无效的
- 屏幕锁屏和解锁
- 电量改变
public class MainActivity extends Activity { private IntentFilter intentFilter; private NetworkChangeReceiver networkChangeReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intentFilter = new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); networkChangeReceiver = new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver, intentFilter); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(networkChangeReceiver); } class NetworkChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "network changes",Toast.LENGTH_SHORT).show(); } } }
- 广播一旦发出,系统就会去所有清单文件中寻找,哪个广播接收者的action和广播的action是匹配的,如果找到了,就把该广播接收者的进程启动起来
4大组件其中比较特殊的是广播接收者,可以不在清单文件中配置,可以通过代码进行注册。其他组件全部在清单文件中注册
四大组件都可以配置这个属性 process在组件节点配置 process:如:android:process="xxx.ooo.xxx"
比如说:处理图片的时候,会很耗内存,就需要在单独的新的进程中,可以减少内存溢出的几率
广播的生命周期
a. 广播接收者的生命周期非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁;
b. 广播接收者中不要做一些耗时的工作,否则会弹出 Application No Response错误对话框;
c. 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉;
d. 耗时的较长的工作最好放在服务中完成;
内容提供者
请介绍下ContentProvider是如何实现数据共享的。
是四大组件之一,内容提供者的作用:把私有数据暴露给其他应用,通常,是把私有数据库的数据暴露给其他应用
在清单文件中定义内容提供者的标签,注意必须要有authorities属性,这是内容提供者的主机名,功能类似地址
<provider android:name="com.itheima.contentprovider.PersonProvider" android:authorities="com.itheima.person" android:exported="true" ></provider>
把自己的数据通过uri的形式共享出去,android 系统下不同程序,数据默认是不能共享访问
需要去实现一个类去继承ContentProvider
为什么要用ContentProvider?它和sql的实现上有什么差别?
屏蔽数据存储的细节,对用户透明,用户只需要关心操作数据的uri就可以了
不同app之间共享,操作数据
Sql也有增删改查的方法.
但是contentprovider 还可以去增删改查本地文件. xml文件的读取,更改,网络数据读取更改
请介绍下Android的数据存储方式
1.文件储存,在内部文件和SD卡
getCacheDir(),在data/data/包名/cache
getFilesDir(),在data/data/包名/files
SD卡:首先通过File file = new File(Environment.getExternalStorageDirectory(), "info.txt"),然后通过io存储
2.SharedPreference
3.SQLite数据库:
当应用程序需要处理的数据量比较大时,为了更加合理地存储、管理、查询数据,往往使用关系数据库来存储数据。Android系统的很多用户数据,如联系人信息,通话记录,短信息等,都是存储在SQLite数据库当中的,所以利用操作SQLite数据库的API可以同样方便的访问和修改这些数据。
4.ContentProvider:
主要用于在不同的应用程序之间实现数据共享的功能,不同于sharepreference和文件存储中的两种全局可读写操作模式,内容提供其可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险
Fragment
简单说说Fragment?
用途:在一个Activity里切换界面,切换界面时只切换Fragment里面的内容
生命周期方法跟Activity一致,可以理解把其为就是一个Activity,与Activity同存亡,Activity的XX方法调用,Fragment的XX方法就调用
他们是怎么进行传递数据的?
活动传递给Fragment:为了方便碎片和活动之间进行通信, FragmentManager提供了一个类似于findViewById()的方法,专门用于从布局文件中获取碎片的实例,前提是自己在布局文件中定义fragment这个标签,代码如下所示:
RightFragment rightFragment = (RightFragment) getFragmentManager()
.findFragmentById(R.id.right_fragment);
调用 FragmentManager的 findFragmentById()方法,可以在活动中得到相应碎片的实例,然后就能轻松地调用碎片里的方法了。还有findViewByTag,在replace 的时候设置tag
或者在fragment里声明接口,然后activity获得fragment对象调用接口里的方法
fragment数据传递给活动,直接getActivity就可以调用活动里的方法了
activity给fragment传递数据一般不通过fragment的构造方法来传递,会通过setArguments来传递,因为当横竖屏会调用fragment的空参构造函数,数据丢失。
fragment和fragment数据传递
首先在一个fragment可以得到与它相关联的活动,然后再通过这个活动去获取另外一个fragment的实例,这样也就实现了不同fragment之间的通信功能
FragmentManager , add 和 replace 有什么区别?
- 使用 FragmentTransaction 的时候,它提供了这样两个方法,一个 add , 一个 replace ,add 和 replace 影响的只是界面,而控制回退的,是事务。
- add 是把一个fragment添加到一个容器 container 里。replace 是先remove掉相同id的所有fragment,然后在add当前的这个fragment。
- 在大部分情况下,这两个的表现基本相同。因为,一般,咱们会使用一个FrameLayout来当容器,而每个Fragment被add 或者 replace 到这个FrameLayout的时候,都是显示在最上层的。所以你看到的界面都是一样的。但是, 使用add的情况下,这个FrameLayout其实有2层,多层肯定要比一层的来得浪费,所以还是推荐使用replace。 当然有时候还是需要使用add的。比如要实现轮播图的效果,每个轮播图都是一个独立的Fragment,而他的容器FrameLayout需要add多个Fragment,这样他就可以根据提供的逻辑进行轮播了。而至于返回键的时候,这个跟事务有关,跟使用add还是replace没有任何关系。
- replace()方法会将被替换掉的那个Fragment彻底地移除掉,因此最好的解决方案就是使用hide()和show()方法来隐藏和显示Fragment,这就不会让Fragment的生命周期重走一遍了。
Fragment和view的区别
Fragment可以有效的对 view进行管理(增删和替换)而且结构更加清晰,有模块化的实现思想。
用view 很多逻辑代码可能都需要写在Activity里,如果view很多, 耦合度会很高。用Fragment则可以各自管理,起了解耦的作用。
一般软件简单的话直接view,复杂的用Fragment。
viewpager是一个滑动切换的控件,Fragment是一个轻量级的Activity,这个Fragment可以放到这个Viewpager里面去运行。
例如QQ或微信那样,可以来回切换不同的选项卡,即切换了不同的Fragment。通常Viewpager 会放fargment或者view
Fragment和Activity的区别
因为现在的手机屏幕都比较大了,Activity会把内容拉的很长,用Fragment的话可以左侧是列表,右侧是内容。在一个Activity里切换界面,切换界面时只切换Fragment里面的内容。Fragment通常用来作为一个activity界面的一部分。
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">
很全面的Android面试题的更多相关文章
- 最全面的 Android 编码规范指南
最全面的 Android 编码规范指南 本文word文档下载地址:http://pan.baidu.com/s/1bXT75O 1. 前言 这份文档参考了 Google Java 编程风格规范和 Go ...
- 很全的 Python 面试题
很全的 Python 面试题 Python语言特性 1 Python的函数参数传递 看两个例子: Python 1 2 3 4 5 a = 1 def fun(a): ...
- 最全面的Android Webview详解
转自:最全面的Android Webview详解 前言 现在很多App里都内置了Web网页(Hyprid App),比如说很多电商平台,淘宝.京东.聚划算等等,如下图 那么这种该如何实现呢?其实这是 ...
- 最全面的Android Studio使用教程【申明:来源于网络】
最全面的Android Studio使用教程[申明:来源于网络] http://www.admin10000.com/document/5496.html
- [转]一篇很全面的freemarker教程
copy自http://demojava.iteye.com/blog/800204 以下内容全部是网上收集: FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主 ...
- 一篇很全面的freemarker教程
以下内容全部是网上收集: FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成:1,文本:直接输出的部分2,注释:<#-- ... --& ...
- 【转】一篇很全面的freemarker教程---有空慢慢实践
FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成: 1,文本:直接输出的部分 2,注释:<#-- ... -->格式部分,不会输 ...
- 最全面的Android Intent机制讲解
对于大型软件开发经验较少的程序员来说,这可能是一个不太容易理解的抽象概念,因为它与我们平常使用的简单函数调用,或者通过库调用接口的方式不太一样.在 Intent 的使用中你看不到直接的函数调用,相对函 ...
- 一篇很全面的freemarker教程 前端工程师必备
FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成: 1,文本:直接输出的部分 2,注释:<#-- ... -->格式部分,不会输 ...
随机推荐
- JavaScript高程--<script>标签
<script>标签 在HTML5中script主要有以下几个属性:async,defer,charset,src,type, async(可选): 关键词:异步脚本,外部文件,立即下载: ...
- mybatis 详解(四)------properties以及别名定义
上一篇博客我们介绍了mybatis的增删改查入门实例,我们发现在 mybatis-configuration.xml 的配置文件中,对数据库的配置都是硬编码在这个xml文件中,如下图,那么我们如何改进 ...
- linux指令大全
系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...
- git for windows+TortoiseGit客户端的使用二
通常都是使用git协议方式来连接服务器,然后使用https方式的连接方法,是如何设置的: 先登录github服务器,获取远程服务器仓库: 在本地创建一个存放仓库的目录,然后使用tortoiseGit客 ...
- POJ-1915 Knight Moves (BFS)
Knight Moves Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 26952 Accepted: 12721 De ...
- redis单机安装以及简单redis集群搭建
安装环境: 两台虚拟机都是Centos 7.0 IP分别为:192.168.149.132 192.168.149.133 Redis采用的版本是redis-3.2.4 集群是采用两台虚拟机模拟8个 ...
- C#设计模式(2)-简单工厂模式
引言 上一遍中介绍了设计模式中的单例模式-C#设计模式(1)-单例模式,本篇将介绍简单工厂模式,也是比较容易理解的一种模式: 简单工厂模式简介 什么是简单工厂模式? 定义一个工厂类,它可以根据参数的不 ...
- selenium--关键字驱动
package com.dn.twohomework;import java.util.ArrayList;import java.util.Set;import java.util.List;// ...
- 腾讯SNG电面
第一次电面. 前半段基本闲聊,问题也记得不太清楚了. 自我介绍. 为什么想去上海工作?除了职业方面有其他原因吗?我猜出来面试官想问私人问题了,你真的可以直接问的,拐弯抹角了好久...有什么爱好.特长. ...
- iOS开发中如何创建多个target
在开发iOS应用程序的过程中,经常需要根据不同的需求,切换到不同的项目配置,或者打不同的包(测试环境.开发环境.生产环境等等),如果每次都是手动配置,一则比较麻烦,二则容易配置错,那么有没有更好的方案 ...