Android面试复习

面试背诵

1 http加密传输
我们都知道,一般 的软件都存在登录模块,当我们用http进行登录的时候,如果不进行处理,则会被别人抓取大数据,怎么办呢,数据加密。
文章链接
数据加密一般分为对称加密和非对称加密。
对称加密的加密和解密秘钥相同,优点是算法简单,加密速度快,例如aes。
非对称加密,分为公钥和秘钥,例如des。
现在的问题在于,如果使用aes加密,就必须把aes的秘钥传输给服务器端,这时候就会产生风险。
而des加密,公私钥分别存储在客户端与服务器端,不存在这个问题,但是其解密速度比较缓慢,因此不适合大型文件的加密。
于是两者可以配合使用:
请求:
1. 服务器端(server)和客户端(client)分别生成自己的密钥对
2. server和client分别交换自己的公钥
3. client生成AES密钥(aesKey)
4. client使用自己的RSA私钥(privateKey)对请求明文数据(params)进行数字签名
5. 将签名加入到请求参数中,然后转换为json格式
6. client使用aesKey对json数据进行加密得到密文(data)
7. client使用sever的RSA公钥对aesKey进行加密(encryptkey)
8. 分别将data和encryptkey作为参数传输给服务器端
服务器端进行请求响应时将上面流程反过来即可。

这时候还有一个问题,我们的秘钥怎么进行保存呢?
如果是以字符传递形式,那么还是不安全的。
那么我们可以用c或者c++写jni接口,然后打包成so库,这样反编译的时候就困难了。
2 socket长连接
socket通讯可以包括udp,tcp。tcp是可靠的,可以保证数据的完整性,udp是不可靠的,数据的传输可能丢失。
长链接:socket 当客户端和服务链接之后就可以相互通讯
短连接:http 通讯双方在需要交互的时候建立一个链接,发送完毕之后就断开链接

1: String message=”Hello Android!”;

2: int server_port = 12345;

3: DatagramSocket s = new DatagramSocket();

4: InetAddress local = InetAddress.getByName(“192.168.1.102”);

5: int msg_length=message.length();

6: byte[] message = message.getBytes();

7: DatagramPacket p = new DatagramPacket(message, msg_length,local,server_port);

8: s.send(p);

从变量名中应该非常容易理解这个代码片段。

然后是服务端的代码:

1: String text;

2: int server_port = 12345;

3: byte[] message = new byte[1500];

4: DatagramPacket p = new DatagramPacket(message, message.length);

5: DatagramSocket s = new DatagramSocket(server_port);

6: s.receive(p);

7: text = new String(message, 0, p.getLength());

8: Log.d(“Udp tutorial”,”message:” + text);

9: s.close();

必须要设置输入报文的最大值:

1: byte[] message = new byte[1500];

服务器端:
Serversocket sersocket =newServersocker2141();
BufferedReader reader=null;
Socket socket=sersocket.accept();
reader=new BufferReader(new InputSteram(socket.getInputStream));
客户端:
Socket socket=new Socket();
BufferedWriter writer;
writer=new BuffeedWriter(new outputstream(socket.getoutputstream());
为了能够使客户端随时接受服务器发过来的消息,则需要开启一个线程,监听bufferedreader是否有内容,如果有,则获取到;
同时我们要学会使用mina这个框架
3 数据库
随着软件版本的升级,原有的数据库结构可能已经不能使用新功能。如果数据库没有进行相应的处理,新版本在读取数据的时候就产生问题
sqlite提供了alter table命令,运行用户重命名或者添加字段到表里,但是却不能删除字段:
alert table mytable add column newcolumn
如果在升级过程中,表的数据结构发生了变化,并且还要进行数据的转移:
v1:t_user(username, password);

v2: t_user(username, password), t_region(region, code);

v3: t_user(username, password), t_region(region, code, country);

可以看出,第一次升级增加了一张表,而第二次升级修改了表的定义。
1 将表明改为临时表
alter table t-region rename to t-regionlinshi
2 创建新表
create table t-regtion();
3 导入数据
insert into t-region select region ,code,”” from t-regionlinshi
4 删除临时表
drop table t-regionlishi
跨越版本的升级:
假如说应用程序发布了很多版本,以至于出现多个数据库版本,那么如何指定升级策略呢?
1.确定相邻版本的区别,从版本1一次更新
2确定每个版本与数据库的差别,为每个版本写不同的升级策略。
方式一,每次更新数据库,只需要在onupgrade编写,当前版本和最新版本升级的代码,易于理解和维护,缺点是,当版本过多,多次迭代需要很多的时间
方法二,能保证每个版本的更新都可以在最短的时间内进行升级,缺点是每次升级,onupgrade方法都要重写。
参考地址
## Android设计模式 ##
1 mvc
activity fragment 相当于c 布局相当于v,数据逻辑是m
随着业务的增长,controller的代码越来越臃肿它不仅仅要控制业务逻辑,还要控制view的展示、使得app的耦合性变大
2 mvp
数据逻辑相当于 m,activity相当于v,负责view的绘制与展示,view和model之间的交互是p。
最明显的却别在于,mvc允许model和view进行交互,而mvp中,model和view的交互需要通过presenter完成。还有就是presenter与view 之间交互通过接口
3 mvvm
看起来mvvm跟mvp很是相似。viewmodel起到了presenter的职责,但是与mvp不同的是,vm与v的交互通过datebing。
而p持有的是view的对象。
4通过代码的比较,mvp模式下代码量有明显的增加,但是逻辑更加的清晰,mvp模式不适合小型的项目,如果是大型的项目倒是可以考虑
## Android性能的优化 ##
1. UI
Ui的绘制流畅是onmeasur onlayout draw ,如果子控件过多,绘制的过程将比较缓慢。对于listview,gridview,要注意复用item,通过settag实现viewholder的复用。
对于viewpager,同时缓存的最小值为3,如果过多,将会出现卡顿现象。
对于图片的加载,如果网络过慢或者图片过大,这样会出现长时间不能加载出来的现象,因此设置不同分辨率的图片是很有必要的。
2. 数据缓存
但我们在进行数据展示的时候。如果数据是重复的,那么这样的请求将没有意义,这时候我们就可以设置一个最大请求间隔。第一次请求 的数据放在本地的数据库中,如果在数据有效时间内,再次请求的时候就获取数据库文件,否则请求网络。
3. 防止oom
图片过大oom
使用insamplesize 改变图片尺寸,选择解码方式
对图片就行及时的回收
使用专业的图片加载框架
数据库查询的时候游标及时的关闭
数据流及时close
还有就是对象不能及时的回收,生命周期长的对象持有生命周期短对象的引用
切换横竖屏的oom
当我们切换横竖屏的时候,会重新加载生命周期。如果我们activity里面有一个thread没有执行完毕,并且引用了activity,那么activity就没有销毁
AsyncTask的问题更严重,其内部使用的是线程池机制,产生的生命周期是不确定的,应用程序无法控制。
线程改进的方法
1,将线程的内部类改为静态内部类,因为非静态内部类持有器外部类的引用
2,在程序中尽量采用若引用保存context

4.正确的注册和注销监听器

thread asynctask 线程池

什么是线程池呢

我们知道,在执行耗时的操作,我们就会开启一个线程。如果还有其它的任务,我们再次开启一个线程。涉及与主线程的交互,我们将会使用handler。
但是问题在于,如果开启大量的线程:
1 每个线程的创建与销毁的资源开销都是很大的
2 子线程会占用系统资源,从而降低apk的性能
那么这时候threadpool就是这么一个管理线程工具,这样就可以同意调度线程。
这时候,忽然想到线程的关闭,一种说法是设置一个标志位,当为false是停止。另外一种呢,就是加入线程池。
线程池中,有两个方法用于线程池的关闭
第一种,shutdown,不会立即终止,而是等缓存队列中的任务执行完毕才终止,不过不会接受新的任务
第二种,shutdownow,立即终止,并尝试打断执行的任务,清空队列。

那么thread 与asnctask的优缺点
异步任务是thread的封装,onbackground中访问网络,在onpostexeute里面更新ui
缺点在于,asynctask内部是一个线程池,在同一时间只能允许五个线程运行,更多的话就会被阻塞,并且最多是128个,否则会报错。

Android的常用设计模式

  1. 单例模式
    单例模式保证一个类只有一个访问实例,同时这个类提供一个全局的访问点。因此,当我们创建一个对象需要消耗过多的资源时,便可以考虑这个模式
public class DanLi {

private static DanLi demo=null;
private DanLi()
{
    }
public static DanLi getNewInstance(){
    if (demo==null) {
        demo=new DanLi();
    }
    return demo;
}
}
  1. bulider模式
    可以将复杂对象的创建过程抽象出来,然后用不同的方法构造不同的对象。

public class Dialog {
public Dialog(Context context){

}
public class Bulider{
private Dialog dialog;
public Bulider(Context context){
dialog=new Dialog(context);
}
public Bulider setIcon(){
dialog.setIcon();
return this;
}
public Bulider setTitle(){
dialog.setTitle();
return this;

}
public void show(){
    dialog.show();
}

}

public void setIcon(){

}
public void setTitle(){

}
public void show(){

}
}
`
3 观察者模式
说的观察者模式,我觉得我应该考虑一下eventbus。
分为订阅者,发布者,以及事件总线
onevent 以此为订阅函数,事件在哪里发布就在哪个线程接收
oneventmainthread 以此为订阅函数,事件无论在哪个线程发布,都会在主线程接收,因此oneventmainthread经常更新ui,并且不能进行耗时操作
oneventbackground 事件如果在子线程发布,则在该子线程接收,如果是在主线程发布,则建立一个子线程
oneventasync 无论事件在哪个线程发布,都会建立子线程执行
4 适配器模式
BaseAdpter, ArrayAdapter
就是我们经常使用到的
5 工厂模式
平常我们在建造对象的时候,会使用new,使用工厂模式,只需要执行同一个方法,只是传入的参数不同。

插件化

插件化是什么,像微信的小游戏,当你点击的时候,下载,然后无需安装,直接可以进行玩。
插件化无需升级宿主应用,降低了耦合性。
那么为什么使用插件化呢?
随着业务的发展,需求的不断增加,应用中的dex文件方法书超过了65536,这时候就会出现问题,有些人提出来减少方法数量,删除没有必要的引用,这的确能够缓解,但是总会有引爆的那一天,google提出了一个解决方案multidex。
那么插件化的原理是什么呢?
Android 应用程序会把java文件编译成。class文件,再有再把.class文件编译成.dex文件放入apk。那么动态加载其实就是运行时vm把插件apk直接加载到clsssloader里面的技术。
那么插件加载有什么限制呢?
1 需要预先注册权限
无法在插件中注册具有特殊intentfilter的service activity 广播,以及contentprovider
2 对于service contentprovider 要提前注册
插件编写与正常模块编写的区别
插件内部对资源 的访问有自己的方法,例如inflate
getResouces
3 无法在插件中发送有自定义资源的 通知

Android 动画

参考地址
Android 提供了三种动画,view animation drawable animation propertyanimation
但是第一种有局限性,并不像我们看到的那样,二property animation是真正的属性发生了变化
duration 动画持续的时间
time interpolation 动画的变化率,是先快后慢还是什么
repeat cont 重复次数 behavior 重复的模式
animatorset 动画的集合
1 objectAnimator


objectAnimator.ofFloat(view  retationy 0.0f 360f).setduration().start;

2 valueAnimator
我们可以通过设置addUpdateListener,来监听value的变化
然后就可以自己设置某些属性的值
3. 动画的监听
anim.addlistener(new animatorlistener{
});然后在里面监听动画的开始结束,以及重。
4 animatorSet
动画的集合
可以通过使用animatorset.playtogether(one ,two);设置一起执行
playSequentially一次执行
如果我们有一堆动画,用代码的话 可以使用playwith playbefore等
5 我们可以通过代码实现动画,同样的我们依然可以通过xml文件实现
首先我们要在res 文件夹下创立anim文件夹
6 还有一个我们不经常使用的layouttransition,当容器中视图层次变化时产生的过渡效果

Android 5.0 6.0新特型

这里写链接内容
Android 5.0最大的改变是Material Design的设计风格
也就是扁平化设计,例如新的ui控件cardview tablayot floatbutton
6.0 最大的改变就是权限管理
那么什么是权限管理呢?
Android把系统的权限分为普通权限,危险权限,以及特殊权限
也许有人会考虑到如果我没有做权限管理,是不是意味着我的软件将不能运行
当然不会,我么你都知道,在我们的配置文件里面有一个targetsdkversion,如果这个值小于23,那么就会采用以前的权限管理机制。所以说为了能够兼容,又不想做权限处理,就可以改变这个值。

  @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION_CAMERA_CODE) {
            if (grantResults.length >= 1) {
                int cameraResult = grantResults[0];//相机权限
                boolean cameraGranted = cameraResult == PackageManager.PERMISSION_GRANTED;//拍照权限
                if (cameraGranted) {
                  //具有拍照权限,调用相机
                } else {
                  //不具有相关权限,给予用户提醒,比如Toast或者对话框,让用户去系统设置-应用管理里把相关权限开启
                }
            } 
        }
    }

对于一些特殊的权限,例如文件的读写权限,一般要在开始的时候进行申请,因为我们欢迎界面的图片保存,必须运用到这个,如果用户拒绝,则应跳转到权限管理界面。
例如微信,如果没有给于存储空间权限,则关闭微信。

service保活

参考地址
service被杀死的原因有很多,例如内存回收,第三方软件的清理,系统的后台管理
1. ondestory中重启服务

public int onStartCommand(Intent intent, int flags, int startId) {  
    // TODO Auto-generated method stub  
    return START_STICKY;  
    //return super.onStartCommand(intent, flags, startId);  
}

这个方法的意思是当服务异常关闭的时候,是否要重启
2. 提高service的优先级
一个很好用的方法就是把线程变成前台服务,在onstartcommand 调用stratForeground,类似与音乐播放器
3 双进程
通过jni编程,调用native函数,创建一个子进程,父子进程相互监听。任意一方被杀死的时候,另外一方就把他重新简历
双服务
开启两个服务,然后每隔一段时间进行监听,看对方是否正在运行,如果没有则把他激活。
这时候我们了解一下,remoteservice,其实简历它很简单,只需要在注册的时候,把process参数设置为remoteservice。
因为remoteservie在新的线程中运行,所以说不会阻塞主线程,这样看起来似乎很好。其实不然,我们无法与它机型交流,因为这样就涉及到进程间通讯,就必须使用aidl。

进程保活

  1. 使用广播进行唤醒
    例如开机广播,第三方sdk也会唤醒响应的程序,例如支付宝sdk唤醒支付宝。
    同阵营app的唤醒,例如淘宝,天猫
    2 使用前台服务
    例如音乐播放器
    3双进程守护

videoview 全屏播放

在videoview的外部嵌套一个布局,当我们点击全屏的时候,设置屏幕为横屏,设置为fullwindow,然后改变其父布局的大小,这时候videoview会重新计算宽高。

public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  if (mVv == null) {
      return;
  }
  if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){//横屏
      getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
      getWindow().getDecorView().invalidate();
      float height = DensityUtil.getWidthInPx(this);
      float width = DensityUtil.getHeightInPx(this);
      mRlVv.getLayoutParams().height = (int) width;
      mRlVv.getLayoutParams().width = (int) height;
  } else {
      final WindowManager.LayoutParams attrs = getWindow().getAttributes();
      attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
      getWindow().setAttributes(attrs);
      getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
      float width = DensityUtil.getWidthInPx(this);
      float height = DensityUtil.dip2px(this, 200.f);
      mRlVv.getLayoutParams().height = (int) height;
      mRlVv.getLayoutParams().width = (int) width;
  }
}

textureview

我们都知道,在进行视频播放,或者拍照的时候,我们都会考虑原生的surfaceview,它的工作方式是创建一个置于应用程序窗口之后的新窗口。也就是跟ui界面不在一个窗口上。这样,surfaceview窗口刷新的时候就不用重绘应用程序窗口,这样看来其还是很高效的。
但是因为surfaceview不在应用窗口上,所以说我们不能对他进行一些动画效果,例如uc浏览器的视频播放窗口可以自由移动。同时,也难以放在listview和scrollview。
这时候textureview来了,他并没有穿件一个单独的surface来绘制,,因此我们可以把他看做一个控件,进行移动,透明度的改变等。

清除数据 清除缓存一键清理

清除数据,是指清楚软件的配置信息,以及数据库文件
清除缓存 是指软件运行过程中的临时文件。例如缓存的图片,以及数据内容等
一键清理 是系统级别的功能,主要是
杀死进程,以达到释放内存的目的

清除缓存的原理就是把应用中的数据内容给删除掉:
应用内数据的所有路径:
/data/data/com.xxx.xxx/cache - 应用内缓存(注:对应方法getCacheDir())
/data/data/com.xxx.xxx/databases - 应用内数据库
/data/data/com.xxx.xxx/shared_prefs - 应用内配置文件
/data/data/com.xxx.xxx/files - 应用内文件(注:对应方法getFilesDir())

remoteviews

remoteviews 翻译过来是远程视图,他不是当前进程的视图,而是systemservice的视图。与程序不在一个进程中,应用程序与remoteviews之间通过binder进行通信。
remoteviews大多用在通知栏和桌面浮动界面。
例如在3.0之后,我们创建通知,会使用创建者模式。事先定义好一个,remoteviewe,然后调用:

/3.创建一个Notification
        mNotification = new Notification.Builder(this)
        .setSmallIcon(R.drawable.ic_launcher)
        .setContentIntent(mPendingIntent)
        .setContent(mRemoteViews)
        .build();

由于remoteviews不在app进程中, 我们不能用寻常的findviwbyid来改变其内容的值,
我们使用:mRemoteViews.setTextViewText(R.id.remote_content, "改变了内容");

activity与service进行数据传递

1 通过intent传递数据
2 activity绑定service ,并且并且实现serviceconnect接口,
在onServiceConnected方法里面,当绑定成功之后,可以获得一个binder对象,然后设值

Android 崩溃处理

我们都知道,Android出现各种各样的bug是在所难免的。如果问题严重,可能会出现崩溃的现象,如果我们不进行处理,则会直接退出。
这样对于用户的体验是及其不友好的,因此我们必须进行处理。
一方法,我们在崩溃发生之后,弹出对话框,说明错误信息,然后退出该activity。
另外一个方法,就是直接退出程序,然后重启程序。
这时候我们实现uncaughtexceptionhandler这个接口,重载uncaughtexception方法。
在这个方法里面

Intent intent = new Intent(application.getApplicationContext(), MainActivity.class);  
            PendingIntent restartIntent = PendingIntent.getActivity(    
                    application.getApplicationContext(), 0, intent,    
                    Intent.FLAG_ACTIVITY_NEW_TASK);                                                 
            //退出程序                                          
            AlarmManager mgr = (AlarmManager)application.getSystemService(Context.ALARM_SERVICE);    
            mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,    
                    restartIntent); // 1秒钟后重启应用   
            application.finishActivity();  
        }    

activity的启动模式

任务栈是一个后进先出结构,每一个新建立的activity都会放在栈顶。栈顶的activity获得焦点,如果点击back按钮,则栈顶的activity退出,调用onstop,ondestory方法。每个app默认只有一个任务栈,
standard 标准模式,每次启动一个activity,则先创建一个activity放入栈顶
singletop 如果栈顶已经存在这个activity,则不会重新建立activity,调用这个activity的onnewintent方法。
singletask 如果任务栈中存在这个activity,则不会重新建立,调用onnewintent方法,并且在该activity上面的activity被销毁
singleinstance 该activity放在一个独立的栈中

Android进程优先级

1 前台进程 与用户交互的activity,也就是我么你正在使用
2 可见进程 已经处于暂停状态的activity,已经失去了焦点,但是可见
3 服务进程 例如运行着startservice开启的服务,例如在后台下载文件,播放播放音乐
4 后台进程 运行这onstop而停止的进程,例如后台的qq

Serializable和Parcelable

序列化的意思是将一个对象转化成一个可传输可存储的对象。

Parcelable
他的作用是把对象进行分解,分解后的每一个部分都能够被intent所支持

Android的存储方式

sqllite 数据库
共享参数 以键值对的形式,本质是一个xml
文件存储 房子内存卡里
contentprovider 内容提供者,实现进程间数据的共享。不过它用处很少,很少软件原因别人共享自己的数据。不过音频,视频,通讯录经常采用这种方式。如果有数据进行共享,就通过contentprovider定义一个URI,然后就可以通过这个uri访问数据了、

计步器

总结来说,如果用g-sensor来实现计步会保证良好的兼容性,排除锁屏自动关闭sensor的定制系统除外,基本所有的Android手机都可以使用,但是需要一定时间的算法调试和后台保活机制的健全保证,开发周期较长;如果项目需求开发周期较短,并且没有强制性的全机型兼容,那么可以考虑使用step-sensor,优点比较明显,而且使用协处理器代替纯软件计算实现计步监测已经是大势所趋。另外以上两种方案都需要开机自启权限。

Android新特性

5.0 md设计风格
6.0 大量流畅的动画
支持文件夹拖拽应用
相机增加专业模式
支持快速充电的切换
7.0
分屏多任务
夜间模式

view的刷新机制

在Android 中,viewgroup负责布局并且显示ui,当view 需要刷新的时候,要通知父view对它进行刷新。
首先view要调用view.invilate方法,找到父view,随后把他的attachinfo保存的信息传递给父view刷新自己
这里写链接内容

局部刷新

这里写链接内容
1. 获取点击的item
2. 改变对应position的数据
3. 获得对应的view,更新数据
4. 要记得,调用adapter的notifchangeset方法会导致整个列表更新

view点击事件分发机制

这里写链接内容
我们都知道,用户界面包含多层结构。当我们点击的时候,事件会一层层的分发下去。这就是通过,ondispatchTouchEvent,当某个view的ontouchevent方法返回true的时候,停止分发,开始消耗该点击事件。
如果子view都返回false,则由父view 的ontoucheevent进行处理。
当然,viewgroup还有一个onTercepttouchevent,如果我们不想对点击事件进行分发,则返回true,表示点击事件内部消耗,由他的ontouchevent进行处理

网络数据优化

1.请求合并,能够一次获取的数据,不要分多次进行请求
2. 数据请求的body,head以及返回值进行压缩
3. 根据网络状况进行不同质量图片的下载,适用于电商

nfc

nfc的工作模式:
1 读卡器模式 读写nfc标签
2 仿真卡模式 常用的场景是公交卡门禁卡,把一些信息封装成数据包保存,当靠近的时候被读取,然后进行验证
3 点对点模式 这时候就相当于蓝牙的功能,可以进行数据的传递
nfc标签
nfc的标签多种多样,有的只能读,有的只能写,有的能够对数据进行加密,甚至进行逻辑运算

数据操作的形式
读取ndff数据
写入ndff数据
通过Android beam技术将ndff数据传递到另外一个设备

tag发布系统
当Android设备扫描到一个nfctag。通常的做饭是让合适的intent进行处理,这时候很可能会出现几个软件让你进行选择。
为了能够使软件自动的选择合适的处理activity,Android提供了intent发布系统和前台发布系统处理。
如果当前的activity可以处理,则系统会优先让此activity对该intent进行处理。如果不能够处理,则交给intent发布系统,检测intent filter,看是否能够处理改tag、

蓝牙

蓝牙经历了多个版本的更新,在4.0版本之前,我们可以统称为传统的蓝牙。而在这之后我们叫做ble,也就是低功耗蓝牙。相比着传统蓝牙,ble传输速度更快,覆盖范围更广,延迟更短,安全性更高,耗电量低等。这也是近年来可穿戴设备兴起的原因。另外,两者的传输协议也发生了变化。传统蓝牙是以socket通讯为基础,而低功耗蓝牙则是易gatt协议来实现。

listview加载数据,图片错位

我们都知道,为了优化listvie,我们选择重用view布局。但是这样的结果会导致,当我们加载图片的时候,由于该布局是重用的,导致图片可能上上一页的。为了正常显示,我们可以为我们的imageview设置一个tag,并且预设一个图片,意思就是说判断我们的tag是否跟我们的url相同,如果是则进行加载。

广播

广播分为两类:
无序广播 sendbroadcast
有序广播 sendorderbroadcast
广播接受者的级别越高则能够越早的获取到广播,高级别的广播接收器可以通过abortbroadcast对广播进行拦截
注册广播的方式有两种,一种是在配置文件的静态注册
一种是在代码中注册,不过这样的注册方式当activity结束的时候广播的接收器也开始失效。
还有一点需要明确的是,BroadcastReceiver 的生命周期只有十秒左右,因此我们不能在里面进行耗时的操作。同样我们也不能开启一个线程,因为这样当我们BroadcastReceiver 结束之后,当系统的内存不够的时候会优先杀死没有组件运行的进程,此线程也会被杀死。最好的方法是我们启动一个服务,在里面进行耗时操作

java

一般大家都知道ArrayList和LinkedList的大致区别:
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

一、内存格局通常分为四个区:

全局数据区:存放全局变量,静态数据,常量 —全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。

代码区:存放二进制代码

栈区(stack):存放为运行而分配的局部变量,参数,返回数据,返回地址等 — 由编译器自动分配释放,其操作方式类似于数据结构中的栈(但二者不是同一概念)。

堆区(heap):即自由存储区 — 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收(如Java中的垃圾回收器)。它与数据结构中的堆是两回事,分配方式类似于链表。

String类为例子说明eqauls与==的区别:

在开始这个例子之前,同学们需要知道JVM处理String的一些特性。Java的虚拟机在内存中开辟出一块单独的区域,用来存储字符串对象,这块内存区域被称为字符串缓冲池。当使用 String a = “abc”这样的语句进行定义一个引用的时候,首先会在字符串缓冲池中查找是否已经相同的对象,如果存在,那么就直接将这个对象的引用返回给a,如果不存在,则需要新建一个值为”abc”的对象,再将新的引用返回a。String a = new String(“abc”);这样的语句明确告诉JVM想要产生一个新的String对象,并且值为”abc”,于是就在堆内存中的某一个小角落开辟了一个新的String对象。
StringBuilder:线程非安全的 StringBuffer:线程安全的

所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。
String类用来表示那些创建后就不会再改变的字符串,它是immutable的。而StringBuffer类用来表示内容可变的字符串,并提供了修改底层字符串的方法。 经编译后程序的bytecode(字节码)展示出了实质: 在用String类对象直接拼接时,JVM会创建一个临时的StringBuffer类对象,并调用其append()方法完成字符串的拼接,这是因为String类是不可变的,拼接操作不得不使用StringBuffer类(并且--JVM会将”You are nice.”和”I love you so much.”创建为两个新的String对象)。之后,再将这个临时StringBuffer对象转型为一个String,代价不菲!可见,在这一个简单的一次拼接过程中,我们让程序创建了四个对象:两个待拼接的String,一个临时StringBuffer,和最后将StringBuffer转型成为的String--它当然不是最初的str了,这个引用的名称没变,但它指向了新的String对象。

Java的四种引用,强弱软虚,用到的场景。

JDK1.2之前只有强引用,其他几种引用都是在JDK1.2之后引入的.

强引用(Strong Reference) 最常用的引用类型,如Object obj = new Object(); 。只要强引用存在则GC时则必定不被回收。

软引用(Soft Reference) 用于描述还有用但非必须的对象,当堆将发生OOM(Out Of Memory)时则会回收软引用所指向的内存空间,若回收后依然空间不足才会抛出OOM。一般用于实现内存敏感的高速缓存。 当真正对象被标记finalizable以及的finalize()方法调用之后并且内存已经清理, 那么如果SoftReference object还存在就被加入到它的 ReferenceQueue.只有前面几步完成后,Soft Reference和Weak Reference的get方法才会返回null

弱引用(Weak Reference) 发生GC时必定回收弱引用指向的内存空间。 和软引用加入队列的时机相同

虚引用(Phantom Reference) 又称为幽灵引用或幻影引用,虚引用既不会影响对象的生命周期,也无法通过虚引用来获取对象实例,仅用于在发生GC时接收一个系统通知。 当一个对象的finalize方法已经被调用了之后,这个对象的幽灵引用会被加入到队列中。通过检查该队列里面的内容就知道一个对象是不是已经准备要被回收了. 虚引用和软引用和弱引用都不同,它会在内存没有清理的时候被加入引用队列.虚引用的建立必须要传入引用队列,其他可以没有

HashMap和Hashtable的区别

HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。

HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。
HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。

Map
Map是键值对,键Key是唯一不能重复的,一个键对应一个值,值可以重复。
TreeMap可以保证顺序,HashMap不保证顺序,即为无序的。
Map中可以将Key和Value单独抽取出来,其中KeySet()方法可以将所有的keys抽取正一个Set。而Values()方法可以将map中所有的values抽取成一个集合。

Set
不包含重复元素的集合,set中最多包含一个null元素
只能用Lterator实现单项遍历,Set中没有同步方法。

List
有序的可重复集合。
可以在任意位置增加删除元素。
用Iterator实现单向遍历,也可用ListIterator实现双向遍历

Queue
Queue遵从先进先出原则。
使用时尽量避免add()和remove()方法,而是使用offer()来添加元素,使用poll()来移除元素,它的优点是可以通过返回值来判断是否成功。
LinkedList实现了Queue接口。
Queue通常不允许插入null元素。

Stack
Stack遵从后进先出原则。
Stack继承自Vector。
它通过五个操作对类Vector进行扩展,允许将向量视为堆栈,它提供了通常的push和pop操作,以及取堆栈顶点的peek()方法、测试堆栈是否为空的empty方法等

用法

如果涉及堆栈,队列等操作,建议使用List
对于快速插入和删除元素的,建议使用LinkedList
如果需要快速随机访问元素的,建议使用ArrayList

实现线程的两个方法:
1.继承thread 2实现runnable

线程池

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。

  那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?

  在Java中可以通过线程池来达到这样的效果。今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPoolExecutor类中的方法讲起,然后再讲述它的实现原理,接着给出了它的使用示例,最后讨论了一下如何合理配置线程池的大小。

static final

static是静态修饰关键字,可以修饰变量和程序块以及类方法:当你定义一个static的变量的时候jvm会将将其分配在内存堆上,所有程序对它的引用都会指向这一个地址而不会重新分配内存;修饰一个程序块的时候(也就是直接将代码写在static{…}中)时候,虚拟机就会优先加载静态块中代码,这主要用于系统初始化;当修饰一个类方法时候你就可以直接通过类来调用而不需要新建对象。
final可以修饰变量、方法及类,当你定义一个final变量时,jvm会将其分配到常量池中,程序不可改变其值;当你定义一个方法时,改方法在子类中将不能被重写;当你修饰一个类时,该类不能被继承。

try catch finally

在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。
在转去之前,try中先把要返回的结果存放到不同于x的局部变量中去,执行完finally之后,在从中取出返回结果,
因此,即使finally中对变量x进行了改变,但是不会影响返回结果。
它应该使用栈保存返回值。

jvm dvm的区别

DVM:Dalvik virtual machine
JVM:Java virtual machine

区别:
1.DVM 基于寄存器,JVM基于栈,基于寄存器的编译花费的时间更短;
Dalvik字节码中,变量会被复制给65536个可用寄存器中的任何一个,直接访问这些寄存器,而不是方位堆栈中的元素;
JVM字节码中,变量会被压入堆栈中进行运算;
简单来说,基于寄存器的方式在编译的时候花费的时间更短;

2.Dalvik程序只包含一个.dex,JVM则为多个.class;

3.Dalvik允许多个实例,每一个实例作为一个独立的linux进程执行,可以防止一个程序的崩溃导致所有程序都崩溃;

4.性能:完成同样的事情,基于栈的虚拟机需要更多的指令,意味着更多的指令分派和 内存访问次数,这是 JVM 的执行性能不如 Dalvik VM 的原因之一。

5.DVM预加载-共享机制,运行时,共享相同的类,这样系统消耗会小很多,JVM机制中,打包后,他们都是完全独立的程序,类都是单独加载,单独运行;

另:ART模式 Android runtime (4.4可选,5.0默认开启)
DVM模式,鉴于兼容性,每次运行应用都需要一次编译,执行的效率大大降低;
ART模式,系统会在程序安装后进行一次预编译,将代码转为机器语言存在本地,这样在每次运行时不用再进行编译,大大提高效率;

缺点:
占用存储空间,安装程序变慢;

运动传感器 Motion Sensors

  Android平台提供了一些监控设备运动的传感器。

  运动传感器中有两个永远是基于硬件的,即加速度计和陀螺仪(accelerometer and gyroscope)。

  运动传感器中有三个是既可以基于硬件又可以基于软件的,即重力感应器、线性加速度计、旋转 ##

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值