Android开发面经

如果要你做一个app你的难点是什么?

  • 架构设计
  • UI设计
  • 技术栈选择,使用原生开发还是flutter还是混合开发还是RN。如果考虑性能,优先原生。资源不足并且跨平台flutter。

linearlayout与relativelayout怎么选择?

在RelativeLayout和LinearLayout同时能够满足需求时,尽量使用RelativeLayout,这一点可以从我们MainActivity默认布局就可以看出,默认是RelativeLayout,因为可以通过扁平的RelativeLayout降低LinearLayout嵌套所产生布局树的层级。
Android提供了几种方便的布局管理器,大多数时候,你只需要这些布局的一部分基本特性去实现UI。 一般情况下用LinearLayout的时候总会比RelativeLayout多一个View的层级。而每次往应用里面增加一个View,或者增加一个布局管理器的时候,都会增加运行时对系统的消耗,因此这样就会导致界面初始化、布局、绘制的过程变慢。
同一个布局LinearLayout与RelativeLayout用Hierarchy View查看层级树:
LinearLayout
在这里插入图片描述
RelativeLayout
在这里插入图片描述很明显的可以看出来RelativeLayout比LinearLayout少了一个层级,当然渲染的时间也是大大减少了

讲下布局的优化?

1、善用相对布局RelativeLayout
2、使用抽象布局标签include、merge、ViewStub

  • inclue
    include标签常用于将布局中的公共部分提取出来,比如我们要在activity_main.xml中需要上述LinearLayout的数据,那么就可以直接include进去了。

  • merge
    merge标签是作为include标签的一种辅助扩展来使用,它的主要作用是为了防止在引用布局文件时产生多余的布局嵌套,Android渲染需要消耗时间,布局越复杂,性能就越差。如上述include标签引入了之前的LinearLayout之后导致了界面多了一个层级。这个时候用merge的话,就可以减少一个层级。

  • viewstub
    viewstub是view的子类。他是一个轻量级View, 隐藏的,没有尺寸的View。他可以用来在程序运行时简单的填充布局文件。

3、Android最新的布局方式ConstaintLayout
ConstraintLayout允许你在不适用任何嵌套的情况下创建大型而又复杂的布局。它与RelativeLayout非常相似,所有的view都依赖于兄弟控件和父控件的相对关系。但是,ConstraintLayout比RelativeLayout更加灵活。目前在AndroidStudio中使用也十分方便。

讲下final 类 变量 方法?

final用于控制成员、方法或者是一个类是否可以被重写或者继承等功能。
(1)如果类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。
(2)将变量或者方法声明为final,可以保证他们在使用中不被改变。其初始化可以在两个地方:一是其定义处,也就是说,在final变量定义时直接给其赋值;二是构造函数中。这2个地方只能选其一,要么在定义处直接给其赋值,要么在构造函数中给值,并且在以后的引用中,只能读取,不可修改。被声明为final的方法也同样只能使用,不能重写。

接口和抽象类区别?

1、结构
抽象类中可以有自己的方法实现。也可以有抽象方法。接口只有抽象方法。
抽象类中有自己的成员变量,成员方法。接口只有常量和抽象方法。
抽象类可以用public,protected,private等修饰。接口只能用public修饰。

2、继承方式
子类使用extends关键字继承抽象类。子类可以选择性重写抽象类中需要使用的方法,如果子类没有实现抽象类中所有声明的方法的实现,则子类也是抽象类。
子类使用implements关键字实现接口。子类需要提供接口中所有声明的方法的实现。

3、构造方法
抽象类可以有构造方法,但接口没有构造方法。但抽象类的构造器不用于创造对象,而是让其子类调用这些构造器完成抽象类的初始化操作。

4、多/单继承
一个子类只能继承一个父类,但可以实现多个接口。

5、速度
抽象方法比接口速度快。接口需要时间去寻找在类中实现的方法,故速度较慢。

6、设计
抽象类是对事物的一种抽象,描述的是某一类特性的事物。表示 这个对象是什么。(is-a关系——强调所属关系)
接口是对行为功能的抽象,描述是否具备某种行为特征。表示 这个对象能做什么。(has-a关系——强调功能实现)

activity启动模式?

  • 标准Standard
    每启动一次Activity,就会创建一个新的Activity的实例并将该实例置于栈顶
    (1)每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用,户体验差, 需要点击多次返回才可以把程序退出了。
    (2)每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)
  • 栈顶复用SingleTop
    启动Activity,若创建的Activity位于任务栈栈顶,则Activity的实例不会重建,而是重用栈顶的实例。(调用实例的onNewIntent(),可以通过intent传值,不调用onCreate()和onStart())
    否则就创建该Activity新实例并置于栈顶
  • 栈内复用SingleTask
    1.查看Activity所在的任务栈是否存在,若不存在则重建一个任务栈,创建Activity实例并置于栈顶(可通过TaskAffinity属性指定Activity想要的任务栈)
    这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过taskAffinity属性指定。如果这个任务栈不存在,则会创建这个任务栈。不设置taskAffinity属性的话,默认为应用的包名。
    2.若存在任务栈,则查看该Activity是否存在栈中,若不存在,则创建Activity实例并置于栈顶
    3.若该Activity存在栈中,在将实例上的所有Activity出栈,使该Activity位于栈顶(回调onNewIntent())
  • 单例SingleInstance
    单实例模式,顾名思义,只有一个实例。该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
    创建一个Activity则新建一个任务栈,并将该Activity实例放入新栈。
    一旦该模式的Activity实例已存在某个栈中,任何应用激活该Activity都会重用该栈中的实例并进入该应用中,即 多个应用共享该栈中实例

mainactivity启动了A B C 3个activity,(当前在C界面)按下home键,再点击应用图标启动的是main,这可能是什么原因造成的??

每次启动Intent导致新创建Task的时候,该Task会记录导致其创建的Intent;而如果后续需要有一个新的与创建Intent完全一致(完全一致定位为:启动类,action、category等等全部一样,不可多项也不可缺少),那么该Intent并不会触发Activity的新建启动,而只会将已经存在的对应Task移到前台;这也就是为什么桌面会在再次点击图标时将后台任务挪到前台而不是重新启动App的实现。

但是问题所在的是:他们的启动Intent并没有跟桌面的启动Intent完全一致

这个自定义view需要自定义属性,流程是怎么样的??

(1)onMeasure:对当前View的尺寸进行测量
(2)重写onMeasure
(3)重写onDraw:绘制当前View
(4)自定义布局属性
res/attrs.xml

<!--属性集合名,一般与View名称相同-->
<declare-styleable name="MyCircleView">
    <!--属性名为default_size,取值类型为尺寸类型(dp,px等)-->
    <attr name="default_size" format="dimension"/>
</declare-styleable>

xmlns:app="http://schemas.android.com/apk/res-auto"
<com.sdu.chy.chytest.myView.myViewUtils.MyCircleView
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@color/Orange"
    app:default_size="200dp"/>

public class MyCircleView extends View {
    int defalutSize = 0;
public MyCircleView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    //第二个参数就是我们在styles.xml文件中的<declare-styleable>标签,即属性集合的标签,在R文件中名称为R.styleable+name
    TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.MyCircleView);
    //第一个参数为属性集合里面的属性,R文件名称:R.styleable+属性集合名称+下划线+属性名称
    //第二个参数为,如果没有设置这个属性,则设置的默认的值
    defalutSize = a.getDimensionPixelSize(R.styleable.MyCircleView_default_size, 0);

    //最后记得将TypedArray对象回收
    a.recycle();
}

广播的种类,区别?

a)普通广播(Normal Broadcast)
开发者自身定义 intent的广播(最常用)。
b)系统广播(System Broadcast)
Android中内置了多个系统广播:只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播
c)有序广播(Ordered Broadcast)
发送出去的广播被广播接收者按照先后顺序接收(按照Priority属性值从大-小排序)

  • 无序广播
    context.sendBroadcast(Intent)方法发送的广播,不可被拦截,当然发送的数据,接收者是不能进行修改的。
  • 有序广播
    context.sendOrderBroadcast(Intent)方法发送的广播,可被拦截,而且接收者是可以修改其中要发送的数据,修改和添加都是可以的,这就意味着优先接收者对数据修改之后,下一个接收者接受的数据是上一个接收者已经修改了的。
    d)本地广播(Local Broadcast)
    Android中的广播可以跨App直接通信(exported对于有intent-filter情况下默认值为true),App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。

mvp知道吗…那mvc呢…?

  • 1、Android中MVC是什么?特点?

Model:针对业务模型建立的数据结构和类(与View无关,只与业务相关)
View:XML/JAVA或者JS+HTML进行页面的显示。Activity/Frgament也承担了View的功能。
Controller:Android的控制层通常在Activity、Fragment之中。
本质就是Controller操作Model层的数据,并且将数据返回给View层展示。

  • 2、Android中的MVP模式

MVP(Model-View-Presenter)
Model:主要提供数据的存储功能。Presenter需要通过Model存取数据。
View: 负责处理点击事件和视图展示(Activity、Fragment或者某个View控件)
Presenter: View和Model之间的桥梁,从Model检索数据后返回给View层。使得M/V之间不再有耦合关系。

  • 3、MVP和MVC的区别?(2)

MVP中绝对不允许View直接访问Model
本质是增加了一个接口降低一层耦合度

  • 4、MVVM模式的作用和特点?

Model-View-ViewModel,将Presenter替换为ViewModel。
ViewModel和Model/View进行了双向绑定。
View发生改变时,ViewModel会通知Model进行更新数据
Model数据更新后,ViewModel会通知View更新显示
谷歌发布了MVVM支持库Data Binding:能将数据绑定到xml中
现在谷歌又推出了ViewModel和LiveData组件用于更方便的实现MVVM

面向对象特征,讲下多态和继承?

  • Java多态?
    1、定义
    指允许不同类的对象对同一消息做出响应。
    2、三要素
    (1)继承
    (2)重写
    (3)父类引用指向子类对象
    3、好处
    1.可替换性(substitutability)
    2.可扩充性(extensibility)
    3.接口性(interface-ability)
    4.灵活性(flexibility)
    5.简化性(simplicity)

4、Java中多态实现方式

  • 接口实现
  • 继承父类进行方法重写
  • 同一个类中进行方法重载。

httpurlconnection,关于post方法的步骤?

1、创建一个UrlConnManager类,然后里面提供getHttpURLConnection()方法用于配置默认的参数并返回HttpURLConnection:

public static HttpURLConnection getHttpURLConnection(String url){
     HttpURLConnection mHttpURLConnection=null;
     try {
         URL mUrl=new URL(url);
         mHttpURLConnection=(HttpURLConnection)mUrl.openConnection();
         //设置链接超时时间
         mHttpURLConnection.setConnectTimeout(15000);
         //设置读取超时时间
         mHttpURLConnection.setReadTimeout(15000);
         //设置请求参数
         mHttpURLConnection.setRequestMethod("POST");
         //添加Header
         mHttpURLConnection.setRequestProperty("Connection","Keep-Alive");
         //接收输入流
         mHttpURLConnection.setDoInput(true);
         //传递参数时需要开启
         mHttpURLConnection.setDoOutput(true);
     } catch (IOException e) {
         e.printStackTrace();
     }
     return mHttpURLConnection ;
 }

发送POST请求,所以在UrlConnManager类中再写一个postParams()方法用来组织一下请求参数并将请求参数写入到输出流中

public static void postParams(OutputStream output,List<NameValuePair>paramsList) throws IOException{
      StringBuilder mStringBuilder=new StringBuilder();
      for (NameValuePair pair:paramsList){
          if(!TextUtils.isEmpty(mStringBuilder)){
              mStringBuilder.append("&");
          }
          mStringBuilder.append(URLEncoder.encode(pair.getName(),"UTF-8"));
          mStringBuilder.append("=");
          mStringBuilder.append(URLEncoder.encode(pair.getValue(),"UTF-8"));
      }
      BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(output,"UTF-8"));
      writer.write(mStringBuilder.toString());
      writer.flush();
      writer.close();
  }

接下来我们添加请求参数,调用postParams()方法将请求的参数组织好传给HttpURLConnection的输出流,请求连接并处理返回的结果

private void useHttpUrlConnectionPost(String url) {
     InputStream mInputStream = null;
     HttpURLConnection mHttpURLConnection = UrlConnManager.getHttpURLConnection(url);
     try {
         List<NameValuePair> postParams = new ArrayList<>();
         //要传递的参数
         postParams.add(new BasicNameValuePair("username", "moon"));
         postParams.add(new BasicNameValuePair("password", "123"));
         UrlConnManager.postParams(mHttpURLConnection.getOutputStream(), postParams);
         mHttpURLConnection.connect();
         mInputStream = mHttpURLConnection.getInputStream();
         int code = mHttpURLConnection.getResponseCode();
         String respose = converStreamToString(mInputStream);
         Log.i("wangshu", "请求状态码:" + code + "\n请求结果:\n" + respose);
         mInputStream.close();
     } catch (IOException e) {
         e.printStackTrace();
     }
 }

最后开启线程请求网络

private void useHttpUrlConnectionGetThread() {
       new Thread(new Runnable() {
           @Override
           public void run() {
               useHttpUrlConnectionPost("http://www.baidu.com");
           }
       }).start();
   }

设计模式会哪些,讲下android中的设计模式?

(4.1)创建型
(4.1.1)单例模式(Singleton)
(4.1.2)简单工厂模式(SimpleFactory Pattern)
(4.1.3)工厂方法模式(Factory Method)
(4.1.4)抽象工厂模式(Abastract Factory)
(4.1.5)建造者模式(Builder Pattern)
(4.1.6)原型模式(Prototype Pattern)
(4.2)结构型
(4.2.1)适配器模式(Adapter)
(4.2.2)桥梁模式(Bridge)
(4.2.3)代理模式(Proxy)
(4.2.3.1)静态代理
(4.2.3.2)动态代理
(4.2.4)装饰模式(Decorate)
(4.2.5)外观模式(Facade Pattern)
(4.3)行为型
(4.3.1)模板方法模式(Template Method)
(4.3.2)观察者模式(Observer Pattern)
(4.3.3)状态模式(State Pattern)
(4.3.4)策略模式(Stratege Pattern)
(4.3.5)责任链模式(Chain of Responsibility Pattern)

stringbuffer和stringbuilder区别?

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值