安卓学习 二
旨在记录下学习任务,以避免忘记
Activity,Window与View的关系
Activity调用方法来调用返回PhoneWindow对象,这个window有一个内部类来控制View,也就是Activity的显示。所以就是Activity是画家,window是画布,View即是画笔;Acivity使用window和view,使用View在Window上显示。
activity的生命周期
activity的启动模式
activity的启动方式分为显示启动(通过包名来启动)和隐式启动(通过Intent-filter 的Action,Category 或data来实现 ) 显示启动:
- 最常见的:
startActivity(new Intent(当前Act.this, 要启动的Act.class));
- 通过Intent的ComponentName:
ComponentName cn = new ComponentName("当前Act的包名","启动Act的类路径");
Intent intent = new Intent();
intent.setComponent(cn);
startActivity(intent);
- 初始化Intent时指定包名:
Intent intent = new Intent("android.intent.action.MAIN");
intent.setClassName("当前Act的包名","启动Act的类路径");
startActivity(intent);
下面就是我自己在Android Studio中的小例子
Intent intent = new Intent("android.intent.action.MAIN");
intent.setClassName("com.example.myapplication","com.example.myapplication.MainActivity2");
startActivity(intent);
隐式启动 需要先在 manifest.xml 文件中写如以下代码:
<activity android:name=".SecondActivity"
android:label="第二个Activity">
<intent-filter>
<action android:name="my_action"/>
<category android:name="my_category"/>
<categoty android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
在到java文件中写下例代码进行启动
Intent it = new Intent();
it.setAction("my_action");
it.addCategory("my_category");
startActivity(it);
activity 的四种加载模式
四种加载模式分别为:
四种模式的切换主要在 manifest.xml 文件中修改
<activity android:name=".MainActivity"
android:launchMode="singleTop">//这
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
-
standard模式
通过这种模式每次启动Activity,都会创建一个新的Activity,即使有一个该Activity类实例在栈顶,它还是会创建一个新的Activity,压入栈中。 标准启动模式,也是activity的默认启动模式,在这种模式下启动的activity可以被多次实例化,即在同一个任务中可以存在多个activity的实例,每个实例都会处理一个Intent对象。如果Activity A的启动模式为standard,并且A已经启动,在A中再次启动Activity A,即调用startActivity ( new Intent (this, A.class ) ) , 会在A的上面再次启动一个A的实例,即当前的栈中的状态为 A–>A
-
singleTop模式
和前者一样,不过如果有该Activity类的实例在栈顶的话,就直接复用已有的Activity示例,并不会再创建新的实例。 如果一个以singleTop模式启动的Activity的实例已经存在于任务栈的栈顶,那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的onNewIntern()方法将Intent对象传递到这个实例中。举例来说,如果A的启动模式为singleTop,并且A的一个实例已经存在于栈顶中,那么再调用startActivity(new Intent (this, A.class) ) 启动A时,不会再次创建A的实例,而是复用原来的实例,并且调用原来的onNewIntent()方法。这时任务栈中还是这一个A的实例。如果以singleTop模式启动的activity的一个实例已经存在于任务栈中,但是不在栈顶,那么它的行为和standard模式相同,也会创建多个实例。
什么时候A在栈顶? -
singleTask模式
这种方式加载的Activity在同一Task中仅有一个实例。 (一) 如果要启动的Activity不存在,会创建一个,并且把它压入栈顶 (二) 如果已经位于栈顶了,就不会创建新的示例,直接复用Activity实例 (三) 存在,但不在栈顶,会一处该Activity上其他的Activity,从而让其位于栈顶 只允许在系统中有一个Activity实例。如果系统中已经有了一个实例,持有这个实例的任务将移动到顶部,同时Intent将被通过onNewIntent()发送。如果没有,则会创建一个新的Activity并放在合适的任务中。
-
singleInstance模式
保证系统无论从哪个Task启动Activity都只会创建一个Activity实例,并将它加入新的Task栈顶。 (一) 如果启动的Activity不存在,会先建一个新的Task,然后再创建Activity加入栈顶 (二)已经存在,无论它位于哪个Task,都会移到前台,从而显示出该Activity 保证系统无论从哪个Task启动Activity都只会创建一个Activity实例,并将它加入新的Task栈顶, 也就是说被该实例启动的其他activity会自动运行于另一个Task中。当再次启动该activity的实例时,会重用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这个的Activity实例。
onNewIntent()
onNewIntent与启动模式 前提:ActivityA已经启动过,处于当前应用的Activity任务栈中;
当ActivityA的LaunchMode为Standard时:
由于每次启动ActivityA都是启动新的实例,和原来启动的没关系,所以不会调用原来ActivityA的onNewIntent方法
当ActivityA的LaunchMode为SingleTop时:
如果ActivityA在栈顶,且现在要再启动ActivityA,这时会调用onNewIntent()方法 ,生命周期顺序为:
onCreate —>onStart —>onResume —>onPause —>onNewIntent —>onResume
当ActivityA的LaunchMode为SingleInstance,SingleTask:
如果ActivityA已经在任务栈中,再次启动ActivityA,那么此时会调用onNewIntent()方法,生命周期调用顺序为:
onPause—>跳转其它页面—>onCreate—>onStart—>onResume—onPause—>跳转A—>onNewIntent—>onRestart—>onStart—>onResume
总的来说,只对SingleTop(且位于栈顶),SingleTask和SingleInstance(且已经在任务栈中存在实例)的情况下,再次启动它们时才会调用,即只对startActivity有效,对仅仅从后台切换到前台而不再次启动的情形,不会触发onNewIntent。
如果还不能够理解,可以看一看这篇文章,有动图更加的清晰。
https://blog.csdn.net/qq_44861716/article/details/104358437
service的两种启动方式
service的两种启动方式分别为StartService启动和BindService启动
注:android5.0以后不能使用隐式intent启动Service,即不允许只设置action的方式来启动service
StartService启动
(一)首次启动会创建 一个Service实例,依次调用onCreate() 和 onStartCommand() 方法,此时Service进入运行状态,如果再次调用StartService启动Service,将不会再创建新的Service对象,系统会直接复用前面创建的Service对象,调用它的onStartCommand() 方法! (二) 但这样的Service与它的调用者无必然的联系,就是说当调用者结束了自己的生命周期,但是只要不调用stopService,那么Service还是会继续运行的! (三) 无论启动了多少次Service,只需调用一次StopService即可停掉Service。
Service代码如下:
public class MyService extends Service {
public MyService() {
}
private final String TAG ="MyService";
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind方法被调用!");
return null;
}
@Override
public void onCreate() {
Log.i(TAG, "onCreate方法被调用!");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand方法被调用!");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestory方法被调用!");
super.onDestroy();
}
}
在MainActivity中添加如下代码,再到xml文件中添加两个按钮控件即可。
Button buttonqd = findViewById(R.id.qdfw);
buttonqd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent startIntent = new Intent(MainActivity.this, MyService.class);
startService(startIntent);
}
});
Button buttontzfw = findViewById(R.id.tzfw);
buttontzfw.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent stopIntent = new Intent(MainActivity.this, MyService.class);
stopService(stopIntent);
}
});
一般来说在新建一个Service.java 代码的时候会自动在XML文件中帮我们创建一下代码,用于注册存在这样一个service;若不是之间创建的Service文件而是创建的普通java文件的话,就需要在XML文件中添加一下代码。
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
</service>
BindService启动
(一) 当首次使用bindService绑定一个Service时,系统会实例化一个Service实例,并且调用其onCreate() 和 onBind() 方法,然后调用者就可以通过IBinder和Service 进行交互了,此后如果再次使用bindService绑定Service,系统不会创建新的Service实例,也不会再调用 onBind() 方法,只会直接把IBinder对象传递给其他后来增加的客户端! (二)如果我们接触与服务的绑定,只需调用unbindService() ,此时onUnbind和onDestory 方法将会被调用!这是一个客户端的情况,加入是多个客户端绑定同一个Service的话,情况如下:当一个客户完成和Service之间的互动后,它调用unbindService() 方法开接触绑定。当所有的客户端都和service解除绑定后,系统会销毁service。(除非service也被startService()方法开启) (三)另外,和上面那张情况不同,bindService模式下的Service是与调用者相互关联的,可以理解为 “一条绳子上的蚂蚱”,要死一起死,在bindService后,一旦调用者销毁,那么Service也立即终止! 通过BindService调用Service时调用的Context的bindService的解析 bindService(Intent Service,ServiceConnection conn,int flags)
Service: 通过该intent指定要启动的Service conn : ServiceConnection对象,用户监听访问者与Service见的连接情况,链接成功回调该对象中的onServiceConnected(ComponentName, IBinder) 方法,如果Service 所在的宿主由于异常终止或租其他原因终止,导致Service与访问者间断开连接时调用onServiceDisconnected(CompanentName) 方法,主动通过unBindService() 方法断开并不会调用上述方法! flags :指定绑定时是否自动创建Service (如果Service还未创建),参数可以是0(不自动创建),BIND_AUTO_CREATE(自动创建)
如果Service已经由某个客户端通过StartService () 启动,接下来由其他客户端再调用bindService() 绑定到该Service后调用unbindService() 解除绑定最后在调用bindService() 绑定到 Service 的话,此时所出发的生命周期方法如下: onCreate()-> onStartCommand()-> onBind() -> onUnbind() -> onRebind() 前提是:onUnbind() 方法返回的是true!这里调用了unbindService后Service不会调用onDistory() 方法,因为这个Service是由我们的StartService来启动的,所以调用onUnbind() 方法取消绑定,并不会终止Service。 得出的结论是 :假如我们使用bindService来绑定一个启动的Service,注意是已经启动的Service! 系统只是将Service的内部IBinder对象传递给Activity,并不会将Service的生命周期与Activity绑定,因此调用unBindService() 方法取消绑定时,Service也不会被销毁!
总结: Step 1:在自定义的Service中继承Binder,实现自己的IBinder对象 Step 2:通过onBind( )方法返回自己的IBinder对象 Step 3:在绑定该Service的类中定义一个ServiceConnection对象,重写两个方法, onServiceConnected和onDisconnected!然后直接读取IBinder传递过来的参数即可!
下面就是一个简单的计时Service
public class MyService2 extends Service {
public MyService2() {
}
private final String TAG = "MyService2";
private int count;
private boolean quit;
private MyBinder binder = new MyBinder();
public class MyBinder extends Binder {
public int getCount() {
return count;
}
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind方法被调用!");
return binder;
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate方法被调用!");
new Thread() {
public void run(){
while (!quit) {
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
};
}.start();
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG,"onUnbind方法被调用");
return true;
}
@Override
public void onDestroy() {
super.onDestroy();
this.quit =true;
Log.i(TAG, "onDestroy方法被调用!");
}
@Override
public void onRebind(Intent intent) {
Log.i(TAG,"onRebind方法被调用");
super.onRebind(intent);
}
}
public class MainActivity2 extends AppCompatActivity {
MyService2.MyBinder binder;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("-----Service Connected-----");
binder = (MyService2.MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("-----Service Disconnected-----");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Button buttonlock = findViewById(R.id.lockS);
buttonlock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent startIntent = new Intent(MainActivity2.this, MyService2.class);
bindService(startIntent, conn, Service.BIND_AUTO_CREATE);
}
});
Button buttonbreak = findViewById(R.id.BreakLock);
buttonbreak.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(conn);
}
});
Button buttongetS = findViewById(R.id.GetS);
buttongetS.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Service的count的值为:"
+ binder.getCount(), Toast.LENGTH_SHORT).show();
}
});
}
}
xml文件自动添加
<service
android:name=".MyService2"
android:enabled="true"
android:exported="true">
</service>
Tips: Service不是一个单独的进程,它和它的应用程序在同一个进程中。 Tips:Service不是一个线程,这样就意味者我们应该避免在Service中进行耗时操作;如果将耗时进程放到了Service中的onStart()方法中,很容易引发ANR异常(Application Not Responding,也就是应用未响应)。
IntentService
根据上面对Service的了解,我们知道要想在Service中进行耗时操作是会出问题的,Android为了解决这个问题,提出了Service的替代品:IntentService。 IntentService继承于Service并处理异步请求的一个类,在IntentService中有一个工作线程来处理耗时操作,请求的Intent记录会加入队列。
Service多次创建后销毁
多次启动Service ,只会重复的调用onStartCommand方法!无论启动多少次Service,一个stopService 就会停止Service!
这里再提一嘴,如果使用的是bindService将service和Activity绑定在一起,那么在Activity被销毁时,改Service也会被销毁; 如果使用的是StartService启动的服务,且并未绑定到Activity那么Service的生命周期不会受Activity影响,在Activity销毁后,Service不会发生变化,无法销毁。 如果使用bindService()方法启动服务,活动内部维持着service传来的Binder对象,二者同生命周期 活动退出时确实使用了unbindService()方法取消绑定的话,binder对象设为空,活动会销毁。 如果没使用unbindService()方法,内存泄露, 活动无法销毁
Service 创建的时候就销毁会怎么样(生命周期)
@Override
public void onCreate() {
Log.i(TAG, "onCreate方法被调用!");
super.onCreate();
onDestroy();
}
总结:启动的时候销毁,就是在onCreate的时候加一条onDestroy,调用这个函数,根据下图我们可以清晰的看出,在启动的时候调用了OnCreate() 方法随后就调用了onDestroy() ,再其次是调用的onStartCommand() 方法,随后再多次点击启动服务都只是调用onStartCommand() 方法.
https://www.runoob.com/w3cnote/android-tutorial-activity.html
https://www.runoob.com/w3cnote/android-tutorial-service-1.html
https://www.runoob.com/w3cnote/android-tutorial-service-2.html https://www.runoob.com/w3cnote/android-tutorial-service-3.html
https://blog.csdn.net/javazejian/article/details/52709857?
|