安卓学习(二)

安卓学习 二

旨在记录下学习任务,以避免忘记

Activity,Window与View的关系

Activity调用方法来调用返回PhoneWindow对象,这个window有一个内部类来控制View,也就是Activity的显示。所以就是Activity是画家,window是画布,View即是画笔;Acivity使用window和view,使用View在Window上显示。

activity的生命周期

来源于菜鸟,侵删

activity的启动模式

activity的启动方式分为显示启动(通过包名来启动)和隐式启动(通过Intent-filter 的Action,Category 或data来实现 )
显示启动

  1. 最常见的:
startActivity(new Intent(当前Act.this, 要启动的Act.class));
  1. 通过Intent的ComponentName:
ComponentName cn = new ComponentName("当前Act的包名","启动Act的类路径");
Intent intent = new Intent();
intent.setComponent(cn);
startActivity(intent);
  1. 初始化Intent时指定包名:
Intent intent = new Intent("android.intent.action.MAIN");
intent.setClassName("当前Act的包名","启动Act的类路径");
startActivity(intent);

下面就是我自己在Android Studio中的小例子

 				//第一种最常见的显示启动
                //startActivity(new Intent(MainActivity.this, MainActivity2.class));

                //第二种显示启动,第一个参数是当前应用的包名,第二个参数是要跳转的组件的类路径
				//ComponentName cn = new ComponentName("com.example.myapplication","com.example.myapplication.MainActivity2");
				//Intent intent = new Intent();
				//intent.setComponent(cn);
				//startActivity(intent);

                //第三种显示启动,第一个参数是当前应用的包名,第二个参数是要跳转的组件的类路径
                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) {
        // TODO: Return the communication channel to the service.
        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?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值