一、排坑
显式意图跳转闪退
应用间不要用显式意图
Activity直接返回到主Activity时闪退
onActivityResult内加入resultcode判断
protected void onActivityResult(int requestCode, int resultCode, Intent data) {// TODO Auto-generated method stubsuper.onActivityResult(requestCode, resultCode, data);if (resultCode != 1 && resultCode != 2) {return;}String name = data.getStringExtra("name");if(requestCode == 10){EditText et = (EditText)findViewById(R.id.et);et.setText(name);}else if(requestCode == 20){EditText et_content = (EditText)findViewById(R.id.et_content);et_content.setText(name);}}
二、Activity跳转
Activity的跳转需要创建Intent对象,通过设置intent对象的参数指定要跳转Activity
通过设置Activity的包名和类名实现跳转,称为显式意图
通过指定动作实现跳转,称为隐式意图
显式意图
跳转至同一项目下的另一个Activity,直接指定该Activity的字节码即可
跳转至其他应用中的Activity,需要指定该应用的包名和该Activity的类名
隐式意图
要让一个Activity可以被隐式启动,需要在清单文件的activity节点中设置intent-filter子节点
<intent-filter > <action android:name="com.itheima.second"/> <data android:scheme="asd" android:mimeType="aa/bb"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter>
action 指定动作(可以自定义,可以使用系统自带的)
data 指定数据(操作什么内容)
category 类别 (默认类别,机顶盒,车载电脑)
隐式意图启动Activity,需要为intent设置以上三个属性,且值必须与该Activity在清单文件中对三个属性的定义匹配
intent-filter节点及其子节点都可以同时定义多个,隐式启动时只需与任意一个匹配即可
显式意图和隐式意图的应用场景
显式意图用于启动同一应用中的Activity
隐式意图用于启动不同应用中的Activity
如果系统中存在多个Activity的intent-filter同时与你的intent匹配,那么系统会显示一个对话框,列出所有匹配的Activity,由用户选择启动哪一个
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);if (ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.CALL_PHONE)!= PackageManager.PERMISSION_GRANTED){//申请权限ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CALL_PHONE},1);}else {//把动作告诉系统//send(); }}/*** 跳转至打电话activity* 跳转至其他应用的activity* 隐式跳转:通过指定action和data* @param v*/public void click1(View v){Intent intent = new Intent();//隐式意图 intent.setAction(Intent.ACTION_CALL);intent.setData(Uri.parse("tel:110"));//跳转 startActivity(intent);}/*** 跳转至secondActivity* 在本应用中跳转* 显示跳转:直接指定目标Activity的包名和类名* @param v*/public void click2(View v){Intent intent = new Intent();//cls:直接指定目标Activity的类名//显示意图intent.setClass(this, SecondActivity.class);startActivity(intent);}/*** 显示跳转至拨号器*///bug!!!public void click3(View v){Intent intent = new Intent();//指定目标Activity的包名和类名intent.setClassName("com.android.dialer", "com.android.dialer.DialtactsActivity");startActivity(intent);}/*** 隐式跳转至拨号器*/public void click4(View v){Intent intent = new Intent();//隐式设置拨号器的动作 intent.setAction(Intent.ACTION_DIAL);startActivity(intent);}/*** 隐式跳转至secondActivity* @param v*/public void click5(View v){Intent intent = new Intent();intent.setAction("com.itheima.sa2"); // intent.setData(Uri.parse("heima2:qwe")); // intent.setType("text/username"); // intent.setData(Uri.parse("heima2:qwe123")); intent.setDataAndType(Uri.parse("heima2:qwe123"), "text/username");//系统会自动添加默认的category intent.addCategory(Intent.CATEGORY_DEFAULT);startActivity(intent);}/*** 显式跳转至浏览器*///bug!!!public void click6(View v){Intent intent = new Intent();intent.setClassName("com.android.browser", "com.android.browser.BrowserActivity");startActivity(intent);}/*** 隐式跳转至浏览器* @param v*/public void click7(View v){Intent intent = new Intent();intent.setAction(Intent.ACTION_VIEW);intent.setData(Uri.parse("http://www.baidu.com"));startActivity(intent);} }
public class SecondActivity extends Activity {private static final String TAG = "SecondActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_second);//获取到启动这个activity的意图Intent intent = getIntent();Uri uri = intent.getData();if(uri!=null)Log.e(TAG, uri.toString());} }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.index42.createactivity"> <uses-permission android:name="android.permission.CALL_PHONE"/><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"android:icon="@drawable/photo2"android:label="主界面"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:name=".SecondActivity"android:icon="@drawable/photo3"android:label="第二个界面"><intent-filter ><action android:name="com.itheima.sa"/><action android:name="com.itheima.sa3"/><data android:scheme="heima"/><data android:scheme="heima3"/><category android:name="android.intent.category.DEFAULT"/></intent-filter><intent-filter ><action android:name="com.itheima.sa2"/><data android:scheme="heima2" android:mimeType="text/username"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></activity></application></manifest>
跳转时的数据传递
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){Intent intent = new Intent(this, SecondActivity.class);//把数据封装至intent对象中 // intent.putExtra("malename", "李志"); // intent.putExtra("femalename", "芙蓉姐姐");//把数据封装至bundle对象中Bundle bundle = new Bundle();bundle.putString("malename", "李志");bundle.putString("femalename", "芙蓉姐姐");//把bundle对象封装至intent对象中 intent.putExtras(bundle);startActivity(intent);} }
public class SecondActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Intent intent = getIntent();//从intent对象中把封装好的数据取出来 // String maleName = intent.getStringExtra("malename"); // String feMaleName = intent.getStringExtra("femalename"); Bundle bundle = intent.getExtras();String maleName = bundle.getString("malename");String feMaleName = bundle.getString("femalename");Random rd = new Random();int yinyuan = rd.nextInt(100);TextView tv = (TextView) findViewById(R.id.tv);tv.setText(maleName + "和" + feMaleName + "的姻缘值为" + yinyuan);} }
三、Activity生命周期
void onCreate()
- Activity已经被创建完毕
void onStart()
- Activity已经显示在屏幕,但没有得到焦点
void onResume()
- Activity得到焦点,可以与用户交互
void onPause()
- Activity失去焦点,无法再与用户交互,但依然可见
void onStop()
- Activity不可见,进入后台
void onDestroy()
- Activity被销毁
void onRestart()
- Activity从不可见变成可见时会执行此方法
使用场景
- Activity创建时需要初始化资源,销毁时需要释放资源;或者播放器应用,在界面进入后台时需要自动暂停
完整生命周期(entire lifetime)
onCreate-->onStart-->onResume-->onPause-->onStop-->onDestory
可视生命周期(visible lifetime)
onStart-->onResume-->onPause-->onStop
前台生命周期(foreground lifetime)
onResume-->onPause
四、Activity的四种启动模式
每个应用会有一个Activity任务栈,存放已启动的Activity
Activity的启动模式,修改任务栈的排列情况
- standard 标准启动模式
- singleTop 单一顶部模式
- 如果任务栈的栈顶存在这个要开启的activity,不会重新的创建activity,而是复用已经存在的activity。保证栈顶如果存在,不会重复创建。
- 应用场景:浏览器的书签
-
singeTask 单一任务栈,在当前任务栈里面只能有一个实例存在
- 当开启activity的时候,就去检查在任务栈里面是否有实例已经存在,如果有实例存在就复用这个已经存在的activity,并且把这个activity上面的所有的别的activity都清空,复用这个已经存在的activity。保证整个任务栈里面只有一个实例存在
- 应用场景:浏览器的activity
- 如果一个activity的创建需要占用大量的系统资源(cpu,内存)一般配置这个activity为singletask的启动模式。webkit内核 c代码
-
singleInstance启动模式非常特殊, activity会运行在自己的任务栈里面,并且这个任务栈里面只有一个实例存在
- 如果你要保证一个activity在整个手机操作系统里面只有一个实例存在,使用singleInstance
- 应用场景: 电话拨打界面
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.index42.lifecycle"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:launchMode="singleInstance"android:name=".SecondActivity"></activity></application></manifest>
五、横竖屏切换
默认情况下 ,横竖屏切换, 销毁当前的activity,重新创建一个新的activity
在一些特殊的应用程序场景下,比如游戏,不希望横竖屏切换activity被销毁重新创建
需求:禁用掉横竖屏切换的生命周期
始终横屏,可180度旋转
public class MainActivity extends Activity {private static final String TAG = "MainActivity";private SreenOrientationListener mSreenOrientationListener;int blood;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.e(TAG, "main:create" );//设置当前Activity的方向,使用代码控制横竖屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);mSreenOrientationListener = new SreenOrientationListener(this);blood = 100;}class SreenOrientationListener extends OrientationEventListener {public SreenOrientationListener(Context context) {super(context);}@Overridepublic void onOrientationChanged(int orientation) {if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {return; // 手机平放时,检测不到有效的角度 }// 只检测是否有四个角度的改变if (orientation > 350 || orientation < 10) {// 0度:手机默认竖屏状态(home键在正下方)orientation = 0;setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);Log.e("orientation", "orientation" + orientation);} else if (orientation > 80 && orientation < 100) {// 90度:手机顺时针旋转90度横屏(home建在左侧) setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);Log.e("orientation", "orientation" + orientation);} else if (orientation > 170 && orientation < 190) {// 手机顺时针旋转180度竖屏(home键在上方)orientation = 180;setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);Log.e("orientation", "orientation" + orientation);} else if (orientation > 260 && orientation < 280) {// 手机顺时针旋转270度横屏,(home键在右侧) setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);Log.e("orientation", "orientation" + orientation);}}}@Overrideprotected void onStart() {// TODO Auto-generated method stubsuper.onStart();System.out.println("main:start");}@Overrideprotected void onResume() {// TODO Auto-generated method stubsuper.onResume();mSreenOrientationListener.enable();System.out.println("main:resume");};@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.onPause();mSreenOrientationListener.disable();System.out.println("main:pause");}@Overrideprotected void onStop() {// TODO Auto-generated method stubsuper.onStop();System.out.println("main:stop");}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();System.out.println("main:destroy");};@Overrideprotected void onRestart() {// TODO Auto-generated method stubsuper.onRestart();System.out.println("main:restart");}public void click(View v){Intent intent = new Intent(this, SecondActivity.class);startActivity(intent);} }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.index42.lifecycle"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"android:configChanges="orientation|keyboardHidden|screenSize"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activityandroid:name=".SecondActivity"></activity></application></manifest>
六、Activity跳转返回值
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View c){//跳转至选择联系人ActivityIntent intent = new Intent(this, ContactActivity.class); // startActivity(intent);//用这个api启动的Activity,在销毁时,系统会回调onActivityResultstartActivityForResult(intent, 10);}public void click2(View v){//跳转至选择快捷回复的ActivityIntent intent = new Intent(this, CallbackActivity.class);startActivityForResult(intent, 20);}//如果有Activity在销毁时返回了数据,那么就会调用此方法来接收数据//requestCode:用来区分数据来自于哪一个Activity//resultCode:用来区分返回的数据是什么类型的 @Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// TODO Auto-generated method stubsuper.onActivityResult(requestCode, resultCode, data);if (resultCode != 1 && resultCode != 2) {return;}String name = data.getStringExtra("name");if(requestCode == 10){EditText et = (EditText)findViewById(R.id.et);et.setText(name);}else if(requestCode == 20){EditText et_content = (EditText)findViewById(R.id.et_content);et_content.setText(name);}} }
public class ContactActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_contact);ListView lv = (ListView) findViewById(R.id.lv);final String[] objects = new String[]{"小志","逼哥","世界级XXX","国服第一"};lv.setAdapter(new ArrayAdapter<String>(this, R.layout.item_listview, R.id.tv, objects));//给listview设置条目的点击侦听lv.setOnItemClickListener(new OnItemClickListener() {//当某个条目被点击时,此方法调用 @Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {//Activity返回时传递数据,也是通过意图对象Intent data = new Intent();//把要传递的数据封装至意图对象中data.putExtra("name", objects[position]);//当前Activity销毁时,data这个意图就会传递给启动当前Activity的那个ActivitysetResult(1, data);//销毁当前Activity finish();}});} }
public class CallbackActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_contact);ListView lv = (ListView) findViewById(R.id.lv);final String[] objects = new String[]{"免谈,没戏,滚犊子","媳妇我错了,求原谅","老子才是一家之主"};lv.setAdapter(new ArrayAdapter<String>(this, R.layout.item_listview, R.id.tv, objects));lv.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {Intent data = new Intent();data.putExtra("name", objects[position]);setResult(2, data);finish();}});}}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" android:orientation="vertical"><LinearLayout android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><EditTextandroid:id="@+id/et"android:layout_weight="1"android:layout_width="0dp"android:layout_height="wrap_content"android:hint="请输入联系人"/><Button android:layout_weight="0"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="+"android:onClick="click"/></LinearLayout><EditTextandroid:id="@+id/et_content"android:layout_weight="1"android:layout_width="match_parent"android:layout_height="0dp"android:hint="请输入短信内容"android:gravity="top"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="快捷回复"android:onClick="click2"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发送短信"/> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><TextView android:id="@+id/tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="20sp"/> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><ListView android:id="@+id/lv"android:layout_width="match_parent"android:layout_height="match_parent"></ListView> </LinearLayout>