Activity相关知识点与应用

本文详细介绍了Android中Activity的管理方法、生命周期及其各种状态之间的转换。覆盖了Activity的启动模式、屏幕方向改变时的行为、Activity间的跳转及数据传递等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(1)ActivityCollector统一管理活动,可以一次性finish

publicclass ActivityCollector {

privatestatic List<Activity> activities=new ArrayList<Activity>();

publicstatic void addActivity(Activity activity){

activities.add(activity);

}

publicstatic void removeActivity(Activity activity){

activities.remove(activity);

}

publicstatic void finishAll(){

for(Activityactivity:activities){

if(!activity.isFinishing()){

activity.finish();

}

}

}

(2)判断当前Activity是从哪跳转过来的?

如果我需要根据intendC之前的活动是哪个来对应不同的两种C的界面。如何实现?

可以在IntentmIntent=new Intent(A.this,C.class);

Stringname=“A”;

mIntent.putExtra(“ActivityName”,name);

我们可以在Aintent中多添加一项String来标记是哪个活动。然后在C中获取到就可以区分处是从哪个活动传来的,并匹配使用对应的布局。

(3)空指针异常java.lang.NullPointerException

publicclassMainActivityextendsActionBarActivity {

ButtonmButton;

@Override

protectedvoidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mButton.setText("what");

}


}

编译时不报错,运行时会报空指针

原因是类在初始化的时候ButtonmButton;可以理解成ButtonmButton=null;

成员变量被初始化了。而null是一个引用类型。null这个类型是不具有setText()方法的,所以会报空指针异常

(4)Intent跳转多个Activity的试验。A跳到BB跳到C,finishB.C中按Back,是返回A还是重新CreateB?

A跳到BfinishA,B中按Back,重新createA?还是退出程序?

首先:A使用Intent到B

A执行onStop()方法,并未执行onDestroy(),当然资源紧张可能会被销毁

我们按back键执行的是ActivityonBackPressed()方法,源码如下

publicvoidonBackPressed() {

if(!mFragments.popBackStackImmediate()){

finish();

}

}

finish()就是销毁当前活动,活动对象从堆栈里出栈。

手机屏幕上显示的能与用户交互的活动永远是堆栈的栈顶元素。

其实Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动

的集合,这个栈也被称作返回栈(BackStack)。栈是一种后进先出的数据结构,在默认情况

,每当我们启动了一个新的活动,它会在返回栈中入栈,并处于栈顶的位置。而每当我们

按下Back键或调用finish()方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入

栈的活动就会重新处于栈顶的位置。系统总是会显示处于栈顶的活动给用户。

这样就好理解了。

活动的启动模式为standard情况下:

A跳到BB跳到C,finishB.C中按Back,是返回A还是重新CreateB?

返回B。

A跳到BfinishA,B中按Back,重新createA?还是退出程序?

退出程序。

(5)如何延迟启动Activity

准确的说,应该是如何延时执行任务。

方法1:

newThread(new Runnable(){

publicvoid run(){

try{

Thread.sleep(3000);

}

catch(InterruptedExceptione){

e.printStackTrace();

}

IntentmIntent=new Intent(MainActivity.this,SecAct.class);

startActivity(mIntent);

}

}).start();

方法二:

newTimmer.schedual(new TimerTask(){

publicvoid run(){

IntentmIntent=new Intent(MainActivity.this,SecAct.class);

startActivity(mIntent);

}

},3000);

方法三:

newHandler().postDelayed(new Runnable(){

publicvoid run(){
Intent mIntent=newIntent(MainActivity.this,SecAct.class);

startActivity(mIntent);

}

,3000);

(6)异常情况下的Activity的生命周期变化

如当前设备的configuration(配置,一般指屏幕旋转)发生改变从而导致Activity被销毁重建。

OnStart(),onStop()是从活动是否可见的角度。你可以理解成onStart()调用后,Activity就可见了。

OnResume(),onPause()是从活动是否位于前台可以交互的角度。

ActivityA中条跳转到ActivityB中时,先执行A的onPause(),后执行B的onResume().

准确的是:

AonPause()—BonCreate()—BonStart()—BonResume()—AonStop()

A不可交互但可见,B创建,B可见,B可交互,A不可见

通过分析,可以知道onPause()onStop()都不能执行耗时的操作,尤其是onPause(),所以我们应当尽量在onStop()中操作。

Land:landscape横屏

port:portrait竖屏

情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建

默认情况下,我们的Activity不做特殊处理。

Activity会被销毁,调用onPause,onStop,onDestroy,还会调用onSaveInstanceState(Bundle).

onSaveInstanceState(Bundle)该方法一定执行在onStop之前,但与onPause执行顺序先后不定,有可能在它之前也可能在它之后。
这个方法只会出现在Activity被异常终止的情况下,正常情况下系统不会回调这个方法。

Activity被重新创建后,系统会调用onRestoreInstanceState(Bundle).

所以当我们自己想要异常情况下存储一些数据时,可以在onSaveInstanceState中存,在onRestoreInstanceState中取。

onSaveInstanceState源码中可以看到,它让顶层容器一层层的往下,去通知它的子元素来保存数据,有点像事件分发。会调用ViewonSaveInstanceState,View同样有onRestoreInstanceState,在调用了ActivityonRestoreInstanceState时调用。

下面是ActivityonSaveInstanceState.

protectedvoidonSaveInstanceState(Bundle outState) {

outState.putBundle(WINDOW_HIERARCHY_TAG,mWindow.saveHierarchyState());

Parcelablep = mFragments.saveAllState();

if(p != null){

outState.putParcelable(FRAGMENTS_TAG,p);

}

getApplication().dispatchActivitySaveInstanceState(this,outState);

}


每种View组件的onSaveInstanceStateonRestoreInstanceState可能不同,要去看源码,比如TextView就可以保存和恢复自己的文本选中状态和文本内容。

情况2:资源内存不足导致低优先级的Activity被杀死

这种情况我们不好模拟,但是其数据存储和恢复过程和情况1完全一致。


如何让系统配置发生改变后,不重新创建Activity

AndroidManifest.xml中的Activtiy中设置android:configChanges=”orientation|screenSize”

还有locale:指的是设备的本地位置发生了改变,一般指切换了系统语言。

minSdkVersiontargetSdkVersion有一个大于13时,就必须加上screenSize(旋转屏幕导致屏幕尺寸变化)

这样处理后,Activity没有重新创建,并且没有调用onSaveInstanceStateonRestoreInstanceState两个方法,取而代之的是调用了ActivityonConfigurationChanged(Configuration)方法。这个时候我们就可以在这个方法中做一些特殊处理了。

(7)ActivityLaunchMode活动的启动模式

AndroidManifest.xml<activity></activity>中设置的android:launchMode=”xxx”来设置

xxx可以为standard,singleTop,singleTask,singleInstance

每个应用一般对应一个Activity的返回栈。(注意理解这句话)

(8)Activity如何锁定横屏,竖屏

AndroidManifest.xml<activity></activity>中设置的android:screenOrientation=”xxx”来设置

xxx默认是unspecified(未指明的)

横屏就xxx设置为landscape

竖屏就xxx设置为portrait

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE););//强制为横屏

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏

(9)下拉状态栏,当前Activity并不会调用onPause()方法。(实测过)

那么我们在onResume()去更新ui实际是没生效的。那么如何让Activity中的ui随着下拉栏的设置的变化同步更新呢?

比如我们当前Activity有个Switch代表wifi是否打开,我们进行以下操作,下拉状态栏,然后打开wifi,然后状态栏上去后,发现当前ActivitySwitchCheck状态并没有改变。

解决方法1

去系统源码,也就是状态栏那里的点击事件里面去发送一个广播,然后在当前Activity里面注册个广播(内部类)接收就行了。可以先确认下系统本身是否有系统广播(当wlan状态和蓝牙状态改变的时候)。

这种方法的弊端在于,如果我是做apk的,不是做系统的。系统源码没法修改的话,这种方法就行不通了。

优点在于:百分百的正确。假设系统很卡,我下拉状态栏,点击wifi按钮,此时没生效,我回到当前Activity,调用了onWindowFocusChanged方法,获取到wifi状态(此时还没生效,所以还是关闭),更新ui一次。ui显示状态为关闭。过了一会,之前在下拉状态栏的状态生效了,然而当前Activity依然显示的还是关闭状态,这就是bug了。(veryimportant

蓝牙开关:intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);

wifi(wlan)开关:intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);

注意要AndroidManifest.xml中要添加权限。

解决方法2

api18也就是4.3了。这个方法实测是有效的。

public void onWindowFocusChanged(boolean focus){
}
From API 18 you can use this code directly in your Fragment:
final ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
viewTreeObserver.addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
    @Override
    public void onWindowFocusChanged(final boolean hasFocus) {
        // do your stuff here
    }
});
Where you can get the view in onViewCreated or simply call getView() from everywhere.

解决方法3

低于这以下的版本暂时没啥好办法,只有在Activity里面去写,先在这个方法里面获取到Fragment方法,然后去调用Fragment的方法。当然,如果Fragment较多要这么处理的话,可以让他们实现接口(自己写一个)。这样写就是多态。

accepted
You can either create an interface and all your fragments implement this interface, and inside your onWindowFocusChanged you get the current fragment and pass call the method provided by the interface.
A sample interface for the fragments could be:
public interface IOnFocusListenable {
   public void onWindowFocusChanged(boolean hasFocus);
}
Your fragments have to implement this interface:
public class MyFragment implement IOnFocusListenable {
    ....
    public void onWindowFocusChanged(boolean hasFocus) {
        ...
    }
}
And in the onWindowFocusChanged of your Activity you can then do the following:
public class MyActivity extends AppCompatActivity {
   @Override
   public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);


        if(currentFragment instanceOf IOnFocusListenable) {
            ((IOnFocusListenable) currentFragment).onWindowFocusChanged(hasFocus);
        }
    }
}

(10)直接杀掉进程的时候是不会调用ActivityonDestroy()等方法的
问题:是否会调用其它的方法?应该是会的,印象里异常关闭会调用一个方法?
比如我启动一个Activity,执行onCreate(),onStart(),onResume().此时Activity在前台可见,我在系统中,adb
shell ,ps |grep xxx,kill xxx;
实测是不会继续执行onPause(),onStop(),onDestory()的。
如果我是在手机操作中先点home键(此时执行onPause(),onStop()),调出应用程序管理,然后杀掉它。并不会执行onDestory().

(11)Activity常用方法

抛开7大方法不说(onCreate,onStart,onResume,onPause,onStop,onRestart,onDestory

onPostCreate()

onPostResume()

onWindowFocusChanged()

onActivityResult()

onSaveInstanceState()

onRestoreInstanceState()

onConfigurationChanged()

onAttachedToWindow()

onDetachedFromWindow()

(12)Acitivityfinish():是直接执行onDestroy()还是onPause(),onStop(),onDestory().

结果和Activity已经执行到的位置有关。

如果finish()直接写在onCreate(),那么只调用onDestory();

如果写在onStart()中,那么调用onStop(),onDestory();

如果写在onResume()中,那么调用onPause(),onStop(),onDestory();

所以与Activity当前所在的生命周期有关系。

(13)ActivityonCreate()中多次调用view.invalidate()是否生效

实测并不会调用viewonDraw().onResume后第一次调用onDraw()(因为加载layout布局).

如果view.invalidate()是在onResume()前执行的话。无论多少次实际是不生效的。

只有在执行onResume后,Activity可视化后(比如放在按钮监听中,只有onResume,可视化后你才能看到btn,所以点击后执行invalidate是在onResume调用invalidate().才会去多次执行onDraw().

(14)AcitivityonNewIntent()方法。

android:launchMode="singleTask"模式下,这个方法才会在合适的时机调用。

如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。

大家遇到一个应用的Activity供多种方式调用启动的情况,多个调用希望只有一个Activity的实例存在,这就需要ActivityonNewIntent(Intentintent)方法了。只要在Activity中加入自己的onNewIntent(intent)的实现加上Manifest中对Activity设置lanuchMode=“singleTask”就可以。

onNewIntent()非常好用,Activity第一启动的时候执行onCreate()---->onStart()---->onResume()等后续生命周期函数,也就时说第一次启动Activity并不会执行到onNewIntent().而后面如果再有想启动Activity的时候,那就是执行onNewIntent()---->onResart()------>onStart()----->onResume().如果android系统由于内存不足把已存在Activity释放掉了,那么再次调用的时候会重新启动Activity即执行onCreate()---->onStart()---->onResume()等。

当调用到onNewIntent(intent)的时候,需要在onNewIntent()中使用setIntent(intent)赋值给ActivityIntent.否则,后续的getIntent()都是得到老的Intent

publicvoid onNewIntent(Intent newIntent) {

super.onNewIntent(newIntent);

setIntent(newIntent);//必须要有

//dosomething

}

(15)ActivityreCreate()方法

3.0以后才有的。

可以使用在日间/夜间模式的切换


可以看到这里调用recreate方法会比正常启动Activity多调用了onSaveInstanceStateonRestoreInstanceState,并且onSaveInstanceStateonCreate方法之前调用。

if(savedInstanceState != null) {

mTheme= savedInstanceState.getInt(THEME);

switchTheme(mTheme);

}

这部分代码要在setContentView(R.layout.activity_main)代码之前调用,否则改变不了主题


(16)Activity设置进入,退出动画

TweenAnimation

Intentintent=newIntent(this,SecondActivity.class);

startActivity(intent);

overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);

publicvoidoverridePendingTransition(intenterAnim,intexitAnim) {}

对于一个Activity,它有进入动画和退出动画两个。

(17)ActivityA跳转到ActivityBActivityB跳转到ActivityC.希望C中按下back键后,直接跳转到A.

ActivityB中代码如下设置:

startActivity(intent);

finish();//多加上finish即可。

finishActivityB即可。

(18)ActivityA跳转B,B返回给A数据

startActivityForResult(intent);

A里面要重写onActivityResult()方法。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值