Android学习笔记
Android几种进程
- 前台进程:即与用户正在交互的Activity或者Activity用到的Service等,如果系统内存不足时前台进程是最后被杀死的
- 可见进程:可以是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被用户可见,但由于失去了焦点而不能与用户交互
- 服务进程:其中运行着使用startService方法启动的Service,虽然不被用户可见,但是却是用户关心的,例如用户正在非音乐界面听的音乐或者正在非下载页面自己下载的文件等;当系统要空间运行前两者进程时才会被终止
- 后台进程:其中运行着执行onStop方法而停止的程序,但是却不是用户当前关心的,例如后台挂着的QQ,这样的进程系统一旦没了有内存就首先被杀死
- 空进程:不包含任何应用程序的程序组件的进程,这样的进程系统是一般不会让他存在的
- 如何避免后台进程被杀死:
调用startForegound,让你的Service所在的线程成为前台进程
Service的onStartCommond返回START_STICKY或START_REDELIVER_INTENT
Service的onDestroy里面重新启动自己
Android开发基础之服务Service
- Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户
界面的应用组件,Service是使程序后台运行的保证. - Service与Activity的区别:
当 Activity 被 finish 之后,你不再持有该 Thread 的引用,并且没有办法在不同的 Activity 中对同一 Thread 进行控制。而任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例
代码:
startService --> onCreate()--> onStartCommand()--> stopService-->onDestroy()
1.多次调用时onCreate方法只执行一次,onStartConmon()会被多次调用。
2.当我们通过startService启动时候,通过intent传值,在onStartCommand()方法中获取值的时候,一定要先判断intent是否为null
- bindService()方式进行绑定
onCreate()-->onBind()-->unBind()-->onDestroy()
1.这种方式更方便Activity与Service的通信,activity获取ServiceConnection对象,通过ServiceConnection来获取service中内部类的类对象
2.绑定服务的生命周期跟Activity是不求同时生,但求同时死,Activity没了,服务也要解绑;
3.绑定服务开启的服务,只可以解绑一次,多次解绑会抛异常;
- 两种方式的优缺点:
1、startService这个方法来启动服务的话,是长期运行的,只有stopService才会停止服务。而bindService来启动服务,不用的时候,需要调用unBindService,否则会导致context泄漏,所以bindService不是长期运行的。当context销毁的时候,则会停止服务运行。
2、startService来启动服务可以长期运行,但是不可以通讯,而bindService的方式来启动服务则可以通讯,两者都有优缺点,所以我们就有了混合起来使用的方法。
- bindService demo
public class BindService extends Service {
private static final String TAG = "BindService";
public class CommunicateBinder extends Binder {
void callInnerMethod(){
innerMethod();
}
}
private void innerMethod() {
Log.d(TAG, "innerMethod was called...");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return new CommunicateBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
}
public class BindServiceActivity extends AppCompatActivity implements View.OnClickListener {
private Button bt_bindService, bt_unbindService, bt_callSeviceMethod;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bind_service);
bt_bindService = findViewById(R.id.bindService);
bt_bindService.setOnClickListener(this);
bt_unbindService = findViewById(R.id.unbindService);
bt_unbindService.setOnClickListener(this);
bt_callSeviceMethod = findViewById(R.id.bt_callSeviceMethod);
bt_callSeviceMethod.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.bindService:
//创建意图对象
Intent intent = new Intent(this, BindService.class);
// 第一个是参数是意图对象,第二个参数是回调,第三个参数是标记,这个是自动创建的意,如果服务没有start,那么会自己创建。
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
break;
case R.id.unbindService:
//解绑服务
if (mServiceConnection != null) {
unbindService(mServiceConnection);
}
break;
case R.id.bt_callSeviceMethod:
//调用服务里的方法
callServiceMethod();
break;
default:break;
}
}
private BindService.CommunicateBinder mCommunicateBinder;
private ServiceConnection mServiceConnection = new ServiceConnection(){
// 当调用bindService方法后就会回调Activity的onServiceConnected,在这个方法中会向Activity中传递一个IBinder的实例,Acitity需要保存这个实例
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
if (service instanceof BindService.CommunicateBinder) {
mCommunicateBinder = (BindService.CommunicateBinder) service;
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
//这个方法只有出现异常时才会调用,服务正常退出不会调用。
}
};
到底什么是Binder
-
通常意义下,Binder指的是一种通信机制
-
对于传输过程而言,Binder是 可以进行跨进程传递的对象
-
线程中sleep和wait的区别
(1)这两个方法来自不同的类,sleep是来自Thread,wait是来自Object;
(2)sleep方法没有释放锁,而wait方法释放了锁。
(3)wait,notify,notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。
View,ViewGroup事件分发
Android的View事件分发
Android ViewGroup事件分发机制
-
View事件的运行顺序为:
dispatchTouchEvent—> onTouch (setOnTouchListener) —> onTouchEvent -
VeiwGroup事件的运行顺序:
VeiwGroup的dispatchTouchEvent -> VeiwGroup的onInterceptTouchEvent(需要拦截,只要return true) ->View的dispatchTouchEvent ->View的onTouchEvent
如果最后一个view没有消费事件 ,事件就会依次回传,传递到最高位的Activity,如果Activity也没有消费事件,这个事件就会被抛弃。
子View可以通过调用getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup对其MOVE或者UP事件进行拦截;
Touch事件传递机制
*在我们点击屏幕时,会有下列事件发生:
Activity调用dispathTouchEvent()方法,把事件传递给Window;
Window再将事件交给DecorView(DecorView是View的根布局);
DecorView再传递给ViewGroup;
Activity ——> PhoneWindow ——> DecorView ——> ViewGroup——> View
3事件分发的主要有三个关键方法
- dispatchTouchEvent() 分发
- onInterceptTouchEvent() 拦截 ,只有ViewGroup独有此方法
- onTouchEvent() 处理触摸事件
Activity首先调用dispathTouchEvent()进行分发,接着调用super向下传递
- ViewGroup首先调用dispathTouchEvent()进行分发,接着会调用onInterceptTouchEvent()(拦截事件)。若拦截事件返回为true,表示拦截,事件不会向下层的ViewGroup或者View传递;false,表示不拦截,继续分发事件。默认是false,需要提醒一下,View是没有onInterceptTouchEvent()方法的
事件在ViewGroup和ViewGroup、ViewGroup和View之间进行传递,最终到达View;
- View调用dispathTouchEvent()方法,然后在OnTouchEvent()进行处理事件;OnTouchEvent() 返回true,表示消耗此事件,不再向下传递;返回false,表示不消耗事件,交回上层处理。
Intent传递数据和Bundle传递数据
// 1.直接用intent.putExtra
Intent intent = new Intent(MainActivity.this,OtherActivity.class);
intent.putExtra("name", "Nicole");
intent.putExtra("age", 25);
intent.putExtra("address", "Shenzhen");
//2.用Bundle
Intent intent = new Intent(MainActivity.this,OtherActivity.class);
Bundle bundle = new Bundle();
bundle.putString("name", "Ben");
bundle.putInt("age", 28);
bundle.putString("address", "China");
intent.putExtras(bundle); //将bundle传入intent中。
Intent传递数据和Bundle传递数据的区别?
Intent传递数据和Bundle传递数据是一回事,Intent传递时内部还是调用了Bundle。
// Intent putExtra源码
public @NonNull Intent putExtra(String name, Bundle value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putBundle(name, value); //使用bundle添加参数
return this;
}
public @NonNull Intent putExtra(String name, String value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putString(name, value); //使用bundle添加参数
return this;
}
public @NonNull Intent putExtra(String name, int value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putInt(name, value); //使用bundle添加参数
return this;
}
public @NonNull Intent putExtra(String name, Parcelable value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putParcelable(name, value); //使用bundle添加参数
return this;
}
public @NonNull Intent putExtra(String name, Serializable value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putSerializable(name, value); //使用bundle添加参数
return this;
}
... 其他的类型
Serializable 和Parcelable 的区别
- Serializable Java 序列化接口 在硬盘上读写 读写过程中有大量临时变量的生成,内部执行大量的i/o操作,效率很低。
Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中
Serializable 方式
- 使用 Intent 来传递对象通常有两种实现方式,Serializable 和 Parcelable,本小节中我们先来学习一下第一种的实现方式。
Serializable 是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。至于序列化的方法也很简单,只需要让一个类去实现 Serializable 这个接口就可以了。
比如说有一个 Person 类,其中包含了 name 和 age 这两个字段,想要将它序列化就可以这样写
public class Person implements Serializable{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
其中 get、set 方法都是用于读取和赋值字段数据的,最重要的部分是在第一行。这里让 Person 类去实现了 Serializable 接口,这样所有的 Person 对象就都是可序列化的了。
接下来在 FirstActivity 中的写法非常简单:
Person person = new Person();
person.setName("Tom");
person.setAge(20);
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("person_data", person);
startActivity(intent);