4-1-1 Activity的创建
- 新建类继承Activity或其子类
- 在AndroidManifest中声明
- 创建layout并在Activity的onCreate中设置
在AndroidManifest.xml里可设置
android:theme:设置主题样式
android:screenOrientation:用于控制activity启动时方向,一般设置竖屏或横屏显示
android:launchMode:设置启动模式,具体参考https://www.jianshu.com/p/404964d344d3
<intent-filter>:用于设置默认启动的Activity
4-1-2 Activity的生命周期
4-1-3 Activity的跳转和数据传递
1. 显示跳转和隐式跳转
各种跳转方式
//显示跳转1 Intent intent = new Intent(AActivity.this, BActivity.class); startActivity(intent); //显示跳转2 Intent intent = new Intent(); intent.setClass(AActivity.this, BActivity.class); startActivity(intent); //显示跳转3 Intent intent = new Intent(); intent.setClassName(AActivity.this, "com.example.hao.helloworld.jump.BActivity"); startActivity(intent); //显示跳转4 Intent intent = new Intent(); intent.setComponent(new ComponentName(AActivity.this, "com.example.hao.helloworld.jump.BActivity")); startActivity(intent); //隐式跳转 Intent intent = new Intent(); intent.setAction("com.example.test.BActivity"); startActivity(intent);
以上就是各种跳转方式,常用的也就第一种显示跳转1
其中隐式跳转中需要在AndroidManifest.xml里对要跳转的Activity设置<intent-filter>
<intent-filter> <action android:name="com.example.test.BActivity" />//这个就是要跳转的action名 <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
2.Activity之间的数据传递
通过intent.putExtra()来传递,但是查看源码发现,实质上是新建了一个Bundle()
public Intent putExtra(String name, boolean value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putBoolean(name, value);
return this;
}
至于Intent本身就可以传递参数(Intent.putExtra("key", value))但为什么要用Bundle,参考https://www.jianshu.com/p/e9db0797293b
AActivity传递数据:
Intent intent = new Intent(AActivity.this, BActivity.class); Bundle bundle = new Bundle(); bundle.putString("name","helloworld"); bundle.putInt("number",88); intent.putExtras(bundle); startActivity(intent);
BActivity接收数据:
Bundle bundle = getIntent().getExtras(); String name = bundle.getString("name"); int number = bundle.getInt("number");
3.startActivityForResult
如果想在Activity中得到新打开的Activity 关闭后返回的数据,则需要使用startActivityForResult(Intent intent, int requestCode)方法打开新的Activity,新的Activity 关闭后会向前面的Activity传回数据,为了得到传回的数据,必须在前面的Activity中重写onActivityResult(int requestCode, int resultCode, Intent data)方法。
传回数据同传出数据一样,也是通过Bundle来实现
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
ToastUtil.showMsg(AActivity.this, data.getExtras().getString("title"));
}
重写方法来接收传回来的数据,这里用的是自定义的封装的Toast
data.getExtras().getString()接收传回来的String
4-1-4 Activity的4种启动模式
android:launchMode属性
Activity是由任务栈管理的,每启动一个Activity,就会被放入栈中,按返回键,就会从栈顶移除一个Activity
- standard:标准模式,默认,每次启动Activity时(startActivity),都创建Activity实例,并放入任务栈;
- singleTop:Task栈顶复用模式,如果某个Activity自己激活自己,即任务栈栈顶就是该Activity,则不需要创建实例,其余情况都要创建Activity实例;
- singleTask:Task栈内复用模式,如果要激活的那个Activity在任务栈中存在实例,则不需要创建实例,只需要把此Activity放入栈顶,并把该Activity以上的Activity实例都pop;
- singleInstance:全局单例模式,相当于全局的实例,其他Activity若有该实例便可复用
AActivity和BActivity跳转实例,会输出实例相关信息
AActivity:
Log.d("AActivity","----onCreate----");
Log.d("AActivity","taskid:"+getTaskId()+" ,hash:"+hashCode());
logTaskName();
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("AActivity","----onNewIntent----");
Log.d("AActivity","taskid:"+getTaskId()+" ,hash:"+hashCode());
logTaskName();
}
private void logTaskName(){
try {
ActivityInfo info = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
Log.d("AActivity", info.taskAffinity);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
BActivity:
Log.d("BActivity","----onNewIntent----");
Log.d("BActivity","taskid:"+getTaskId()+" ,hash:"+hashCode());
logTaskName();
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("BActivity","----onNewIntent----");
Log.d("BActivity","taskid:"+getTaskId()+" ,hash:"+hashCode());
logTaskName();
}
private void logTaskName(){
try {
ActivityInfo info = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
Log.d("AActivity", info.taskAffinity);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
1.Standard
这是开启AActivity时输出的debug信息
点击跳转到AAcitvity(也就是跳转到本身),发现只有hashcode发生了改变,也就是重新创建了AActivty的实例
点击JUMP会跳转到BActivity,输出信息如下,发现也是只有hashcode发生变化,说明BActivity也是新建的实例
2.singleTop
当要启动的目标Activity已经位于栈顶,不会创建新的实例,会复用栈顶的Activity,并且其onNewIntent()方法会被调用,如果目标Activity不在栈顶,则跟standard一样创建新的实例
开启AAcitvity时输出的信息:
再点击跳转到AAcitvity输出的信息:
可以看到并未调用onCreate()方法,而是调用了onNewIntent()方法,复用了AActivity
再点击JUMP(跳转到BActivity)输出的信息:
新建了一个BActivity实例,以为BActivity不在栈顶
3.singleTask
在同一个任务栈中,如果要启动的目标Activity已经在栈中,则会复用该Acitvity,并调用其onNewIntent()方法,并且该Activity上面的Activity会被清除;如果栈中没有,则新建新实例
在AndroidManifest.xml对AActivity的taskName进行了设置:
android:launchMode="singleTask" android:taskAffinity="com.example.hao.helloworld.singletask"
启动AActivity时输出信息为:
再点击跳转到AAcitvity输出的信息:
可以看到很明显的复用了AActivity
再点击JUMP(跳转到BActivity)输出的信息:
发现新建了一个任务栈,id为10,name为:com.example.hao.helloworld
再从BActivity跳转回AActivity时AActivity输出的信息:
发现也是复用了AActivity
4.singleInstance(较少使用)
全局复用,不管哪个Task栈,只要存在目标Activity,就复用。每个Activity占有一个新的Task栈
4-2-1 Fragment详解(一)
创建一个主Actiity:ContainerActivity和两个Fragment:AFragmen和BFragment
然后avtivity_container.xml设置如下,一个按钮,一个Fragment
<Button android:id="@+id/btn_change" android:layout_width="match_parent" android:layout_height="50dp" android:text="更换Fragment"/> <FrameLayout android:id="@+id/fl_container" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/btn_change"> </FrameLayout>
Fragment组件将使用AFragment或BFragment
AFragment的布局文件如下(BFragment和AFragment一样):
<TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#000000" android:textSize="20sp" android:text="我是AFragment" android:gravity="center"/>
再在AFragment(BFragment也一样)绑定到layout
public class AFragment extends Fragment {
private TextView mTvTitle;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, container, false);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mTvTitle = (TextView) view.findViewById(R.id.tv_title);
}
}
在ContainerActivity添加Fragment
//实例化AFragment
aFragment = new AFragment();
//把AFragment添加到Activity,记得调用commit
getFragmentManager().beginTransaction().add(R.id.fl_container, aFragment).commitAllowingStateLoss();
使用Fragment时,可以通过用户交互来执行一些动作,比如增加、移除、替换等。所有这些改变构成一个集合,这个集合被叫做一个transaction。然后需要调用commit()方法,将这些变化应用。至于commit()和commitAllowingStateLoss()区别,需要自己了解
getFragmentManager().beginTransaction().replace(R.id.fl_container, bFragment).commitAllowingStateLoss();
replace是替换Fragment
4-2-2 Fragment详解(二)
1.getActivity()为null的问题
最好采用如下方法获取Activity
if(getActivity() != null){ // }else { }
2.向Fragment传递参数
在Fragment中设置如下:
public static AFragment newInstance(String title){
AFragment aFragment = new AFragment();
Bundle bundle = new Bundle();
bundle.putString("title", title);
aFragment.setArguments(bundle);
return aFragment;
}
至于为什么 要通过Bundle来传递参数,因为Activity重新创建时,会重新构建它所管理的Fragment,原先的Fragment的字段值将会全部丢失,但是通过Fragment.setArguments(Bundle bundle)方法设置的bundle会保留下来。
然后在onViewCreated中设置
mTvTitle = (TextView) view.findViewById(R.id.tv_title); if(getArguments() != null){ mTvTitle.setText(getArguments().getString("title")); }
最后在Activity中实例化Fragment时调用
aFragment = AFragment.newInstance("我是参数");