Android面试题

Service 是什么,启动方式区别,生命周期,如何停用

  • Android 的 Service有两个作用,后台或跨进程(AIDL)
  • 两个启动方法,分别是Context.startService()和Context.bindService()。
  • 生命周期根据启动的方式有两条
    • onCreate(), onStart(),onDestroy()。onCreate()在重复启动时不会执行。
    • onCreate(), onBind(),onUnBind(),onDestroy()。只能绑定一次。
      -销毁方法是onDestroy()。
  • 执行耗时操作建议使用Intent Service,自带多线程且自动停止。

BroadcastReceiver是什么,种类,注册方式,生命周期

  • BroadcastReceiver系统或应用活动通知接收
  • 广播分类
    • 普通广播:Context.sendBroadcast(Intent myIntent)
    • 有序广播:Context.sendOrderedBroadcast(intent, receiverPermission)第二个参数为[-1000,1000]的优先级,1000为最高优先等级。
    • 异步广播:Context.sendStickyBroadcast(Intent myIntent),需要权限 <uses-permission android:name="android.permission.BROADCAST_STICKY" />,需要手动去掉removeStickyBroadcast(intent)
    • 有序异步广播:sendStickyOrderedBroadcast(intent, resultReceiver, scheduler, initialCode, initialData, initialExtras)
  • 动态注册,注册后才存在,需手动解除注册;静态(系统)注册,App未启动也存在
  • 生命周期会调方法:void onReceive(Context curContext,Intent broadcastMsg),只有10秒时间,如果超过则报ANR错误。

Broadcast、EventBus和自己实现观察者模式的不同

  • Observable耦合度三者最高
  • Broadcast重量级,消耗资源较多,跨进程传递消息。与SDK链接紧密,许多系统级事件用广播通知:网络变化、电量、短信发送和接受状态
  • EventBus轻量且快速,灵活不依赖Context,使用简单。采用观察者可能会造成接口膨胀
    现在比较流行的开源控件RxJava也是用的观察者模式,可以很方便的使用RxJava实现个RxBus取代EventBus。

ContentProvider

  • ContentProvider使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存储在文件系统中、在一个SQLite数据库、或以任何其他合理的方式。其他应用可以通过ContentResolver类(见ContentProviderAccessApp例子)从该内容提供者中获取或存入数据
  • 通过Uri进行访问。Uri uri = Uri.parse("content://com.bing.provider.personprovider/person")
  • ContentUris类使用
    • Uri uri = Uri.parse("content://com.bing.provider.personprovider/person");
    • Uri resultUri = ContentUris.withAppendedId(uri, 10);
    • //生成后的Uri为:content://com.bing.provider.personprovider/person/10
    • Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person/10")
    • long personid = ContentUris.parseId(uri);
    • //获取的结果为:10

Android系统中GC什么情况下会出现内存泄露呢

导致内存泄露主要的原因是:没有释放申请的内存空间,垃圾回收器GC无法回收内存。如下情况能导致内存溢出:

  1. 数据链接没有关闭。如数据库contentprovider,io,sokect,cursor等
  2. (匿名)内部类对象会持有宿主类的强应用this。如果是new Thread这类操作,线程没有执行结束时当前Activity不会被回收。(常见Handler操作)
  3. Context引用。TextView等等都会持有上下文引用,如果有static drawable,就会导致内存无法释放
  4. 静态集合类。,ashMap,Vector等。如果是静态集合,要及时setnull,否则就会一直持有这些对象
  5. observer 我们在使用监听器的时候,addxxxListener(),记得不用时removexxxListener,否则内存leak
  6. Bitmap对象不使用时,采用recycle()释放内存

Android UI中的View如何刷新

要分清View刷新的情景:多线程和双缓冲。

  • 不使用多线程和双缓冲。View发生改变重绘,使用View.invalidate()激活View.onDraw()方法。
  • 使用多线程和不使用双缓冲。注意非UI线程不能对UI进行直接操作,需要用Handler进行线程通讯,在UI线程对View进行重绘。
  • 使用多线程和双缓冲。SurfaceView直接实现了双缓冲,实现Surfaceholder.Callback接口。Surfaceholder.lockCanvas()锁定画布,Surfaceholder.unlockCanvasandPost()解锁画布。

事件分发机制

Android开发: View - 事件分发

Handler机制,线程通讯

Android提供Handler来满足线程间的通讯。

  • Handler:Message处理和发送。
    • 通过Looper获取MessageQueue中的消息(FIFO)
    • 通过Looper将消息放入MessageQueue
  • Looper:轮询器
    • 每个线程有且只有一个私人的Looper
    • 初始化Looper对象,此对象会拥有一个Message Queue对象
    • 主线程(UI线程)会自动初始化Looper。其他线程需要Looper.prepare()初始化,Looper.loop()开始轮询
  • MessageQueue:消息队列
    • 存放一个线程的Message所有
    • Message被发送给Hander并处理后不会回收或删除,会被标记为闲置状态
    • Handler发送消息是先检索Message Queue中没有没闲置Message,有直接复用,否则新建Message。减少GC回收工作压力,增加内存Leak危险

Handler使用时要特别注意内存Leak:

  1. 要使用 static 静态类定义Handler派生类
  2. static 下访问当前对象的字段属性时需要弱引用(WeakReference)
  3. 在Activity销毁时调用 Handler.removeMessages()将MessageQueue中的消息全部移除
  4. 自定义控件在定义Handler时,尽量使用new Handler(Looper.getMainLooper()), 不要使用new Handler()。因为后者默认在主线程中执行,事实上有些View的创建在子线程中执行。

进程通讯(AIDL等)

  • 访问其他App的Activity:需要App开放支持
  • 内容提供者Content Provider :使用Content Provider提供数据,使用Content Resolver读取数据。
  • 广播Broadcast:被动接受信息
  • AIDL服务:Android Interface Definition Language 安卓接口定义语言
    • AIDL服务提供程序:建立AIDL文件;在文件中创建接口申明方法;注册Service实现声明的接口方法
    • AIDL服务使用程序:copy自动生成的Java文件;建立ServiceConnection对象并绑定AIDL服务;获取AIDL中的接口对象并调用放发获取Value

AIDL步骤(一):提供AIDL服务
在package目录下建立aidl.aidl文件,申明方法,类似接口

package  包名.aidl;  
interface  IMyService  {  
    //为AIDL服务的接口方法,调用AIDL服务的程序需要调用该方法   
    String getValue();
} 

ODT会在gen目录下产生一个IMyService.java文件,此文件ODT自动维护,开发者无需在意。

public  class  MyService extends  Service  {  
    //  IMyService.Stub类是根据IMyService.aidl文件生成的类
    //  该类中包含了接口方法(getValue)   
    public  class  MyServiceImpl extends  IMyService.Stub  {  
        @Override   
        public  String getValue() throws  RemoteException  {  
            return  "从AIDL服务获得的值." ;  
        }  
    }  

    @Override   
    public  IBinder onBind(Intent intent)  {          
        //该方法必须返回MyServiceImpl类的对象实例   
        return  new  MyServiceImpl();  
    }  
}  

manifest配置信息

<!--  注册服务 --> 
<service android:name=".MyService" >  
    <intent-filter>  
        <!--  指定调用AIDL服务的ID  -->  
        <action android:name="net.blogjava.mobile.aidlservice.IMyService"  />  
    </intent-filter>  
</service>  

AIDL步骤(二):使用AIDL服务

public class Main extends Activity implements OnClickListener  {  
private IMyService myService = null;  
    //  创建ServiceConnection对象  
    private ServiceConnection serviceConnection = new ServiceConnection(){  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service){  
            // 获得AIDL服务对象  
            // IMyService.java是AIDL提供工程中自动生成的
            myService = IMyService.Stub.asInterface(service);  
            try  {  
                //  调用AIDL服务对象中的getValue方法
                //  并以对话框中显示该方法的返回值  
                new AlertDialog
                        .Builder(Main.this)
                        .setMessage(myService.getValue())
                        .setPositiveButton("确定", null)  
                        .show();  
            }catch (Exception e)  {  
            }  
        }  

        @Override  
        public void onServiceDisconnected(ComponentName name)  
        {  
        }  
    };  

    @Override  
    public void onClick(View view){  
        //绑定AIDL服务  
        bindService(new Intent("提供程序包名.aidl.IMyService"),  
                serviceConnection, Context.BIND_AUTO_CREATE);  
    }  
}  

如何对 Android 应用进行性能分析

android 性能主要之响应速度 和UI刷新速度。
可以参考博客:Android系统性能调优工具介绍
首先从函数的耗时来说,有一个工具TraceView 这是androidsdk自带的工作,用于测量函数耗时的。
UI布局的分析,可以有2块,一块就是Hierarchy Viewer 可以看到View的布局层次,以及每个View刷新加载的时间。
这样可以很快定位到那块layout & View 耗时最长。
还有就是通过自定义View来减少view的层次。

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

  1. 使用Shared Preferences存储数据,用来存储key-value,pairs格式的数据,它是一个轻量级的键值存储机制,只可以存储基本数据类型。
  2. 使用文件存储数据,通过FileInputStream和FileOutputStream对文件进行操作。在Android中,文件是一个应用程序私有的,一个应用程序无法读写其他应用程序的文件。
  3. 使用SQLite数据库存储数据,Android提供的一个标准数据库,支持SQL语句。
  4. 使用Content Provider存储数据,是所有应用程序之间数据存储和检索的一个桥梁,它的作用就是使得各个应用程序之间实现数据共享。它是一个特殊的存储数据的类型,它提供了一套标准的接口用来获取数据,操作数据。系统也提供了音频、视频、图像和个人信息等几个常用的Content Provider。如果你想公开自己的私有数据,可以创建自己的Content Provider类,或者当你对这些数据拥有控制写入的权限时,将这些数据添加到Content Provider中实现共享。外部访问通过Content Resolver去访问并操作这些被暴露的数据。
  5. 使用网络存储数据

描述一下Intent 和 Intent Filter

  • Intent在Android中被翻译为”意图”,他是三种应用程序基本组件-Activity,Service和broadcast receiver之间相互激活的手段。在调用Intent名称时使用ComponentName也就是类的全名时为显示调用。这种方式一般用于应用程序的内部调用,因为你不一定会知道别人写的类的全名。
  • Intent Filter是指意图过滤,不出现在代码中,而是出现在android Manifest文件中,以<intent-filter>的形式。(有一个例外是broadcast receiver的intent
    filter是使用Context.registerReceiver()来动态设定的,其中intent filter也是在代码中创建的)而一个intent有action,data,category等字段。一个隐式intent为了能够被某个intent filter接收,必须通过3个测试,一个intent为了被某个组件接收,则必须通过它所有的intent filter中的一个。

谈谈对Android NDK的理解。

android NDK是一套工具,允许Android应用开发者嵌入从C、C++源代码编译来的本地机器代码到各自的应用软件包中。
1、 NDK是一系列工具的集合。
NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者帮助时巨大的。
NDK集成了交叉编辑器,并提供了相应的mk文件隔离CPU、平台、API等差异,开发人员只需要简单修改mk文件(指出“那些文件需要编译”、“编译特性要求”等),就可以创建出so。NDK可以自动将so和Java应用一起打包,极大的减轻了开发人员的打包工作。
2、NDK提供了一份稳定、功能有限的API头文件声明。
这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、log库(liblog)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值