站长资讯网
最全最丰富的资讯网站

Android开发者面试阿里等大厂遇到的问题整理

推荐:《2020年Android面试题大汇总【收藏】》

先简单说说我这四年期间的面试经历吧。面试的公司很多,其中有让我心血沸腾的经历,也有让我感到失望到无助的经历,我将这些体会都记录下来,细想之后很值得,面了这么多公司,要是最后什么也没有留下来,那就太浪费了。至少对于我来说有些东西在整理总结之后才能得到一个肯定的答案。希望这些能对即将换工作或者打算看看机会的你有一些帮助。

以下问题的答案均是个人四年来多次面试实践中整理的,如有不同意见,欢迎斧正。

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

答案:

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

以下是代码实现

public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private TextView mTextView; 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 != null) {                     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); } }复制代码

参考博文blog.csdn.net/ucxiii/arti…

2.onNewIntent()的调用时机

解析:

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

首先,在默认情况下,当您通过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方法

答案:

前提:ActivityA已经启动过,处于当前应用的Activity堆栈中; 当ActivityA的LaunchMode为SingleTop时,如果ActivityA在栈顶,且现在要再启动ActivityA,这时会调用onNewIntent()方法 当ActivityA的LaunchMode为SingleInstance,SingleTask时,如果已经ActivityA已经在堆栈中,那么此时会调用onNewIntent()方法

当ActivityA的LaunchMode为Standard时,由于每次启动ActivityA都是启动新的实例,和原来启动的没关系,所以不会调用原来ActivityA的onNewIntent方法,仍然调用的是onCreate方法

以下是代码实例

1.设置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>复制代码

2.MainActivity中重写onNewIntent方法

package code.xzy.com.handlerdemo; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; 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...."); } }复制代码

3.Main2Actvity执行点击跳转,MainActivity被复用,执行onNewIntent方法

package code.xzy.com.handlerdemo; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; 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优势在于可以轻松实现:

  1. ListView的功能
  2. GridView的功能
  3. 横向ListView的功能
  4. 横向ScrollView的功能
  5. 瀑布流效果
  6. 便于添加Item增加和移除动画

不过一个挺郁闷的地方就是,系统没有提供ClickListener和LongClickListener。 不过我们也可以自己去添加,只是会多了些代码而已。 实现的方式比较多,你可以通过mRecyclerView.addOnItemTouchListener去监听然后去判断手势,

当然你也可以通过adapter中自己去提供回调

参考

jcodecraeer.com/a/anzhuokai… blog.csdn.net/lmj62356579… www.360doc.com/content/16/…

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的操作

6.HTTPS中SSL证书认证的过程

7.简述Android的Activity的内部机制

8.对Android Framework层的某一个模块(或者System App)做简要介绍

9.Android Handler的机制和原理

主线程使用Handler的过程

首先在主线程创建一个Handler对象 ,并重写handleMessage()方法。然后当在子线程中需要进行更新UI的操作,我们就创建一个Message对象,并通过handler发送这条消息出去。之后这条消息被加入到MessageQueue队列中等待被处理,通过Looper对象会一直尝试从Message Queue中取出待处理的消息,最后分发会Handler的handler Message()方法中。

参考 blog.csdn.net/u012827296/…

10.线程间通信和进程间通信有什么不同,Android开发过程中是怎么实现的

www.cnblogs.com/yangtao1995…

11.简述项目中对于内存优化的几个细节点

答案:

  1. 当查询完数据库之后,及时关闭Cursor对象。
  2. 记得在Activity的onPause方法中调用unregisterReceiver()方法,反注册广播
  3. 避免Content内存泄漏,比如在4.0.1之前的版本上不要讲Drawer对象置为static。当一个Drawable绑定到了View上,实际上这个View对象就会成为这个Drawable的一个callback成员变量,上面的例子中静态的sBackground持有TextView对象lable的引用,而lable只有Activity的引用,而Activity会持有其他
赞(0)
分享到: 更多 (0)