Android四大组件之一——Activity123

Android四大组件之Activity123

Activity是Android最重要也是最常用的组件

一、Activity基本知识

  • Activity的生命周期

显示状态:onCreate,onStart,onResume

隐藏状态:onPause,onStop

销毁状态:onDestroy

当启动应用时会有如下方法得到执行onCreate-->onStart-->onResume

onStart是可见但不可交互状态

onResume是可见且可交互状态


当点击Back键时会调用onPause-->onStop-->onDestroy(一个Activity从创建到销毁的全过程,onRestart另说)

onPause是不可交互但可见状态

onStop是不可见且不可交互状态



通过Intent启动另一个Activity观察生命周期


需要注意的是点击button后首先执行的是onPause方法,然后创建另一个Activity,当SecondActivity可见时再执行MainActivity的onStop方法。

点击Back键后同理先执行onPause方法,回到MainActivity,因为MainActivity已经有实例,所以执行onRestart方法替代onCreate,之后依然类似,onStart-->onResume,以及SecondActivity的onStop-->onDestroy。



为什么只是先暂停当前Activity,而不是跳转Activity后再执行onPause-->onStop,或者先onPause-->onStop,然后再创建跳转Activity?

1)如果当前的应用是音乐播放器,当有电话打来时,当前的Activity在接听页面显示之前都不会暂停,不符合交互逻辑。

2)同样的例子,电话页面未显示而当前Activity已经stop,则会出现不可见的黑屏状态,直到接听页面创建并显示完成。


Activity横竖屏切换的生命周期

切换横竖屏时会将当前Activity按正常流程Destroy,然后重新创建Activity



切换横竖屏时,如果有输入框之类的控件,则需要保存竖屏时的状态,比如说有输入框之类的控件而且已经有输入内容,此时切到横屏不应该丢失数据,因此需要调用onSaveInstanceState保存状态信息。在onCerate方法中进行判断参数savedInstanceState是否为空

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        if (savedInstanceState != null) {
            Log.i("tag", "MainActivity" + savedInstanceState.getString("libo"));
        }
        Log.i("tag", "MainActivity onCreate");
        button = (Button) findViewById(R.id.button1);
        button.setOnClickListener(this);
    }
    
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.i("tag", "MainActivity onSaveInstanceState");
        outState.putString("libo", "abc");
    }

Activity生命周期的应用——音乐播放

onDestroy方法常用作释放资源

private MediaPlayer mediaPlayer;
private int position;

//在onCreate方法中初始化
mediaPlayer = MediaPlayer.create(this, R.raw.ifyou);
mediaPlayer.start();

//在onPause方法中暂停MediaPlayer,并记录播放进度
@Override
protected void onPause() {
   super.onPause();
   Log.i("tag", "MainActivity onPause");
   if (mediaPlayer.isPlaying()) {
     mediaPlayer.pause();
     position = mediaPlayer.getCurrentPosition();
     Log.i("tag", position+"");
   }
}
    
//在onResume方法中读取进度播放
@Override
protected void onResume() {
   super.onResume();
   Log.i("tag", "MainActivity onResume");
   if (position != 0) {
     mediaPlayer.seekTo(position);
     Log.i("tag", position+"");
     mediaPlayer.start();
   }
}

//在onDestroy方法中进行资源的释放
@Override
protected void onDestroy() {
    super.onDestroy();
     Log.i("tag", "MainActivity onDestroy");
     if (mediaPlayer != null) {
       mediaPlayer.release();
       mediaPlayer = null;
     }
}

  • Activity之间的启动方式

显式启动

Intent是Android程序中各组件之间进行交互的一种重要方式,不仅可以指明当前组件想要执行的动作,还可以在不同的组件之间传递数据。一般可被用于启动Activity,启动Service,以及发送广播等。

通过构造Intent,指定需要跳转的Activity。

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);
startActivity(intent);

隐式启动

为将要启动的Activity添加一个Intent过滤器,并指定action标签,指明当前Activity可以响应"libo"这个action。category标签默认为 android.intent.category.DEFAULT,更精确的指明了当前Activity能够响应带有category的Intent。action和category标签内容同时匹配时,这个Activity才能响应。当 category为默认时,可以省略 intent.addCategory() 方法。

        <activity android:name="com.example.activity.FourthActivity">
            <intent-filter >
                <action android:name="libo"/>
                <category android:name="android.intent.category.DEFAULT"/> 
            </intent-filter>
        </activity>

Intent intent = new Intent();
intent.setAction("libo");
startActivity(intent);
隐式启动多用于启动没有源文件的Activity,比如系统的浏览器,拨号,短信等

//打开网页
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.parse("http://www.qq.com");
intent.setData(uri);
startActivity(intent);
//打开图库
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivity(intent);
//发送短信
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, "hello csdn");
startActivity(intent);
//拨号
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.parse("tel:666666");
intent.setData(uri);
startActivity(intent);

以上系统应用可以被调用,网页通过setData方法指定Intent操作的数据。另外,还可以通过Intent-Filter配置Data标签,更精确的指定当前活动可以响应什么类型的操作。

Data标签可以配置如下内容:

1.android:scheme 用于指定数据的协议部分,例如http、geo地理位置、tel拨打电话

2.android:host 用于指定数据的主机名部分,例如www.qq.com

3.android:port 用于指定数据的断口部分,一般紧随主机名之后

4.android:path 用指定主机名和端口之后的部分

5.android:mimeType 用于指定可以处理的数据类型。

更多系统的action可以查阅官方文档

  • Activity之间的数据传递

向下一个活动传递数据

通过Intent启动另一个Activity时,可以利用Intent携带一定量的具体数据。

具体方法为putExrta。通过键值对的方式。可以传递常用的8种类型及数组,String,int,double等

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);
		intent.putExtra("name", "libo");
		intent.putExtra("age", 21);
		startActivity(intent);
在被启动的Activity中需要先进行getintent,获取启动Intent,然后通过getStringExtra等的函数取出数据

Intent intent = getIntent();
		if (intent != null) {
			text.setText(intent.getStringExtra("name") + " " + intent.getIntExtra("age", 0));
		}

也可以通过Bundle先进行封装,再通过Intent传递

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);
		Bundle bundle = new Bundle();
		bundle.putString("name", "libo");
		bundle.putInt("age", 21);
		intent.putExtras(bundle);
		startActivity(intent);
Bundle也可以用于封装对象实例进行传递,不过对象须实现Serializable接口进行序列化(序列化是Java IO中的知识)
public class Person implements Serializable {
	
	private String name;
	private int age;
	private String address;
	
	public Person(String name, int age, String address){
		this.name = name;
		this.age = age;
		this.address = address;
	}
	
	@Override
	public String toString() {
		return "name: " + name + "age: " + age + "address: " + address;
	}
}

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);
		Person person = new Person("libo", 21, "xian");
		Bundle bundle = new Bundle();
		bundle.putSerializable("person", person);
		intent.putExtras(bundle);
		startActivity(intent);

Intent intent = getIntent();
		if (intent != null) {
			Person person = (Person) intent.getSerializableExtra("person");
			text.setText(person.toString());
		}
Bundle也可以用于传递图片,但大小不能过大,上限约为0.5M

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);
		Bundle bundle = new Bundle();
		Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
		bundle.putParcelable("bitmap", bitmap);
		intent.putExtras(bundle);
		startActivity(intent);

img.setImageBitmap((Bitmap) intent.getParcelableExtra("bitmap"));
当Bundle携带数据量过大时会抛出如下错误
!!! FAILED BINDER TRANSACTION !!!
如果需要在另一个Activity中使用本Activity的一些比较大的数据,可以考虑SQLite,或者文件

返回数据给上一个活动

此时启动Activity的方法不是startActivity而是startActivityForResult(Intent intent, int requestCode),request只要保证是唯一值就可以。

Intent intent = new Intent(MainActivity.this, FirstActivity.class);
		startActivityForResult(intent, 1);
@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		switch (requestCode) {
		case 1:
			if (resultCode == RESULT_OK) {
				String str = data.getStringExtra("first");
				text.setText(str);
			}
			break;

		default:
			break;
		}
	}
Intent intent = new Intent();
		intent.putExtra("first", "libo");
		setResult(RESULT_OK, intent);
		finish();

  • Activity的启动模式( launchMode)

standard

默认是模式,可以创建条件允许的任意多个

singleTop

如果再次创建的Activity在栈顶,那么就不会再重新创建新Activity,而是执行onNewIntent方法

如果不在栈顶,则跟默认模式相同,还是会再创建新的Activity

singleTask

MainActivity->Activity->MainActivity(MainActivity默认,Activity singleTask),如果此时再启动Activity则会执行第二个MainActivity的onDestroy方法,即在任务栈中进行出栈,直到Activity处于栈顶。

singleInstance

启动Activity时会处于不同的任务栈中

Main1->First->Main2->First->Main3(Main默认模式,First singleInstance),First被启动两次但是只执行一次onCreate方法并创建一个新的任务栈,其余均为onNewIntent方法。

当First启动Main2时,因为是默认模式,则会寻找Task1,并创建Activity,Main3同样,此时显示的是Main3,单击Back键时会返回到Main2,Main1,最后才是First。

Back会先把此栈中的Activity全部出栈,再把Task2中的Activity出栈。

  • 启动活动的最佳写法

启动不是由自己开发的一个Activity,不清楚该Activity需要传递哪些数据,除了查看源码之外,完全可以在Activity创建一个静态方法来提示调用者该Activity的详细信息。

	public static void activityStart(Context context, String data1, String data2){
		Intent intent = new Intent(context, FirstActivity.class);
		intent.putExtra("data1", data1);
		intent.putExtra("data2", data2);
		context.startActivity(intent);
	}
//启动时,只需一句代码,并且简单完整的传入所需的各个参数
FirstActivity.activityStart(this, "abc", "def");



二、深入了解Activity




以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值