Android开发

以下是在做Xamarin.Form开发时遇到的Android相关问题 

安卓开发中JDK、SDK、NDK、ADT、ANT等概念作用解释

jar包与aar包的区别

Android中API级别

清单文件中

<uses-sdk android:minSdkVersion="integer"
          android:targetSdkVersion="integer"
          android:maxSdkVersion="integer" />

通过整数形式的 API 级别表示应用与一个或多个版本的 Android 平台的兼容性。应用表示的 API 级别将与给定 Android 系统的 API 级别进行比较,其结果在不同 Android 设备上可能有所差异。

  • android:minSdkVersion

一个用于指定应用运行所需最低 API 级别的整数。如果设备的 API 级别低于该属性中指定的值,Android 系统将阻止用户安装应用。您应始终声明该属性。

注意:如果您不声明该属性,系统将假定默认值为“1”,这表示您的应用兼容所有 Android 版本。如果您的应用并不兼容所有版本(例如,它使用 API 级别 3 中引入的 API),并且您尚未声明正确的 minSdkVersion,则当应用安装在 API 级别小于 3 的系统上时,应用将在运行时尝试访问不可用的 API 时发生崩溃。因此,请务必在 minSdkVersion 属性中声明合适的 API 级别

  • android:targetSdkVersion

一个用于指定应用的目标 API 级别的整数。如果未设置,其默认值与为 minSdkVersion 指定的值相等。

该属性用于通知系统,您已针对目标版本进行测试,并且系统不应通过启用任何兼容性行为,以保持您的应用与目标版本的向前兼容性。应用仍可在较低版本上运行(最低版本为 minSdkVersion)。

  • android:maxSdkVersion

一个指定作为应用设计运行目标的最高 API 级别的整数。

任一情况下,如果应用的 maxSdkVersion 属性低于系统本身使用的 API 级别,则系统将不允许安装应用。在系统更新后重新验证的情况下,这实际相当于将您的应用从设备中移除。

警告:不建议声明该属性。

API级别,各 Android 平台版本所支持的 API 级别,参考官网:什么是 API 级别?

Android 平台提供一种框架 API,应用可利用它与底层 Android 系统进行交互。该框架 API 由以下部分组成:

  • 一组核心软件包和类
  • 一组用于声明清单文件的 XML 元素和属性
  • 一组用于声明和访问资源的 XML 元素和属性
  • 一组 Intent
  • 一组应用可请求的权限,以及系统中包括的权限强制执行

Android 平台提供的框架 API 使用称为“API 级别”的整数标识符指定。每个 Android 平台版本恰好支持一个 API 级别,但隐含对所有早期 API 级别(低至 API 级别 1)的支持。Android 平台初始版本提供的是 API 级别 1,后续版本的 API 级别则依次增加。

match_parent、fill_parent与wrap_content的区别

/match_parent/: 它就是强制性的使它的大小等同于父控件,父控件多大,他就多大。

/fill_parent/: 这个属性就是充满了整个父控件。

有的人可能会觉得fill_parent和match_parent的作用相同啊。没错,从Android2.2以后是一样的,但是如果为了兼容更低的版本,建议使用fill_parent。

蓝色框框是父控件的大小—-(fill_parent,match_parent)

/wrap_content/: wrap—->包(着),content—->内容,单词意思上去理解,这个属性就是让这个属性包着内容,转译过来,就是使这个属性和内容的大小刚好。

蓝色框框是父控件大小—-(wrap_content)

View中FocusChange与Click的区别

以编辑栏为例,

FocusChange是焦点切换事件,当焦点不在此控件时,一旦它获得焦点则引发该事件;相反 失去焦点也会触发

_etFrom.FocusChange += EtSender_FocusChange;

private void EtSender_FocusChange(object sender, FocusChangeEventArgs e)
        {
            if (e.HasFocus)
            {
                if (_pageViewPcl.MailAccountList.Count > 1)
                {
                    SwitchAccount();
                }
            }
        }

Click时单击事件(前提是此控件获得焦点的情况下,否则不会触发)

Activity的生命周期

管理Activity的生命周期

(“创建”和“开始”)是瞬态,CreatedStarted)都是短暂的瞬态,系统会通过调用下一个生命周期回调方法从这些状态快速移到下一个状态。 

  • Resumed:在这种状态下,Activity处于前台,且用户可以与其交互。(有时也称为“运行”状态。)
  • Paused:在这种状态下,Activity被在前台中处于半透明状态或者未覆盖整个屏幕的另一个Activity—部分阻挡。暂停的Activity不会接收用户输入并且无法执行任何代码。
  • Stopped:在这种状态下,Activity被完全隐藏并且对用户不可见;它被视为处于后台。停止时,Activity实例及其诸如成员变量等所有状态信息将保留,但它无法执行任何代码。

1、启动与销毁Activity

  大多数app包括多个activity,使用户可以执行不同的动作。不论这个activity是当用户点击应用图标创建的main activtiy还是为了响应用户行为而创建的其他activity,系统都会调用新activity实例中的onCreate()方法。

我们必须实现onCreate()方法来执行程序启动所需要的基本逻辑。例如可以在onCreate()方法中定义UI以及实例化类成员变量。

  一旦onCreate 操作完成,系统会迅速调用onStart() 与onResume()方法。我们的activity不会在Created或者Started状态停留。技术上来说, activity在onStart()被调用后开始被用户可见,但是 onResume()会迅速被执行使得activity停留在Resumed状态,直到一些因素发生变化才会改变这个状态。例如接收到一个来电,用户切换到另外一个activity,或者是设备屏幕关闭。

  activity生命周期最后一个回调是onDestroy(),当收到需要将该activity彻底移除的信号时,系统会调用这个方法。

大多数 app并不需要实现这个方法,因为局部类的references会随着activity的销毁而销毁,并且我们的activity应该在onPause()与onStop()中执行清除activity资源的操作。然而,如果activity含有在onCreate调用时创建的后台线程,或者是其他有可能导致内存泄漏的资源,则应该在OnDestroy()时进行资源清理,杀死后台线程。

Note: 除非程序在onCreate()方法里面就调用了finish()方法,系统通常是在执行了onPause()与onStop() 之后再调用onDestroy() 。在某些情况下,例如我们的activity只是做了一个临时的逻辑跳转的功能,它只是用来决定跳转到哪一个activity,这样的话,需要在onCreate里面调用finish方法,这样系统会直接调用onDestory,跳过生命周期中的其他方法。

2、暂停与恢复Activity

当打开一个半透明的activity时(例如以对话框的形式),之前的activity会被暂停。 只要之前的activity仍然被部分可见,这个activity就会一直处于Paused状态。然而,一旦之前的activity被完全阻塞并不可见时,则其会进入Stop状态。

我们应该避免在onPause()时执行CPU-intensive 的工作,例如写数据到DB,因为它会导致切换到下一个activity变得缓慢(应该把那些heavy-load的工作放到onStop()去做)。

如果activity实际上是要被Stop,那么我们应该为了切换的顺畅而减少在OnPause()方法里面的工作量。

Note:当activity处于暂停状态,Activity实例是驻留在内存中的,并且在activity 恢复的时候重新调用。我们不需要在恢复到Resumed状态的一系列回调方法中重新初始化组件。

恢复:

当用户从Paused状态恢复activity时,系统会调用onResume()方法。

请注意,系统每次调用这个方法时,activity都处于前台,包括第一次创建的时候。所以,应该实现onResume()来初始化那些在onPause方法里面释放掉的组件

3、停止与重启Activity

停止:

当activity调用onStop()方法, activity不再可见,并且应该释放那些不再需要的所有资源。一旦activity停止了,系统会在需要内存空间时摧毁它的实例(和栈结构有关,通常back操作会导致前一个activity被销毁)。极端情况下,系统会直接杀死我们的app进程,并不执行activity的onDestroy()回调方法, 因此我们需要使用onStop()来释放资源,从而避免内存泄漏。尽管onPause()方法是在onStop()之前调用,我们应该使用onStop()来执行那些CPU intensive的shut-down操作,例如往数据库写信息。

 重启:

当activity从Stopped状态回到前台时,它会调用onRestart().系统再调用onStart()方法,onStart()方法会在每次activity可见时都会被调用onRestart()方法则是只在activity从stopped状态恢复时才会被调用,因此我们可以使用它来执行一些特殊的恢复(restoration)工作,请注意之前是被stopped而不是destrory。

使用onRestart()来恢复activity状态是不太常见的。然而,因为onStop()方法应该做清除所有activity资源的操作,我们需要在重启activtiy时重新实例化那些被清除的资源,同样, 我们也需要在activity第一次创建时实例化那些资源。介于上面的原因,应该使用onStart()作为onStop()所对应方法。因为系统会在创建activity与从停止状态重启activity时都会调用onStart()。也就是说,我们在onStop里面做了哪些清除的操作,就该在onStart里面重新把那些清除掉的资源重新创建出来。

4、重新创建Activity

Activity由于正常的程序行为而被Destory的几个场景:

  • 当用户点击返回按钮
  • Activity通过调用finish()来发出停止信号
  • 系统也有可能会在Activity处于stop状态且长时间不被使用
  • 在前台activity需要更多系统资源的时关闭后台进程,以图获取更多的内存

当Activity是因为用户点击Back按钮或者是activity通过调用finish()结束自己时,系统就丢失了对Activity实例的引用,因为这一行为意味着不再需要这个activity了。

然而,如果因为系统资源紧张而导致Activity的Destory, 系统会在用户回到这个Activity时有这个Activity存在过的记录,系统会使用那些保存的记录数据(描述了当Activity被Destory时的状态)来重新创建一个新的Activity实例。那些被系统用来恢复之前状态而保存的数据被叫做 "instance state" ,它是一些存放在Bundle对象中的key-value pairs。(请注意这里的描述,这对理解onSaveInstanceState执行的时刻很重要)

  为了可以保存额外更多的数据到saved instance state。在Activity的生命周期里面存在一个额外的回调函数,你必须重写这个函数onSaveInstanceState() ,当用户离开Activity时,系统会调用它

当系统调用这个函数时,系统会在Activity被异常Destory时传递 Bundle 对象,这样我们就可以增加额外的信息到Bundle中并保存到系统中。

若系统在Activity被Destory之后想重新创建这个Activity实例时,之前的Bundle对象会(系统)被传递到你我们activity的onRestoreInstanceState()方法与 onCreate() 方法中。

basic-lifecycle-savestate

onResume()方法什么时候执行

onResume是在启动activity启动之后才能执行的,也就是恢复执行。

程序正常启动:
正常退出:onPause()->onStop()->onDestory();
程序按back 退出:onPause()->onStop()->onDestory(),
                再进入:onCreate()->onStart()->onResume();
程序按home退出:onPause()->onStop(),
                 再进入:onRestart()->onStart()->onResume();
 
一个Activity启动另一个Activity: onPause()->onStop(), 
                再返回:onRestart()->onStart()->onResume()

Activity之入栈出栈操作

如果是多个关联的Activity一起操作,如由FirstActivity打开SecondActivity程序,SecondActivity程序打开ThirdActivity程序,则所有的Activity将会自动压入到一个栈中。

而如果点击手机屏幕上的返回键,或使用Intent连续返回到上一个Activity时,会以“后进先出”的原则从ThirdActivity界面返回到SecondActivity界面,再返回到FirstActivity界面。从栈中弹出每一个Activity程序。

 

而如果一个Activity调用了finish()方法,即意味着该Activity将会被销毁。例如SecondActivity.this.finish(),则该SecondActivity就不会被压入栈,以后执行栈操作时不会再显示该SecondActivity程序。

所以如果从ThirdActivity界面执行返回操作,则会从ThirdActivity直接返回到FirstActivity界面。

Activity四种启动模式

Activity四种启动模式及onNewIntent()方法

https://www.cnblogs.com/CallMeUncle/p/5511093.html

Intent用法

Intent在Android中的核心作用就是“跳转”(Android中的跳转机制),同时可以携带必要的信息,将Intent作为一个信息桥梁。最熟悉的莫过于从一个活动跳转到另一个活动,然后返回到上一个活动。

Intent的基本知识

Android程序关闭 退出问题

在Xamarin.Android中是System.Environment.Exit(0)

1、使用System.exit(0)退出后app又重新启动

System.exit(0):终止当前正在运行的 Java 虚拟机。参数用作状态码;根据惯例,非 0 的状态码表示异常终止。System.exit(0)正常终止程序,有时候在退出安卓应用会使用到。
使用这个方法如果前面存在没有finish()掉的Activity会重新启动,导致退出失败。
所以:使用System.exit(0)时,确保任务栈中所有activity已经finish。

2、Process.killProcess(Process.myPid())

会杀掉所有PID一样的进程,比如那些拥有相同UID的应用,统统都会被杀掉。

但是这两种都需要注意 所有Activity都已经销毁。

参考:

Android两种杀掉进程方式总结(System.exit()和Process.killProcess())    

System.exit和Process.killProcess

3、关闭Activity

  • finish ()方法:在你的activity结束或者应该被关闭时调用。ActivityResult将通过onActivityResult()方法传递给启动者。这是比较常用的关闭Activity的方法。
  • finishAffinity()方法:关闭该Activity和同一栈中的所有位于该Activity下面的Activity。比如说在同一Activity栈中,Activity A启动了Activity B,Activity B启动了Activity C。Activity B调用finishAffinity()方法,会关闭 Activity A和 Activity B,Activity C仍然存在。如果Activity C调用该方法,则A,B,C,都会被关闭,且如果应用只有这一个栈,那么C调用该方法会直接退出应用。注意:该方法在API level 16之后添加。
  • finishAndRemoveTask()方法:系统默认情况下finish、killProcess,应用窗口缩略图依然会保留在最近任务中。 此方法让Activity不显示在系统的最近任务列表中,按了HOME键之后,Activity是完全不显示在最近任务中,即使它还在运行。

Activity中的各种“finish()”方法

Android 判断锁屏,亮屏,解锁

广播接收器BroadcastReceiver,有点类似发布订阅。它监听的是设备的事件,当前app在后台运行时,也能监测到这些事件。

按锁屏按键是ActionScreenOff 此时锁屏,熄屏;

解锁与亮屏:

实际测试中发现,

1、输入密码/指纹时开启,可能时,解锁->亮屏【黑屏时指纹】 或者 亮屏->解锁【先亮着屏再解锁】

2、人脸识别开启,也可能时,解锁->亮屏【黑屏时对着人脸】 或者 亮屏->解锁【先亮着屏再对着人脸】

参考:

android 判断锁屏,亮屏,解锁。并给出一个使用例子

但是需要注意:注销(防止资源泄露)

【官方】Broadcast Receivers in Xamarin.Android

//定义
    public class LockScreenReceiver : BroadcastReceiver
    {
        public string ChangeRemark = "";
        public override void OnReceive(Context context, Intent intent)
        {
            if (intent != null)
            {
                if (intent.Action.Equals(Intent.ActionScreenOn))
                {
                    ChangeRemark = "亮屏";
                }
                else if (intent.Action.Equals(Intent.ActionScreenOff))
                {
                    ChangeRemark = "锁屏";
                }
                else if (intent.Action.Equals(Intent.ActionUserPresent))
                {
                    ChangeRemark = "解锁";
                }
                //MainApplication.getInstance().setChangeDesc(change);
            }
        }
    }

    //使用
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        private LockScreenReceiver mReceiver;
        private IntentFilter filter;

        protected override void OnCreate(Bundle bundle)
        {

            base.OnCreate(bundle);

            global::Xamarin.Forms.Forms.Init(this, bundle);

            mReceiver = new LockScreenReceiver();
            filter = new IntentFilter();
            filter.AddAction(Intent.ActionScreenOn);
            filter.AddAction(Intent.ActionScreenOff);
            filter.AddAction(Intent.ActionUserPresent);
            RegisterReceiver(mReceiver, filter);

            LoadApplication(new App());

        }
        protected override void OnDestroy()
        {
            base.OnDestroy();
            if (mReceiver != null)
                UnregisterReceiver(mReceiver);
        }
        protected override void OnResume()
        {
            if (mReceiver.ChangeRemark == "亮屏")
            {
            }
        }
    }
View Code

Android数据存储

Android 五种数据存储的方式分别为:
1. SharedPreferences:以Map形式存放简单的配置参数;
2. ContentProvider:将应用的私有数据提供给其他应用使用;
3. 文件存储:以IO流形式存放,可分为手机内部和手机外部(sd卡等)存储,可存放较大数据;
4. SQLite:轻量级、跨平台数据库,将所有数据都是存放在手机上的单一文件内,占用内存小;
5. 网络存储 :数据存储在服务器上,通过连接网络获取数据;

Sharedpreferences是Android平台上一个轻量级的存储类,用来保存应用程序的各种配置信息,其本质是一个以“键-值”对的方式保存数据的xml文件,其文件保存在/data/data//shared_prefs目录下。在应用中通常做一些简单数据的持久化缓存

在全局变量上看,其优点是不会产生Application 、 静态变量的OOM(out of memory)和空指针问题,其缺点是效率没有上面的两种方法高。
参考:Android数据存储五种方式总结

原文地址:https://www.cnblogs.com/peterYong/p/11730592.html