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);
}
onCreate()方法其实也有一个Bundle类型的参数。这个参数在一般情况下都是null,但是当活动被系统回收之前有通过 onSaveInstanceState()方法来保存数据的话,这个参就会带有之前所保存的全部数据
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(),让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则

  1. 当用户按下HOME键时
  2. 长按HOME键,选择运行其他的程序时
  3. 锁屏时
  4. 从activity A中启动一个新的activity时
  5. 屏幕方向切换时

如何退出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);
    }  
 Person mPerson = (Person)getIntent().getSerializableExtra(ObjectTranDemo.SER_KEY);  
 Book mBook = (Book)getIntent().getParcelableExtra(ObjectTranDemo.PAR_KEY); 

怎么让在启动一个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");
category 是默认的,不需要需要写,每个 Intent中只能指定一个 action,但却能指定多个 category
intent.addCategory("com.example.activitytest.MY_CATEGORY");
可以调用 Intent中的 addCategory()方法来添加一个 category
intent-filter节点及其子节点都可以同时定义多个,隐式启动时只需与任意一个匹配即可
// 电话
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL); // 设置动作
intent.setData(Uri.parse("tel://123456")); // 设置数据
// 网页
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://192.168.1.45:8080/androidWeb"));
// 音频/视频,设置 type
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/daqin.mp3"), "audio/*"); // 设置数据和数据类型,将启动音频播放器(vedio)
 
 

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方法。

1.一旦在项目的任何位置调用了Context的startService()方法,相应的服务就会启动起来,并回调onStartCommand()方法。如果这个服务之前还没有创建过,onCreate()方法会先于onStartCommand()方法执行。
2.服务启动了之后会一直保持运行状态,直到 stopService()或stopSelf()方法被调用。注意虽然每调用一次startService()方法,onStartCommand()就会执行一次,但实际上每个服务都只会存在一个实例。所以不管调用了多少次startService()方法,只需调用一次stopService()或stopSelf()方法,服务就会停止下来了。

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怎么实现通信

方法一:

  1. 添加一个继承Binder的内部类,并添加相应的逻辑方法
  2. 重写Service的onBind方法,返回我们刚刚定义的那个内部类实例
  3. 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:阻止其他接收者接收这条广播,类似拦截,只有有序广播可以被拦截
发送有序广播:
  1. sendOrderedBroadcast(intent);
第一个参数仍然是Intent,第二个参数是一个与权限相关的字符串,这里传入 null就行了
     2.sendOrderedBroadcast(intent, null, new MyReceiver(), null, 0, "1", null);
这里的第三个参数是最终接收者resultReceiver:不需要在清单文件中配置,这个广播接收者只接受该条有序广播,并且是最后一个收到该广播,并且一定可以收到该广播
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");
	}

  

如何注册广播

广播的方式一般有两种,在代码中注册和在 AndroidManifest.xml中注册,其中前者也被称为动态注册,后者也被称为静态注册。
动态注册:需要使用广播接收者时,执行注册的代码,不需要时,执行解除注册的代码
  • 安卓中有一些广播接收者,必须使用代码注册,清单文件注册是无效的
  1. 屏幕锁屏和解锁
  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面试题的更多相关文章

  1. 最全面的 Android 编码规范指南

    最全面的 Android 编码规范指南 本文word文档下载地址:http://pan.baidu.com/s/1bXT75O 1. 前言 这份文档参考了 Google Java 编程风格规范和 Go ...

  2. 很全的 Python 面试题

    很全的 Python 面试题 Python语言特性 1 Python的函数参数传递 看两个例子:           Python   1 2 3 4 5 a = 1 def fun(a):      ...

  3. 最全面的Android Webview详解

    转自:最全面的Android Webview详解 前言 现在很多App里都内置了Web网页(Hyprid App),比如说很多电商平台,淘宝.京东.聚划算等等,如下图  那么这种该如何实现呢?其实这是 ...

  4. 最全面的Android Studio使用教程【申明:来源于网络】

    最全面的Android Studio使用教程[申明:来源于网络] http://www.admin10000.com/document/5496.html

  5. [转]一篇很全面的freemarker教程

    copy自http://demojava.iteye.com/blog/800204 以下内容全部是网上收集: FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主 ...

  6. 一篇很全面的freemarker教程

    以下内容全部是网上收集: FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成:1,文本:直接输出的部分2,注释:<#-- ... --& ...

  7. 【转】一篇很全面的freemarker教程---有空慢慢实践

    FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成: 1,文本:直接输出的部分 2,注释:<#-- ... -->格式部分,不会输 ...

  8. 最全面的Android Intent机制讲解

    对于大型软件开发经验较少的程序员来说,这可能是一个不太容易理解的抽象概念,因为它与我们平常使用的简单函数调用,或者通过库调用接口的方式不太一样.在 Intent 的使用中你看不到直接的函数调用,相对函 ...

  9. 一篇很全面的freemarker教程 前端工程师必备

    FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成: 1,文本:直接输出的部分 2,注释:<#-- ... -->格式部分,不会输 ...

随机推荐

  1. JavaScript高程--<script>标签

    <script>标签 在HTML5中script主要有以下几个属性:async,defer,charset,src,type, async(可选): 关键词:异步脚本,外部文件,立即下载: ...

  2. mybatis 详解(四)------properties以及别名定义

    上一篇博客我们介绍了mybatis的增删改查入门实例,我们发现在 mybatis-configuration.xml 的配置文件中,对数据库的配置都是硬编码在这个xml文件中,如下图,那么我们如何改进 ...

  3. linux指令大全

    系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...

  4. git for windows+TortoiseGit客户端的使用二

    通常都是使用git协议方式来连接服务器,然后使用https方式的连接方法,是如何设置的: 先登录github服务器,获取远程服务器仓库: 在本地创建一个存放仓库的目录,然后使用tortoiseGit客 ...

  5. POJ-1915 Knight Moves (BFS)

    Knight Moves Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 26952   Accepted: 12721 De ...

  6. redis单机安装以及简单redis集群搭建

    安装环境: 两台虚拟机都是Centos 7.0 IP分别为:192.168.149.132  192.168.149.133 Redis采用的版本是redis-3.2.4 集群是采用两台虚拟机模拟8个 ...

  7. C#设计模式(2)-简单工厂模式

    引言 上一遍中介绍了设计模式中的单例模式-C#设计模式(1)-单例模式,本篇将介绍简单工厂模式,也是比较容易理解的一种模式: 简单工厂模式简介 什么是简单工厂模式? 定义一个工厂类,它可以根据参数的不 ...

  8. selenium--关键字驱动

    package com.dn.twohomework;import java.util.ArrayList;import java.util.Set;import java.util.List;// ...

  9. 腾讯SNG电面

    第一次电面. 前半段基本闲聊,问题也记得不太清楚了. 自我介绍. 为什么想去上海工作?除了职业方面有其他原因吗?我猜出来面试官想问私人问题了,你真的可以直接问的,拐弯抹角了好久...有什么爱好.特长. ...

  10. iOS开发中如何创建多个target

    在开发iOS应用程序的过程中,经常需要根据不同的需求,切换到不同的项目配置,或者打不同的包(测试环境.开发环境.生产环境等等),如果每次都是手动配置,一则比较麻烦,二则容易配置错,那么有没有更好的方案 ...