Android面试题笔记(二)

来源:互联网 发布:按键精灵文字输出源码 编辑:程序博客网 时间:2024/06/02 17:27

1、Fragment生命周期?Fragment状态保存?
答:Fragment与Activity生命周期类似,只是多了几个方法。下面是对Fragment生命周期的测试

package com.example.asus.fragment;import android.app.Fragment;import android.content.Context;import android.os.Bundle;import android.support.annotation.Nullable;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;/** * Created by asus on 2017/3/19. */public class Fragment1 extends Fragment {    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        Log.d("Fragment","onCreateView");        return inflater.inflate(R.layout.fragment1_layout,container,false);    }    @Override    public void onActivityCreated(Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        Log.d("Fragment","onActivityCreated");    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        Log.d("Fragment","onAttach");    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("Fragment","onCreate");    }    @Override    public void onStart() {        super.onStart();        Log.d("Fragment","onStart");    }    @Override    public void onResume() {        super.onResume();        Log.d("Fragment","onResume");    }    @Override    public void onPause() {        super.onPause();        Log.d("Fragment","onPause");    }    @Override    public void onStop() {        super.onStop();        Log.d("Fragment","onStop");    }    @Override    public void onDestroyView() {        super.onDestroyView();        Log.d("Fragment","onDestroyView");    }    @Override    public void onDestroy() {        super.onDestroy();        Log.d("Fragment","onDestroy");    }    @Override    public void onDetach() {        super.onDetach();        Log.d("Fragment","onDetach");    }}

首先创建一个Fragment1类继承Fragment,然后在类中重写所有生命周期方法,然后打印方法。当第一调用Fragment1时打印的方法有:
这里写图片描述

然后按home键:
这里写图片描述

再次打开应用程序:
这里写图片描述

然后按back键:
这里写图片描述

这就是一个完整的Fragment生命周期,其中的onAttach()方法用于将Fragment和Activity绑定且最先调用,然后Activity的onCreate()方法调用后调用onCreateView()方法加载Fragment的布局,然后调用ActivityCreated()方法,而onDestroyView()和onDetach()方法与前面的onCreateView()和onAttach()方法相对应。


Fragment通常会在手机屏幕旋转后会存在数据丢失,当然可以使用onSaveInstanceState()方法来进行保存数据或者变量,然后在onActivityCreate()或onViewStateRestored()方法中获取。

但是当一个fragment从返回栈重新返回到栈顶时此时根据其生命周期可以知道其会调用onDestoryView()和onCreateView()方法,说明此时View重建,但是没有调用onSaveInstanceState()方法,一些UI数据会丢失,重新回到开始定义xml文件时的初始化状态,当然添加过android:freezeText属性的TextView和EditText数据依然还在,fragment为其保存了数据,但开发者无法直接获取,只能在onDestoryView中来进行保存,由于方法中没有Bundle参数,这时可以使用和Fragment共存的Argument,具体实现如下:

Bundle savedState;  @Override  public void onActivityCreated(Bundle savedInstanceState) {     super.onActivityCreated(savedInstanceState);     // Restore State Here     if (!restoreStateFromArguments()) {        // First Time running, Initialize something here     }  }  @Override  public void onSaveInstanceState(Bundle outState) {     super.onSaveInstanceState(outState);     // Save State Here     saveStateToArguments();  }  @Override  public void onDestroyView() {     super.onDestroyView();     // Save State Here     saveStateToArguments();  }  private void saveStateToArguments() {     savedState = saveState();     if (savedState != null) {        Bundle b = getArguments();        b.putBundle(“internalSavedViewState8954201239547”, savedState);     }  }  private boolean restoreStateFromArguments() {     Bundle b = getArguments();     savedState = b.getBundle(“internalSavedViewState8954201239547”);     if (savedState != null) {        restoreState();        return true;     }     return false;  }  /////////////////////////////////  // 取出状态数据  /////////////////////////////////  private void restoreState() {     if (savedState != null) {        //比如        //tv1.setText(savedState.getString(“text”));     }  }  //////////////////////////////  // 保存状态数据  //////////////////////////////  private Bundle saveState() {     Bundle state = new Bundle();     // 比如     //state.putString(“text”, tv1.getText().toString());     return state;  }  

然而当返回栈中存在多个fragment时,此时fragment A已有实例,当fragment B到栈顶时进行一次屏幕旋转,此时会调用onSaveInstanceState()方法保存了数据,但此时View已销毁并且没有重新创建,因此当再次旋转屏幕时程序会因为没有可显示的View而崩溃,出现一个空指针NullPointerException异常,因此应该在使用Argument进行数据保存时应判断是否存在 View,如果存在则保存其数据状态,然后把Argument中数据也保存一遍。

private void saveStateToArguments() {     if (getView() != null)        savedState = saveState();     if (savedState != null) {        Bundle b = getArguments();        b.putBundle(“savedState”, savedState);     }  }  

2、AsyncTask原理及不足?IntentService原理?
答:AsyncTask基于异步消息处理机制,可以从子线程切换到主线程,android上将其定义为一个抽象泛型类

public abstract class AsyncTask<Params,Progress,Result>

这里的三个泛型参数用途如下:
(1)Params:在执行AsyncTask时需要传入的参数,可用于后台任务时用。
(2)Progress:后台任务执行时,如果需要显示当前进度,则其可作为进度单位。
(3)Result:当后台任务执行完后,如果需要对结果返回,使用该参数作为返回值类型。

当然使用AsyncTask时还需重写这么几个方法:
(1)onPreExecute():后台任务执行前调用,用于一些界面上的初始换操作
(2)doInBackground(Params……):处理耗时任务在子线程中操作,任务完成后返回执行结果,如果要进行UI更新,还需调用publishProgress(Progress…)方法。
(3)onProgressUpdate(Progress…):当后台任务调用了publishProgress(方法后会调用此方法,其参数由后台任务传递过来,在此方法中进行UI操作。
(4)onPostExecute(Result):后台任务完毕返回执行结果后会立即调用此方法,执行结果会作为参数传入,可利用返回的数据进行一些UI操作。

使用AsyncTASK有这么几个缺点:
(1)在其生命周期中有一个doInBackground()方法来处理耗时任务,它不会随着Activity的销毁而停止,而是一直执行直到后台任务完成,此时可通过调用cancel(boolean)方法使得onCancelled(Result result)得到执行,否则onPostExecute(Result result)会执行。如果没有取消AsyncTask,Activity销毁后由于没有可处理的View会使程序崩溃。当然如果任务中有一个不可中断操作那么取消也无用。
(2)如果AsyncTask被声明一个非静态的内部类,那么会存在一个与AsyncTask关联的Activity的引用,如果Acitivity被销毁,后台任务仍在继续执行,但AsyncTask依然保留着这个引用,使得Activity不能完全被回收,可能导致内存泄漏。
(3)当屏幕旋转或后台时Activity可能会被kill(内存不足时),但此时依然存在一个引用,当Activity重启时,由于该引用已失效,在调用onPostExecute()更新界面时不会生效。
(4)如果此时的线程池中的线程数大于corePoolSize(核心线程),workQuene(任务队列)已满且已达maximumPoolSize(最大线程数)时,线程池将拒绝接收任务,此时只能使用handler处理。关于线程的更多知识可参考http://www.jianshu.com/p/78444487c5ab。


InterService:
Service和Activity同样是运行在主线程中的,但直接在服务中要执行一些耗时操作时,可能会发生ANR,所以在服务中每一个进行的任务中都需要开启一个子线程,这就是多线程编程,当然我们还可以将这些任务放在同一个子线程中顺序进行,不过都得手动操作,要创建一个这种异步处理任务且能够自动停止的服务,那么使用IntentService便可实现这个功能。

IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.

This “work queue processor” pattern is commonly used to offload tasks from an application’s main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.

All requests are handled on a single worker thread – they may take as long as necessary (and will not block the application’s main loop), but only one request will be processed at a time.

从androidAPI的描述可知道:IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。 所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。

3、单线程模型下Message、Handler、Message Quene、Looper之间的关系?
答:先介绍下各自的作用:
(1)Message:一个消息类型,可以理解为线程之间交流的信息,一般在更新UI时,子线程发送消息给主线程使用Handler的handlerMessage()方法进行处理。
(2)Message Quene:用来存放Message的消息队列,通常附属于创建其的一个线程,可以通过Looper.myQuene()来获取当前线程的消息队列。每个Message Quene对应一个Handler,Handler有两种方法给其发送消息:sendMessage和post,都会按照先进先出的方式执行,sendMeesage发送的是一个Message对象,会被Handler的handleMessage()处理;而post发送的是一个 runnable对象,其会自己执行。
(3)Handler:主要处理Message,在后台线程中会传进一个Handler对象,使用其调用sendMessage()方法来发送消息,然后在UI线程中创建一个Handler的匿名子类,重写handleMessage()方法操作发送来的消息。
(4)Looper:可以看做Message Quene中的管家,调用loop()方法可以从消息队列中依次取出消息,Android中会自动为主线程创建Message Quene,但子线程不会。调用Looper.getMainLooper()可获取主线程Looper对象,而调用Looper.myLooper()可能会是一个NULL。
主要流程:简单来说就是使用Handler调用sendMessage()方法来将Message存放在Message Quene中,再使用Looper的loop()方法来取出消息,在handlerMessage()方法中进行处理。他们之间存在这样的一个比例关系,Handler(N):Looper(1):Message Quene(1):Thread(1).

4、说说Activity、Intent、Service之间关系?
答:当应用程序要处理耗时任务比如访问网络等,而这些任务需要放在后台执行,因此可以将其放在服务中处理,但Service是在UI线程中进行的,所以必须开启子线程,然而Intent在这里用来开启服务从而与服务器建立连接。

5、如何保证一个后台服务不被杀死;比较省电的方法是什么?
答:(1)在Service中有一个onStartCommand()方法,其返回一个int类型的值,Android中提供四个常量值,其中的一个START_STICKY值指的是当service被kill后会自动重启并且重新传入Intent对象,恢复为kill前状态。
(2)通过startForeground()方法将进程设置为前台进程,作为前台服务,和Activity一样只有当系统内存不足时才会被kill,可以通过创建Notification对象来建立,然后通过startForeground(id,Notification)方法设置为前台服务。
(3)双进程服务进行互相保护,当一个Service被kill后,使用另一个进行启动。
(4)使用AlarmManager不断启动Service,通过定时来进行启动,还可以通过监听网络状态、开锁屏来控制启动。

由于后面三个方法都需要更多的内存开销,导致系统电量消耗更快,所以第一种方法更省电。
0 0
原创粉丝点击