Android 部分

  1. 内存优化、OOM 异常的检测以及处理

    • 图片的处理

      • 软引用处理图片

      图片软引用

      简单自己用WeakReference做一个bitmap缓存池,也可以用类似图片加载库写一个通用的bitmap缓存池

      • 图片压缩

      BitmapFactory 在解码图片时,可以带一个Options,有一些比较有用的功能,比如:

      inSampleSize:压缩图片

      inJustDecodeBounds : 获得图片大小

      inPreferredConfig : 图片模式,默认会使用ARGB_8888

    • 数据结构优化

      • ArrayMap、SparseArray 替换HashMap

      ArrayMap及SparseArray是android的系统API,对于key为int的HashMap尽量使用SparceArray替代,大概可以省30%的内存;ArrayMap对内存的节省实际并不明显,10%左右,但是数据量在1000以上时,查找速度可能会变慢。

      • 内存抖动:

      主要原因还是有因为大量小的对象频繁创建,导致内存碎片,从而当需要分配内存时,虽然总体上还是有剩余内存可分配,而由于这些内存不连续,导致无法分配,系统直接就返回OOM了。

      例如 :String频繁拼接

      改进方法:StringBuilder拼接字符串

    • 对象泄漏和对象复用

      • 单例(主要原因还是因为一般情况下单例都是全局的,有时候会引用一些实际生命周期比较短的变量例如 Activity的 Context,导致 Activity 虽然 finish 了却无法释放其占用的内存单例内存泄漏)

      • 静态变量(同样也是因为生命周期比较长,GC 无法回收)

      • Handler内存泄露

        1. 在 Java 中,非静态(匿名)内部类会默认隐性引用外部类对象。而静态内部类不会引用外部类对象
        2. 方式:1) 静态内部类 2) 软引用)
      • 匿名内部类(匿名内部类会引用外部类,导致无法释放,比如各种回调)

      • 资源使用完未关闭(BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap)

      • ListView convertView复用

      • onDraw()避免执行对象的创建

    • 内存检测办法

      利用 LeakCanary 来检查 Android 内存泄漏内存泄漏

      在Application中配置,可以检测 Activity 和 Fragment 等的内存泄漏,在 Logcat 中打印出来。
  2. 布局优化

    • 调优工具:hierarchy viewer、

    • viewstub:默认不会加载,手动 inflate 才会加载出来。viewstub

    • 使用RelativeLayout代替LinearLayout,减少层级.

    • 在不影响层级深度的情况下,使用LinearLayout而不是RelativeLayout。因为RelativeLayout会让子View调用2次。

    • 使用TextView的行间距:lineSpacingExtra. 可以同时设置多行文字,中间用/n 分开

    • 用TextView同时显示图片和文字:drawableleft…

    • 使用Spannable或Html.fromHtml:设置一行文字不同颜色,不同大小

    • 用LinearLayout自带的分割线 :xml 中设置 divider 属性

    • Space控件:设置条目间距。使用过多的margin其实会影响代码的可读性。

    • merge标签

    a. 布局顶结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替。

    b. 某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中。

  3. 自定义控件

    步骤:

    1. 构造函数中:1. 获得控件属性(arr.xml)2. 初始化画笔

    2. 重写onMeasure()设置控件大小 : 不设置的话,wrap_content和 match_parent 都是占满屏幕

      其中有三种模式:

      EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

      AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

      UNSPECIFIED:表示子布局想要多大就多大,很少使用

    3. onLayout()

      1. ViewGroup才有这个方法
      2. 作用:摆放子控件位置
    4. ondraw():画界面

    5. 界面刷新的几个方法

      requestLayout:View重新调用一次layout过程。

      invalidate:View重新调用一次draw过程,不能直接在线程中调用

      postInvalidate():在主线程可以调用,内部实现了 handler

  4. 事件分发传递机制

    Android-三张图搞定Touch事件传递机制

    Android事件分发机制详解:史上最全面、最易懂

    onTouch事件传递

  5. ViewPager + Fragment 的使用,及懒加载的实现

    Android ViewPager + Fragment 懒加载实现 吴小龙

    Fragment 懒加载实战 鸿洋

  6. Handler 异步消息机制以及原理

    异步消息处理机制主要由Message,Handler,MessageQueue和Looper这四部分组成

    1. Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据
    2. Handler是处理者的意思,它主要用于发送和处理消息,发送消息通过Handler的sendMessage()方法,发出的消息最终会被传递到Handler的handleMessage()方法中
    3. MessageQueue是消息队列,用来存放Handler发送的消息,这些消息一直存放在消息队列中等待被处理,每个线程只有一个MessageQueue对象
    4. Looper是专门来从MessageQueue中取出消息的,调用Looper的loop()方法后,就会不断的从消息队列中取出消息传递到Handler的handleMessage()方法中,而每个线程中也只有一个Looper对象
  7. 屏幕适配方案

    最全面、最易懂的Android屏幕适配解决方案

    1. 原因:碎片化严重。

    2. 一些基本单位

      dpi:dot per inch(每英寸像素点数)

      计算方法:

      nexus 5

      1920 * 1080

      4.95inch

      dpi = (1920^2 + 1080^2)开根号/4.95 = 445

      px :像素

      dp、dip,在160dp 下,1dp=1px

      sp 可以根据文字大小首选项进行缩放。(不要奇数,不要小数)

      mdpi 120dpi~160dpi

      hdpi 160dpi~240dpi

      xhdpi 240dpi~320dpi

      xxhdpi 320dpi~480dpi

      xxxhdpi 480dpi~640dpi

    3. 解决方案1:支持屏幕尺寸:

      • 使用 wrap_content、match_parent、weight(weight 的计算公式)

      • 使用相对布局

      • 尺寸限定符 :在 layout和 layout-sw600dp(最小宽度限定符) 下分别设置两个名字相同的布局 缺点:维护两套布局

      • 布局别名:先了解。

      • 屏幕方向限定符:

      res/values-sw600dp-land/layouts.xml:

      res/values-sw600dp-port/layouts.xml:

      • .9图
    4. 解决方案2:使用支持各种屏幕密度

      • 解决屏幕宽度不一致的问题:新建多个 values-480*320(各种分辨率)文件,里面对应 单位对应的 px 值;然后设置默认 values 值,设置对应单位对应 dp 的值,防止个别设备对应不上的现象。
      • 提供备用位图:图片放到不同 drawable文件夹,内存占用不同。
    5. 解决方案3:实施自适应用户界面流程

      • 以后再看
  8. 图片加载的优化

    Android一整套图片解决方案 鸿洋

  9. 数据结构相关知识

  10. ViewPager 无限轮播的实现

思路:

  1. 在第一张图片前和最后一张图片后分别添加一个ImageView
  2. 最前边的ImageView背景设置为最后一张图片,最后一个ImageView背景设置第一张图片。
  3. 当我们判断滑动到最后一个ImageView时则设置ViewPager.setCurrentItem(1),让其自动切换到第一张图片,这样在从最后一页切换到第一页时由于图片是用的同一张图片,所以就会使切换效果显得很流畅自然。
  4. 同理,当滑动到第0个ImageView时用ViewPager.setCurrentItem(length)自动切换到倒数第二张图片,第0个ImageView和倒数第二个ImageView图片相同,这样就使滑动效果显得很自然。
  1. 友盟多渠道打包

    1. 添加对友盟库的依赖
    2. 在Manifest.xml中去声明我们的appkey,以及我们的渠道占位符
    3. 在我们应用的build.gradle中去动态的替换掉我们占位符的value即可
    4. 控制台./gradlew assemableRelease自动打包
  2. Listener写法

    • 写一个接口OnClickListener,包含需要回调的方法。

      例如:onClick(View view , int position)

    • 被监听的类 B

      1. 提供外部方法 setOnClickListener(OnClickListener listener)

      OnClickListener是接口,负责回调数据到主动监听的 Class

      1. 新增本地变量mListener,接受1中传递过来的 listener

      mListener = listener

      1. 逻辑处理完直接调用接口中的方法,传入参数执行回调。

      例如:mListener.onClick(view , position)

    • 监听类 A

      new B().setOnClickListener( -v {
      @Override
      public void onClick(View view , int position){这样就拿到了回调的数据
      }
      });
  3. Layout_weight计算

    计算方法:计算出的宽度= 原来宽度+剩余空间所占百分比的宽度

    现在有一个屏幕宽度是480dp,三个 TextView 分别如下。

    textview1:

    width = match_parent
    height = 48d
    weight = 1

    textview2:

    width = match_parent
    height = 48dp
    weight = 2

    textview3:

    width = match_parent
    height = 48dp
    weight = 2

    首先计算剩余空间是:rest = 480 - 480 * 3 = -480 * 2

    最后计算的比例如下所示。

    • textview1:480 + (-480 * 2)(1/5) = 480 3/5
    • textview2:480 + (-480 * 2)(2/5) = 480 1/5
    • textview2:480 + (-480 * 2)(2/5) = 480 1/5
  4. 支付宝

    1. 申请账户,返回四个值。分别是:
    • 私钥(私钥不要放到代码中
    • 公钥
    • AppID
    • 商户支付宝账号
    1. 发待支付的订单信息给服务器,让服务器签名(服务器拿着私钥)
    2. 服务端返回签名信息
    3. 开启子线程
    Runnable payRunnable = new Runnable() {@Overridepublic void run() {// 构造PayTask 对象PayTask alipay = new PayTask(MainActivity.this);// 调用支付接口,获取支付结果String result = alipay.pay(payInfo, true);Message msg = new Message();msg.what = SDK_PAY_FLAG;msg.obj = result;mHandler.sendMessage(msg);}};
    1. 在handler中接受支付的回掉信息
       private Handler mHandler = new Handler() {@SuppressWarnings("unused")public void handleMessage(Message msg) {switch (msg.what) {case SDK_PAY_FLAG: {PayResult payResult = new PayResult((String) msg.obj);/*** 同步返回的结果必须放置到服务端进行验证(验证的规则请看https://doc.open.alipay.com/doc2/* detail.htm?spm=0.0.0.0.xdvAU6&treeId=59&articleId=103665&* docType=1) 建议商户依赖异步通知*/String resultInfo = payResult.getResult();// 同步返回需要验证的信息String resultStatus = payResult.getResultStatus();// 判断resultStatus 为“9000”则代表支付成功,具体状态码代表含义可参考接口文档if (TextUtils.equals(resultStatus, "9000")) {Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_SHORT).show();} else {// 判断resultStatus 为非"9000"则代表可能支付失败// "8000"代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)if (TextUtils.equals(resultStatus, "8000")) {Toast.makeText(MainActivity.this, "支付结果确认中", Toast.LENGTH_SHORT).show();} else {// 其他值就可以判断为支付失败,包括用户主动取消支付,或者系统返回的错误Toast.makeText(MainActivity.this, "支付失败", Toast.LENGTH_SHORT).show();}}break;}default:break;}}};
  5. 微信支付

    [android微信支付详解与坑](http://blog.csdn.net/hello_1s/article/details/52636447)

    1. 申请微信支付,得到三个参数

      //appid 微信分配的公众账号ID
      public static final String APP_ID = "";//商户号 微信分配的公众账号IDpublic static final String MCH_ID = "";//  API密钥,在商户平台设置public static final  String API_KEY= "";(放在后端)
      1. 发待支付的订单信息给服务器,让服务器生成预订单
      2. 服务器再次签名,返回json格式的结果
      PayReq payReq = new PayReq();
      payReq.appId = weiXinPay.getAppid();
      payReq.partnerId = weiXinPay.getPartnerid();
      payReq.prepayId = weiXinPay.getPrepayid();
      payReq.packageValue = weiXinPay.getPackage_exten();
      payReq.nonceStr = weiXinPay.getNoncestr();
      payReq.timeStamp = weiXinPay.getTimestamp();
      payReq.sign = weiXinPay.getSign();
      1. 在Activity中定义一个全局的变量:

        private IWXAPI api = api = WXAPIFactory.createWXAPI(this, "你在微信开放平台创建的app的APPID");
      2. 调取微信支付

        api.sendReq(payReq);
      3. 创建一个activity

        路径为:com.xxx.xxx.wxapi.WXPayEntryActivity implements IWXAPIEventHandler
      4. 回掉支付结果的消息

        public void onResp(BaseResp baseResp) {Log.e("---------->","code:"+baseResp.errCode);if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {//这里就是支付完成后需要做的事,如跳到哪个页面啥的}}
  6. 百度地图的LBS搜索

  7. Bugly检测错误

    • bugly能够检测的类型:常见的错误,空指针,数组越界(最好别说,太low)OOM(对照着内存泄漏来说),ANR(遇到过由于网络请求的Retrofit创建太多而导致ANR异常,后来将Retrofit改为单例模式即可)
  8. 设计模式部分

    1. 项目中运用到那些模式:有点水平的那种:Retrofit的单例模式
    public class AppRetrofit {//valatile关键字Retrofit每次都从内存中取而不是从缓冲中取,保证唯一不变性private  volatile static Retrofit retrofit ;private AppRetrofit(){}public static <T> T getNewsRetrofit(Class<T> clazz, String baseUrl) {if (TextUtils.isEmpty(baseUrl)) {throw new IllegalArgumentException("BaseUrl cannot be null");}
    ///*** 判断是否需要缓存数据,默认为false,可以用单利在每次请求之前设置值*/if (true){if (retrofit == null){synchronized (AppRetrofit.class){if (retrofit == null)retrofit = new Retrofit.Builder().baseUrl(baseUrl) //刚刚添加进来的请求头.client(getCacheOkHttpClient(App.getApplication()))  //使用缓存,Interceptor截获每次网络请求用于缓存数据.addCallAdapterFactory(RxJavaCallAdapterFactory.create())  //添加Rxjava//添加Gson解析.addConverterFactory(GsonConverterFactory.create()).build();}}}else{Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).client(getOKHttpClient()).addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加Gson解析.addConverterFactory(GsonConverterFactory.create()).build();}return retrofit.create(clazz);}
    }
    1. Retrofit的动态代理模式(上面有)
    2. Rxjava的适配器模式(上面也有)
  9. 属性动画

    1. 概述

    Android提供了几种动画类型:View Animation 、Drawable Animation 、Property Animation 。View Animation相当简单,不过只能支持简单的缩放、平移、旋转、透明度基本的动画,且有一定的局限性。比如:你希望View有一个颜色的切换动画;你希望可以使用3D旋转动画;你希望当动画停止时,View的位置就是当前的位置;这些View Animation都无法做到。这就是Property Animation产生的原因。

    1. API 使用介绍

      • ObjectAnimator直接设置 –效率低
      ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(mImageView, "translationX", 0f,100f);//参数分别为要改变的对象。要改变的参数(只要改对象有对应的set,就可以填相应的名字),从多少到多少
      ObjectAnimator.ofFloat(mImageView, "translationY", 0f,100f)//如果同时有两个动画,则会同时进行。
      objectAnimator.start();//开始播放动画
      • propertyValuesHolder,效率相比方法一高
      PropertyValuesHolder p1=PropertyValuesHolder.ofFloat("translationX", 0f,100f);//
      PropertyValuesHolder p2=PropertyValuesHolder.ofFloat("translationY", 0f,100f);
      ObjectAnimator.ofPropertyValuesHolder(mImageView, p1,p2).start();//将设置好的参数,赋给ObjectAnimator
      • AnimatorSet
      ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(mImageView, "translationX", 0f,100f);
      ObjectAnimator objectAnimator2=ObjectAnimator.ofFloat(mImageView, "translationY", 0f,100f);
      ObjectAnimator objectAnimator3=ObjectAnimator.ofFloat(mImageView, "rotation", 0f,360f);
      AnimatorSet animatorSet=new AnimatorSet();
      //animatorSet.playTogether(objectAnimator,objectAnimator2); //设置两个动画一起播放
      //animatorSet.playSequentially(objectAnimator,objectAnimator2); //设置两个动画连续播放,即先播放第一个然后播放第二个
      //上面两者不能同时出现,否则抛出异常。
      animatorSet.play(objectAnimator).with(objectAnimator2);//表示这两个动画同时进行。
      animatorSet.play(objectAnimator3).after(objectAnimator2);//表示这个动画在哪个动画播放结束后进行。
      animatorSet.start(); //动画开始播放Java 部分
  10. Service 详解

    Android Service完全解析,关于服务你所需知道的一切

    1. 基本用法:

      Intent startIntent = new Intent(this, MyService.class);
      startService(startIntent);  //开启服务
      stopService(startIntent);  //关闭服务

      这时候 service 中依次执行:

      onCreate()//只在打开服务时走一次这个方法
      onStartCommand()

      缺点:Activity和Service没什么关联。

    2. Service和Activity通信

      Activity 通知 Service 可以用 Binder调取 Service 里面的方法;

      Service 可以用发送广播通知 Activity 更新界面(当然这里也可以使用LocalBroadcastManager ?暂时不了解)。

      新建一个MyService.class

      public class MyService extends Service {  public static final String TAG = "MyService";  private MyBinder mBinder = new MyBinder();  //...省略一些方法@Override  public IBinder onBind(Intent intent) {  return mBinder;  }  class MyBinder extends Binder {  public void startDownload() {  //自定义方法名称Log.d("TAG", "startDownload() executed");  // 执行具体的下载任务  }  }  }  

      Activity 中:

      public class MainActivity extends Activity implements OnClickListener {  private Button startService;  private Button stopService;  private Button bindService;  private Button unbindService;  private MyService.MyBinder myBinder;  private ServiceConnection connection = new ServiceConnection() {  @Override  public void onServiceDisconnected(ComponentName name) {  }  @Override  public void onServiceConnected(ComponentName name, IBinder service) {  myBinder = (MyService.MyBinder) service;  myBinder.startDownload(); //可以调用 service 中的方法 }  };  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  //...省略 findId 和 click}  @Override  public void onClick(View v) {  switch (v.getId()) {  case R.id.bind_service:  Intent bindIntent = new Intent(this, MyService.class);  bindService(bindIntent, connection, BIND_AUTO_CREATE);  break;  case R.id.unbind_service:  unbindService(connection);  break;  default:  break;  }  }  }  

      备注:

      ​ service 运行在主线程,不能耗时太长,除非开启子线程。

      用startService打开的服务必须用stopService才能停止;

      用bindService打开的服务必须用unbindService才能停止;

      先用startService后用bindService必须先stopService再unbindService才能停止服务。

  11. AIDL

    1. 定义:

      AIDL(Android Interface Definition Language)是Android接口定义语言的意思,

      它可以用于让某个Service多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。

    2. 使用步骤:

      1. 新建MyAIDLService.aidl文件,代码如下所示:
      package com.example.servicetest;
      interface MyAIDLService {  int plus(int a, int b);  String toUpperCase(String str);
      } 
      1. 新建MyService.class (在该类中把方法实现好)
      public class MyService extends Service {
      /*这里先是对MyAIDLService.Stub进行了实现,重写里了toUpperCase()和plus()这两个方法。这两个方法的作用分别是将一个字符串全部转换成大写格式,以及将两个传入的整数进行相加。然后在onBind()方法中将MyAIDLService.Stub的实现返回。这里为什么可以这样写呢?因为Stub其实就是Binder的子类,所以在onBind()方法中可以直接返回Stub的实现。*/......  @Override  public IBinder onBind(Intent intent) {  return mBinder;  }  MyAIDLService.Stub mBinder = new Stub() {  @Override  public String toUpperCase(String str) throws RemoteException {  if (str != null) {  return str.toUpperCase();  }  return null;  }  @Override  public int plus(int a, int b) throws RemoteException {  return a + b;  }  };  }  
      1. 修改AndroidManifest.xml中的代码,给MyService加上一个action
      <service  android:name="com.example.servicetest.MyService"  android:process=":remote" >  <intent-filter>  <action android:name="com.example.servicetest.MyAIDLService"/>  </intent-filter>  </service>  
      1. 拷贝MyAIDLService.aidl文件到Client端

        注意:要将原有的包路径一起拷贝过来

      2. 打开或新建MainActivity,在其中加入和MyService建立关联的代码

      public class MainActivity extends Activity {  private MyAIDLService myAIDLService;  private ServiceConnection connection = new ServiceConnection() {  @Override  public void onServiceDisconnected(ComponentName name) {  }  @Override  public void onServiceConnected(ComponentName name, IBinder service) {  myAIDLService = MyAIDLService.Stub.asInterface(service);  try {  int result = myAIDLService.plus(50, 50);  String upperStr = myAIDLService.toUpperCase("comes from ClientTest");  Log.d("TAG", "result is " + result);  Log.d("TAG", "upperStr is " + upperStr);  } catch (RemoteException e) {  e.printStackTrace();  }  }  };  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  Button bindService = (Button) findViewById(R.id.bind_service);  bindService.setOnClickListener(new OnClickListener() {  @Override  public void onClick(View v) {  Intent intent = new Intent("com.example.servicetest.MyAIDLService");  //隐式调用bindService(intent, connection, BIND_AUTO_CREATE);  }  });  }  }  
  12. IntentService

    1. 介绍:

      • IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作
      • 当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。
      • 可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
    2. 如何使用

      1. 新建 BroIntentService.class
      public class BroIntentService extends IntentService {  @Override  protected void onHandleIntent(Intent intent) {  //Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务  String action = intent.getExtras().getString("param");  if (action.equals("oper1")) {  System.out.println("Operation1");  }else if (action.equals("oper2")) {  System.out.println("Operation2");  }  try {  Thread.sleep(2000);  } catch (InterruptedException e) {  e.printStackTrace();  }  }   } 
      1. 在 Activity 中开启服务

        public class TestActivity extends Activity {  @Override  public void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.main);    //可以启动多次,每启动一次,就会新建一个work thread,但IntentService的实例始终只有一个  Intent startServiceIntent = new Intent("com.test.intentservice");  Bundle bundle = new Bundle();  bundle.putString("param", "oper1");  startServiceIntent.putExtras(bundle);  startService(startServiceIntent);
        }  
    3. 清单文件里注册 Service

    备注:多次开启服务依次执行的方法为:

    onCreate

    onStartCommand

    onStart

    onStartCommand

    onStart

    onDestory (运行完自动结束)

  13. Broadcast

    Android中的广播Broadcast详解

    1. 分类

      • 普通广播

        优点:普通广播是完全异步的,可以在同一时刻(逻辑上)被所有广播接收者接收到,消息传递的效率比较高

        缺点:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播

        Context.sendBroadcast()

      • 有序广播

        有序广播是按照接收者声明的优先级别依次发送。被接收者依次接收广播。

        如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。

        对于有序广播,前面的接收者可以将处理结果存放进广播Intent,然后传给下一个接收者。

        Context.sendOrderedBroadcast()

  14. LocalBroadcastManager(源码简单,待研究)

    Android LocalBroadcastManager的使用

    1. 简介

      不涉及进程间通讯,不用担心普通广播可能产生的一些安全性问题。

      一句话总结LocalBroadcastManager:披着广播外衣的Handler

    2. 使用方法

      LocalBroadcastManager和普通的广播是一模一样,不同的LocalBroadCastManager的调用方不再是context,而是LocalBroadCastManager的实例。

      public class Test extends Activity {private static final String ACTION = "simple_action";private static final String DATA = "data";BroadcastReceiver mReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 新建一个receivermReceiver = new MyReceiver();// 注册receiverLocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(ACTION));// 发送消息Intent messageIntent = new Intent(ACTION);messageIntent.putExtra(DATA, "给xxx的一封信");LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);}@Overrideprotected void onDestroy() {// 取消注册LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);}class MyReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// 处理消息Log.i("TAG", "收到一封信:" + intent.getStringExtra(DATA));}}
      }
  15. SQLite

    Android SQLite数据库使用 学习与代码实践

    介绍两个类

    1. SQLiteOpenHelper 类

      DBHelper继承了SQLiteOpenHelper,作为维护和管理数据库的基类

    2. DBManager 类 (Dao)

      DBManager是建立在DBHelper之上,封装了常用的增删改查业务方法

    具体介绍这两个类

    1. SQLiteOpenHelper 类

      • SQLiteOpenHelper 类中的 getWritableDatabase()getReadableDatabase()方法可以获得数据库的引用。
      • 为了实现对数据库版本进行管理,SQLiteOpenHelper 类提供了两个重要的方法,分别是 onCreate()**onUpgrade(),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。
      • 当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法。
      • onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。
      • onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的。
      • 假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2,并且在onUpgrade()方法里面实现表结构的更新。
      • 当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后做出相应的表结构及数据更新。
    2. SQLiteDatabase类

      • Android提供了一个名为 SQLiteDatabase的类(SQLiteOpenHelper 类中的getWritableDatabase()getReadableDatabase()方法返回这个类的对象)。
      • SQLiteDatabase类封装了一些操作数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)操作(这些操作简称为CRUD)。
      • SQLiteDatabase的学习,应该重点掌握execSQL()和rawQuery()方法。
      • execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句;
      • rawQuery()方法用于执行select语句。

Java 部分

Java 设计模式

  1. Retrofit:动态代理模式

    动态代理

  2. RxJava:适配器模式

    • Retorfit默认的DefaultCallAdapterFactory与Rxjava的适配器模式
      Rxjava适配器模式
  3. MVP

    登陆的 demo 步骤如下:

    1. MainActivity 继承 LoginViewInterface

      LoginViewInterface 包含 getView 和 setView 方法

    2. LoginPresentImp 继承 LoginPresentInterface(包含登陆、注册方法)

      LoginPresentInterface中包含 Login()、resister() 等方法

    3. MainActivity中初始化:LoginPresentInterface mPresenter = new LoginPresentImp(this);

      this 传递的是 LoginViewInterface 的实例

    4. MainActivity 点击登陆按钮的时候调用 mPresenter.Login()

      调用的是 LoginPresentImp 的 Login 方法

    5. LoginPresentImp 的 Login 方法中拿着LoginViewInterface的实例给 activity 往来通信

数据结构部分

  1. 概念及分类:

其他

  1. 每个人都需要的中文排版指南 作者:stormzhang
  2. Android 技能树 By 网易云主程

Android 开发 17 年 5 月份面试问题总结(二)相关推荐

  1. Android开发本地及网络Mp3音乐播放器(二十)歌曲下载完成后通知主界面更新本地音乐

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51448597 项目源码(打赏5积分请点这边):http://download.csdn ...

  2. Android开发——RecyclerView特性以及基本使用方法(二)

    0.  前言 随着Android的发展,虽然ListView依旧重要,但RecyclerView确实越来越多的被大家使用.但显然并不能说RecyclerView就一定优于ListView,而是应该根据 ...

  3. Android开发之属于你的短信验证码(二)

    君子欲讷于言而敏于行.-<论语> 最近身体有点不适,才注意到身体真的是最重要的,以后不管我们有多忙,一定要按时休息,坚持跑步,锻炼身体,做些颈椎的操等等,不要让我们挣的钱拿来看病,大家一起 ...

  4. 三年经验Android开发,2个月面试腾讯、B站,你花了多久弄明白架构设计

    8.Activity启动模式,以及各启动模式生命周期问题 9.静态方法,静态对象为什么不能继承 10.Activity怎么启动Service,Activity与Service交互,Service与Th ...

  5. Android开发两年,跳槽面试小公司面试官说我可以试试大厂---,Android小程序开发实例

    开源库用过哪些 自己平时写项目学习,基本都用过,原理也了解:重构项目的资讯模块用了Retrofit & RxJava,自己思考优化了代码框架,比如线程切换.页面查找等,其实弄清楚原理,要改哪里 ...

  6. Android开发3年,九月份面试12家大厂跳槽成功,我有一些面试经验想分享给你们

    这里推荐一下极客时间上覃超的五遍刷题法: 五遍刷题法 1.第一遍,直接看解法 多解法,比较解法优劣,默写好的解法 2.第二遍,打开leetcode,直接开始写 多种解法比较,调优 3.第三遍,过一天之 ...

  7. 【金九银十】Android开发真等于废人?面试必问

    面试如作战,我们看战争影视剧的时候,经常看到这些剧作往往主要聚焦于作战过程.战场战略,对战前准备给的篇幅往往很少.实际上,战前准备也是关键的一环,没有充足的粮草.车马.兵器的准备.别说赢得战争,投入战 ...

  8. Android开发两年,跳槽面试小公司面试官说我可以试试大厂

    不过还是打算跳槽了,薪资和无法推动项目是个大问题,总不能鱼渔都不得吧.我是抱着找不到好的,就北上的心态找的. 做股票期货的,经验类似,面试太过顺利- Activity的启动模式 Activity和Fr ...

  9. Android开发越来越式微了吗?,flutter二维码扫描第三方

    因为开发一个普通应用的难度下降了,门槛降低和资本冷却以后,把握数据和业务逻辑的开发开始成为新的门槛和香饽饽,所以最直观的就是文章和技术分享的趋势变了. 一部分从 Java Web 到 Android ...

最新文章

  1. How good software makes us stupid?
  2. springmvc常见问题汇总
  3. 工业机器人专项检测技术——环境检测
  4. Git 技术篇 - Github在项目分支里下载某个文件方法,Github项目里的单个js文件下载实例演示
  5. linux合并vi的两个文件,两个文件的对比查看及合并工具:vimdiff-文件合并
  6. [Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)
  7. 20190408 Java中的Double类型计算
  8. zblog php 标题优化,Zblog分类页标题重复的优化 - 张力博客
  9. python画彩虹爱心_用python画一颗彩虹色爱心送给女朋友!!!
  10. java控制台高级_K9s Kubernetes的高级控制台
  11. [BZOJ3456]城市规划
  12. 【操作系统/OS笔记09】线程、线程的实现、上下文切换、进程控制
  13. mid制作乐谱_乐谱编辑(在线简谱制作软件)
  14. java编写的视频网站实例_一个在线视频网站的java web 后端开发
  15. java uml Rose_Rational Rose与UML教程
  16. 中国城市网约车监管之政策走向与发展前景
  17. 三阶魔方快速还原法还原方法
  18. googletest 学习笔记
  19. 我是如何用一行代码表白学妹~❤520情人节送女朋友的3D樱花雨相册礼物❤~(程序员表白专属)...
  20. 【猪八戒】- 2017年在线笔试“叠字问题”

热门文章

  1. 罗辑思维--得到App--一面
  2. Sentienl学习笔记
  3. Python x OpenCV+Numpy 函数参考列表
  4. JavaScript函数(看这个就可以了)
  5. 利用树莓派,实现迅雷24小时远程下载
  6. Numpy与矩阵的相似对角化(Python与高等代数03)
  7. 坑 -- h5获取用户当前定位
  8. IC设计中XilinxIP核申请与使用教程
  9. OpenMV入门(下)
  10. 【VUE】web高德地图海量点标记,全部居中显示在屏幕中