Android开发基础-四大组件之Activity

一、AndroidManifest.xml

Activity、Service、ContentProvider、BroadcastReceiver都需要在这里注册。


image
  • application中的android:supportsRtl属性

官网原文链接:android:supportsRtl

android:supportsRtl
Declares whether your application is willing to support right-to-left (RTL) layouts.
If set to true and targetSdkVersion is set to 17 or higher, various RTL APIs will be activated and used by the system so your app can display RTL layouts. If set to false or if targetSdkVersion is set to 16 or lower, the RTL APIs will be ignored or will have no effect and your app will behave the same regardless of the layout direction ass ociated to the user's Locale choice (your layouts will always be left-to-right)。

从Android 4.2开始,Android SDK支持一种从右到左(RTL,Right-to-Left)UI布局的方式,尽管这种布局方式经常被使用在诸如阿拉伯语、希伯来语等环境中,中国用户很少使用。不过在某些特殊用途中还是很方便的。

  • application中的android:allowBackup属性

何为allowBackup高危漏洞

Android属性allowBackup安全风险源于adb backup容许任何一个能够打开USB 调试开关的人从Android手机中复制应用数据到外设,一旦应用数据被备份之后,所有应用数据都可被用户读取;adb restore容许用户指定一个恢复的数据来源(即备份的应用数据)来恢复应用程序数据的创建。因此,当一个应用数据被备份之后,用户即可在其他Android手机或模拟器上安装同一个应用,以及通过恢复该备份的应用数据到该设备上,在该设备上打开该应用即可恢复到被备份的应用程序的状态。
尤其是通讯录应用,一旦应用程序支持备份和恢复功能,攻击者即可通过adb backup和adb restore进行恢复新安装的同一个应用来查看聊天记录等信息;对于支付金融类应用,攻击者可通过此来进行恶意支付、盗取存款等;因此为了安全起见,开发者务必将allowBackup标志值设置为false来关闭应用程序的备份和恢复功能,以免造成信息泄露和财产损失。

该漏洞的解决方案

1.将allowBackup 的值设置为false;(allowBackup的值为false 对项目运行没有任何影响)
2.通过手机设备的IMEI号来辨识来设备编号和备份前是否一致,不一致则直接跳转登陆页面的同时清空当前应用数据及缓存;

allowBackup为true时如何备份数据

1.打开控制台,输入adb backup -f back.ab -noapk 项目包名
2.输入密码,备份你的数据
3.在另一台设备中安装程序,在控制台输入adb restore back.ab,弹出下列界面,输入密码(如果前面一步你没设置密码就不需要输入密码)

  • application中的android:theme属性

这个标签用于控制样式,对应res文件夹下面的styles.xml文件。

二、Activity之间的跳转

1.显式意图实现界面跳转并传值

  • 实现跳转并传值的代码
Intent intent = new Intent(this, SecondActivity.class);
putExtra("account", accountText);
putExtra("password", passwordText);
startActivity(intent);
  • 接受传值activity中的代码
Intent intent = getIntent();
String account = intent.getStringExtra("account");
String password = intent.getStringExtra("password");

2.隐式意图实现界面跳转

  • androidmanifest中的代码
<activity android:name=".ThirdActivity">
  <intent-filter>
    <action android:name="com.example.LOGIN_INFO" />
    <category android:name="android.intent.category.DEFAULT" />  
  </intent-filter>
</activity>
  • 实现跳转的代码
Intent intent = new Intent();
intent.setAction("com.example.LOGIN_INFO");
intent.addCategory(intent.CATEGORY_DEFAULT);
startActivity(intent);
Action:该activity可以执行的动作

该标识用来说明这个activity可以执行哪些动作,所以当隐式intent传递过来action时,如果跟这里<intent-filter>所列出的任意一个匹配的话,就说明这个activity是可以完成这个intent的意图的,可以将它激活!

常用的Action如下所示:

ACTION_CALL activity 启动一个电话.
ACTION_EDIT activity 显示用户编辑的数据.
ACTION_MAIN activity 作为Task中第一个Activity启动
ACTION_SYNC activity 同步手机与数据服务器上的数据.
ACTION_BATTERY_LOW broadcast receiver 电池电量过低警告.
ACTION_HEADSET_PLUG broadcast receiver 插拔耳机警告
ACTION_SCREEN_ON broadcast receiver 屏幕变亮警告.
ACTION_TIMEZONE_CHANGED broadcast receiver 改变时区警告.

两条原则:

1.<intent-filter>元素至少应该包含一个<action>,否则任何Intent请求都不能和该<intent-filter>匹配。
2.如果Intent请求的Action和<intent-filter>中个任意一条<action>匹配,那么该Intent就可以激活该activity(前提是除了action的其它项也要通过)。
两条注意:
如果Intent请求或<intent-filter>中没有说明具体的Action类型,那么会出现下面两种情况。
1.如果<intent-filter>中没有包含任何Action类型,那么无论什么Intent请求都无法和这条<intent-filter>匹配。
2.反之,如果Intent请求中没有设定Action类型,那么只要<intent-filter>中包含有Action类型,这个Intent请求就将顺利地通过<intent-filter>的行为测试。

3.组件之间的数据传递

不要局限于Activity之间的数据传递,也就是说,这是组件与组件之间的数据传递,也适用于服务,广播接收者…也就是四大组件。
传递的数据主要分两大类:

  • 基本数据类型


    image

    传递方式看下图就懂了:


    image
  • 引用数据类型
    String不是基本数据类型,它是引用数据类型。能传递String因为它已经实现了序列化的接口。
    Bitmap也就是位图,位图对象也是实现了序列化的接口的。所以可以传位图对象,但是要注意的是它的大小 ,后面会讲到意图对象的传值的大小限制。
    那么要传递自定义类的对象,则需要把该类序列化。
    实现Parcelable也行,Serializable也行。后者是Java的,前者是google写的类。两者的不同是前者比较高效,它是写到内存里的,后者是写到持久化存储单元里的。
User user = intent.getParcelableExtra("userKey");
  • Intent封装数据的大小限制
    限制的大小为1M,这块其实是共享内存来的,也就是Blundle。

4.数据回传

这里主要是通过一个回调函数将第二个activity里的数据回传到第一个activity来做处理。

  • 跳转到第二个acitvity不是用startActivity,而是用startActivityForResult
  • 要复写onActivityResult方法,这里会有返回值
    主要代码如下:
    第一个activity:
private static final int sRequestCode = 1;
......
 /**
 * 充值按钮被点击,跳转到充值界面,然后进行充值。
 *
 * @param view
 */
 public void reCharge(View view) {
    Intent intent = new Intent(this, PayActivity.class);
    startActivityForResult(intent, sRequestCode);
}
//回调函数,通过resultCode来对不同情况做处理
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //在这里会返回充值界面返回的数据。
        if (requestCode == sRequestCode) {
            TextView resultText = (TextView) findViewById(R.id.result_text);
            //说明是我们请求的数据结果,对得上请求码
            //然后判断结果码,在支付界面 ,我们定义了-1为失败,1为成功。所以就有了:
            if (resultCode == -1) {
                //支付失败,可以是网络问题,也可以是取消充值
                resultText.setText("充值失败!如果遇到问题请联系客服!");
            } else if (requestCode == 1) {
                //充值成功,给出提示吧!
                resultText.setText("感谢您的支持!您已充值 :" + data.getStringExtra("charge") + "\n 您当前的余额是***");
            }
        }
    }

第二个acitivity中的代码:

    /**
     * 确定充值被点击了,这里提示充值成功,并且把充值的金额返回给前一个界面。
     *
     * @param view
     */
    public void confirmCharge(View view) {
        EditText chargeInput = this.findViewById(R.id.charge_input);
        //这里要对数字进行检查,对吧!
        String targetChargeText = chargeInput.getText().toString().trim();
        String reg = "/(^[1-9]([0-9]+)?(\\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\\.[0-9]([0-9])?$)/";
        if (TextUtils.isEmpty(targetChargeText)) {
            //没有输入内容
            Toast.makeText(this, "您没有输入充值金额!", Toast.LENGTH_SHORT).show();
        } else {
            //如果有输入,判断是否符合金额的格式
            boolean matches = Pattern.matches(reg, targetChargeText);
            if (matches) {
                //TODO:向网络提交数据,然后充值
                //等待返回结果再更新UI
                //这里合法的话,那我们就给出提示,并且把数据设置回去即可
                //把结果封装到Intent里
                Intent resultIntent = new Intent();
                resultIntent.putExtra("charge", targetChargeText);
                setResult(1);
                finish();
            } else {
                Toast.makeText(this, "您输入的金额不合法,请重新输入!", Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * 取消充值
     *
     * @param view
     */
    public void cancelCharge(View view) {
        //这个是取消充值
        setResult(-1);
        finish();
    }

5.跳转到第三方应用

首先判断有没有指定的应用

检测代码如下:

/**
* 检测
*
*/
public static void checkIsInstall(Context ctx, String packageName) {
  if ( !isAvilible( packageName , ctx ) ){
    //没有安装Apk
  }else {
    //已经安装了Apk
    Intent intent = new Intent();
    intent.setClassName(packageName, srcActivity);
    ctx.startActivity(intent);
  }
}
/**
 * 检查是否安装了某应用
*
* @param packageName 包名
* @return
*/
public static boolean isAvilible(String packageName, Context mContext) {
  final PackageManager packageManager = mContext.getPackageManager();
  // 获取所有已安装程序的包信息
  List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
  for (int i = 0; i < pinfo.size(); i++) {
    if (pinfo.get(i).packageName.equalsIgnoreCase(packageName))
      return true;
     }
  return false;
}

注意点

如果加了上面的内容,在 实现的过程中出现了如下的错误:

Caused by: java.lang.SecurityException: Permission Denial: starting Intent { cmp=tecsun.jx.yt.phone/.MainActivity } from ProcessRecord{44299e68 11892:com.example.administrator.linkyingtandemo/u0a85} (pid=11892, uid=10085) not exported from uid 10482

这个应该就是第三方的应用设置了跳转不许可(默认是允许):

android:exported="false"

显式意图跳转有两种方法可以实现

第一种:

Intent intent = new Intent();
intent.setClassName("com.android.browser", "com.android.browser.BrowserActivity");
startActivity(intent);

第二种:

Intent intent = new Intent();
ComponentName componentName=new ComponentName("com.android.browser", "com.android.browser.BrowserActivity");
intent.setComponent(componentName);
startActivity(intent);

隐式意图跳转也有两种情况

第一种不知道指定的Activity界面类名的情况下就需要跳转到指定的界面,需要隐式调用:
通过action和category来进行跳转指定的界面(这两个参数在应用API文档里面有标注 或者 可以直接网上找)

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("android.intent.action.SEARCH");
                intent.addCategory("android.intent.category.DEFAULT");
                intent.setPackage("com.android.browser");
            }
        });

第二种就是不需要跳转到指定的界面,只需要打开应用,而且只知道包名:

      button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = getPackageManager().getLaunchIntentForPackage("com.android.browser");
                startActivity(intent);
            }
        });

跳转到拨打电话的例子(隐式意图):

  • 普通写法:
Intent intent = new Intent();
intent.setAction("android.intent.action.CALL"); //等同于Intent.ACTION_CALL
intent.addCategory("android.intent.category.DEFAULT");  //等同于Intent.CATEGORY_DEFAULT
intent.setPackage("");
Uri uri = Uri.parse("tel:10086");
intent.setData(uri);

startActivity(intent);
  • 简化写法:
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:10086"));

startActivity(intent);

三、横竖屏切换Activity的配置

当切换横竖屏时,Activity会先销毁掉原来的生命周期,然后再重新跑一次。
解决这个问题的方法有两个:

1.修改配置文件,使该activity固定横屏或竖屏。

image

一般来说,游戏固定横屏的比较多

2.修改配置文件,忽略配置的变化。

  <activity android:name=".LandscapeActivity"
            android:configChanges="orientation|screenSize|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容