月薪20k+的Android面试都问些什么(含答案)

你们确定急需一套Android面试宝典,今天给你们准备了我珍藏已久的Android高阶面试宝典,供你们学习 !【文末有干货】 java

1、面试题:

1.自定义Handler时如何避免内存泄漏 2.onNewIntent的调用时机 3.RecyclerView相比ListView有哪些优点 4.谈一谈Proguard混淆技术 5.ANR出现的场景及解决方案android

2、详细解析:

1.自定义Handler时如何避免内存泄漏

通常非静态内部类持有外部类的引用的状况下,形成外部类在使用完成后不能被系统回收内存,从而形成内存泄漏。为了不这个问题,咱们能够自定义的Handler声明为静态内部类形式,而后经过弱引用的方式,让Handler持有外部类的引用,从而可避免内存泄漏问题。面试

如下是代码实现数据库

private WeakReference < MainActivity > activityWeakReference;

private MyHandler myHandler;

static class MyHandler extends Handler {

    private MainActivity activity;

    MyHandler(WeakReference < MainActivity > ref) {

        this.activity = ref.get;

    }

    @Override

    public void handleMessage(Message msg) {

        super.handleMessage(msg);

        switch (msg.what) {

        case 1:

            //须要作判空操做
            if (activity != ) {

                activity.mTextView.setText("new Value");

            }

            break;

        default:

            Log.i(TAG, "handleMessage: default ");

            break;

        }

        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

            //在onCreate中初始化
            activityWeakReference = new WeakReference < MainActivity > (this);

            myHandler = new MyHandler(activityWeakReference);

            myHandler.sendEmptyMessage(1);

            mTextView = (TextView) findViewById(R.id.tv_test);

        }
复制代码

2.onNewIntent的调用时机

在Android应用程序开发的时候,从一个Activity启动另外一个Activity并传递一些数据到新的Activity上很是简单,可是当您须要让后台运行的Activity回到前台并传递一些数据可能就会存在一点点小问题。bash

首先,在默认状况下,当您经过Intent启到一个Activity的时候,就算已经存在一个相同的正在运行的Activity,系统都会建立一个新的Activity实例并显示出来。为了避免让Activity实例化屡次,咱们须要经过在AndroidManifest.xml配置activity的加载方式(launchMode)以实现单任务模式,以下所示:网络

<activity android:label="@string/app_name"

android:launchmode="singleTask"android:name="Activity1">

</activity>
复制代码

launchMode为singleTask的时候,经过Intent启到一个Activity,若是系统已经存在一个实例,系统就会将请求发送到这个实例上,但这个时候,系统就不会再调用一般状况下咱们处理请求数据的onCreate方法,而是调用onNewIntent方法app

前提:ActivityA已经启动过,处于当前应用的Activity堆栈中;当ActivityA的LaunchMode为SingleTop时,若是ActivityA在栈顶,且如今要再启动ActivityA,这时会调用onNewIntent方法ide

当ActivityA的LaunchMode为SingleInstance,SingleTask时,若是已经ActivityA已经在堆栈中,那么此时会调用onNewIntent方法学习

当ActivityA的LaunchMode为Standard时,因为每次启动ActivityA都是启动新的实例,和原来启动的不要紧,因此不会调用原来ActivityA的onNewIntent方法,仍然调用的是onCreate方法优化

如下是代码实例

  • 设置MainActivity的启动模式为SingleTask(栈内复用)
<activity

android:name=".MainActivity"

android:launchMode="singleTask">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>
复制代码
  • MainActivity中重写onNewIntent方法
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private Button mButton;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mButton = (Button) findViewById(R.id.forward_btn);

        mButton.setOnClickListener(new View.OnClickListener {

            @Override

            public void onClick(View view) {

                startActivity(new Intent(MainActivity.this, Main2Activity.class));

            }

        });

        @Override

        protected void onNewIntent(Intent intent) {

            Toast.makeText(this, "onnewIntent", Toast.LENGTH_SHORT).show;

            Log.i(TAG, "onNewIntent: i done....");

        }
复制代码
  • Main2Actvity执行点击跳转,MainActivity被复用,执行onNewIntent方法
public class Main2Activity extends AppCompatActivity {

    private Button mButton;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main2);

        mButton = (Button) findViewById(R.id.btn);

        mButton.setOnClickListener(new View.OnClickListener {

            @Override

            public void onClick(View view) {

                startActivity(new Intent(Main2Activity.this, MainActivity.class));

                finish;

            }

        });
复制代码

3.RecyclerView相比ListView有哪些优点

首先须要解释下RecyclerView的这个名字了,从它类名上看,RecyclerView表明的意义是,我只管Recycler View,也就是说RecyclerView只管回收与复用View,其余的你能够本身去设置。能够看出其高度的解耦,给予你充分的定制自由(因此你才能够轻松的经过这个控件实现ListView,GirdView,瀑布流等效果)

其次RecyclerView提供了添加、删除item的动画 效果,并且能够自定义

RecyclerView相比ListView优点在于能够轻松实现:

  • ListView的功能
  • GridView的功能
  • 横向ListView的功能
  • 横向ScrollView的功能
  • 瀑布流效果
  • 便于添加Item增长和移除动画 不过一个挺郁闷的地方就是,系统没有提供ClickListener和LongClickListener。

不过咱们也能够本身去添加,只是会多了些代码而已。

实现的方式比较多,你能够经过mRecyclerView.addOnItemTouchListener去监听而后去判断手势,

固然你也能够经过adapter中本身去提供回调

4.谈一谈Proguard混淆技术

Proguard技术有以下功能:

  • 压缩 --检查并移除代码中无用的类
  • 优化--对字节码的优化,移除无用的字节码
  • 混淆--混淆定义的名称,避免反编译
  • 预监测--在java平台对处理后的代码再次进行检测

代码混淆只在上线时才会用到,debug模式下会关闭,是一种可选的技术。

那么为何要使用代码混淆呢? 由于Java是一种跨平台的解释性开发语言,而java的源代码会被编译成字节码文件,存储在.class文件中,因为跨平台的须要,java的字节码中包含了不少源代码信息,诸如变量名、方法名等等。而且经过这些名称来访问变量和方法,这些变量不少是无心义的,可是又很容易反编译成java源代码,为了防止这种现象,咱们就须要经过proguard来对java的字节码进行混淆,混淆就是对发布的程序进行从新组织和处理,使得处理后的代码与处理前的代码有相同的功能,和不一样的代码展现,即便被反编译也很难读懂代码的含义,哪些混淆过的代码仍能按照以前的逻辑执行获得同样的结果。

可是,某些java类是不能被混淆的,好比实现了序列化的java类是不能被混淆的,不然反序列化时会出问题。

下面这类代码混淆的时候要注意保留,不能混淆。

  • Android系统组件,系统组件有固定的方法被系统调用。
  • 被Android Resource 文件引用到的。名字已经固定,也不能混淆,好比自定义的View 。
  • Android Parcelable ,须要使用android 序列化的。

其余Anroid 官方建议 不混淆的,如

  • android.app.backup.BackupAgentHelper
  • android.preference.Preference
  • com.android.vending.licensing.ILicensingService
  • Java序列化方法,系统序列化须要固定的方法。
  • 枚举 ,系统须要处理枚举的固定方法。
  • 本地方法,不能修改本地方法名
  • annotations 注释
  • 数据库驱动
  • 有些resource 文件

5.ANR出现的场景及解决方案

在Android中,应用的响应性被活动管理器(Activity Manager)和窗口管理器(Window Manager)这两个系统服务所监视。当用户触发了输入事件(如键盘输入,点击按钮等),若是应用5秒内没有响应用户的输入事件,那么,Android会认为该应用无响应,便弹出ANR对话框。而弹出ANR异常,也主要是为了提高用户体验。

解决方案是对于耗时的操做,好比访问网络、访问数据库等操做,须要开辟子线程,在子线程处理耗时的操做,主线程主要实现UI的操做

这些是木木根据上面的高级工程师技术大纲整理的一套系统全面并且很是深刻的Android进阶资料和面试题

下面是部分资料截图

资料免费领取方式:如今关注我而且加入群聊 群号:1018342383 或者是点击连接加入群聊 【Android开发交流】:jq.qq.com/?_wv=1027&a…

相关文章
相关标签/搜索