最近一直忙于处理其他事情,忽略了笔记的整理,在前几天写好了一直没有上传
## 探究活动
### Activity
activity是最容易吸引用户的地方,它使一种可以包含用户的组件,主要用于和用户进行交互。一个应用程序中可以包含零个或多个活动,但并不包含任何活动的应用程序很少见
### 手动创建活动
Grenerate Layout File:自动为活动创建一个对应的布局文件
Launcher Activity:自动将该activity设置为当前项目的主活动
在mainFest中申明主活动:
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
### 在活动中使用Toast
findViewById:得到的是一个view对象需要向下转型
Toast的用法非常简单,通过静态方法makeText()创建出一个Toast对象,然后调用show()将Toast显示出来及可以了。makeText方法需要传入三个参数:第一个参数是context,也就是Toast要求的上下文对象;第二个参数是Toast显示的文本内容;第三个参数是Toast显示的时长,有两个内置常量可以选择Toast.LENGTH_SHORT和Toast.LENGTH_LONG
在活动中使用menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main , menu);
return true;
}
getMenuInflater()方法能够得到MenuInflater对象,再调用它的inflate()方法就可以给当前活动创建菜单了。inflate()方法接受两个参数,第一个参数用于指定通过哪些资源文件来创建菜单;第二个参数用于指定我们的菜单项将添加到哪一个menu对象当中,这里直接使用onCreateOptionMenu()方法中传入的menu参数。然后给这个方法返回true,表示允许创建的菜单显示出来,如果返回false,创建的菜单将无法显示
定义菜单响应事件:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.add_item:
Toast.makeText(this , "You clicked add" , Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this , "You Clicked Remove" , Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
在onOptionsItemSelected()方法中,通过调用item.getItemId()来判断我们点击的是哪一个菜单项,然后给每个菜单项加入自己的逻辑处理
销毁一个活动
1、按back键
2、按钮设置监听,点击按钮销毁活动
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Toast.makeText(FirstActivity.this , "You Clicked Button 1" , Toast.LENGTH_SHORT).show();
finish();
}
});
使用intent在活动之间穿梭
intent是android中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。intent一般可被用于启动活动、启动服务以及发送广播等场景
intent有多个构造函数的重载,其中一个是Intent(Context packageContext, Class
向下一个活动传递 ####
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String data = "hello SecondActivity";
Intent intent = new Intent(FirstActivity.this , SecondActivity.class);
intent.putExtra("extra_data" , data);
startActivity(intent);
}
});
通过 putExtra()方法传递了一个字符串。注意这里putExtra()方法接收两个参数,第一个是键,用于后面从intent中取值,第二个参数才是真正的传递数据
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity);
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity" , data);
}
首先可以通过getIntent()方法取到用于启动SecondActivity的intent。然后 getStringExtra()方法,传入相应的键值,就可以得到传递的数据了。
传递字符串: getStringExtra
传递整型数据: getIntExtra
传递的是布尔型数据: getBooleanExtra
返回数据给上一个活动
startActivityForResult()方法接收两个参数,第一个参数还是intent,第二个参数是请求码,用于在之后的回调中判断数据的来源
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(FirstActivity.this , SecondActivity.class);
startActivityForResult(intent , 1);
}
});
请求码只要是一个唯一值就可以了,这里传1
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.putExtra("data_return" , "Hello FirstActivity");
setResult(RESULT_OK , intent);
finish();
}
});
setResult方法接收两个参数,第一个参数用于向上一个活动返回处理结果,一般只使用 RESULT_OK 或 RESULT_CANCELE者两个值,第二个参数则吧带有数据的intent传递回去,然后调用finish()方法来销毁活动
由于我们使用 startActivityForResult 方法来启动SecondActivity的,在 SecondActivity被销毁后会回调上一个活动的 onActivityResult() 方法,因此需要在 FirstActivity 中重写这个方法来得到返回的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String returnedData = data.getStringExtra("data_return");
Log.d("FirstyActivity", returnedData);
}
break;
default:
}
}
onActivityResult 方法带有三个参数,第一个参数requestCode,即我们再启动活动时传入的请求码。第二个参数 resultCode,即我们在返回数据时传入的处理结果。第三个参数 data,即携带返回数据的intent。
在一个活动中有可能调用 startActivityForResult()方法去启动很多不同的活动,每一个活动返回的数据都会回调到 onActivityResult() 这个方法中,因此我们首先要做的就是通过检查 requestCode 的值来判断数据来源。确定数据是从 SecondActivity 返回的之后,我们再通过resultCode的值来判断处理结果是否成功。最后从data中取值并打印出来,这样就完成了向上一个活动返回数据的工作
按下back键返回activity,在 SecondActivity 中重写onBackPressed()方法:
活动的生命周期
返回栈
Android是使用任务栈(Task)来管理活动的,一个任务就是一组寻访在栈里的活动的集合,这个栈也被乘坐返回栈(Back Stack)。栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的活动,它会在返回栈中入栈,并处于栈顶的位置。而每当我们按下back键或者调用finish 方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈的活动就会重新处于栈顶的位置。系统总是会显示处于栈顶的活动给用户
活动状态
- 运行状态
当一个活动处于返回栈的栈顶时,这时活动就处于运行状态。系统最不愿意回收的就是处于运行状态的活动,因为这会带来非常差的用户体验
- 暂停状态
当一个活动不再处于栈顶但仍可见时,这时活动就处于暂停状态。处于暂停状态的活动仍然是完全存活的,系统也不愿意去回收这种活动(因为他还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会去考虑回收这种活动
- 停止状态
当一个活动不再处于栈顶位置时,并且完全不可见的时候,就进入了停止状态。系统仍然会为这种活动保持相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的活动有可能被系统回收
- 销毁状态
当一个活动从返回栈中移除后就变成了销毁状态,系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足
活动的生存期
- onCreate:活动第一次被创建时调用,在方法中完成活动的初始化操作,比如:加载布局、绑定事件
- onStart:活动由不可见变为可见时调用
- onResume:活动准备好和用户进行交互时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态
- onPause:在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方法中将一些消耗CPU 的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用
- onStop:在活动完全不可见的时候调用。他和onPause 方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么onPause 方法会得到执行,而onStop方法并不会执行
- onDestroy:在活动被销毁之前调用,之后活动的状态将变为销毁状态
- onRestart:在活动由停止状态转变为运行状态之前调用,也就是活动呗重新启动了
以上方法除了onRestart 方法,其他的都是两两相对的,从而又可以将活动氛围3种生存期
- 完整生存期:活动在onCreate 方法和 onDestroy 方法之间所经历的,就是完整生存期。一般情况下,一个活动会在 onCreate 方法中完成各种初始化操作,而在 onDestroy 方法中完成释放内存的操作
- 可见生存期:活动在onStart 方法和 onStop 方法之间所经历的,就是可见生存期。在可见生存期内,活动对用户总是可见的,即便有可能无法和用户交互。我们可以通过这两个方法,合理地管理那些对用户可见的资源。
- 前台生存期:活动在onResume 方法和 onPause 方法之间所经历的就是前台生存期。在前台生存期内活动总是处于运行状态的,此时的活动时可以和用户进行交互的,我们平时看到和接触最多的也是这个状态下的活动
在AndroidMainFest.xml中将活动射程对话框:
<activity android:name=".DialogActivity"
android:theme="@android:style/Theme.Dialog">
</activity>
启动模式
- standard
系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例
- singleTop
启动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例
- singleTask
当活动的启动模式指定为singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动智商的所有活动统统出站,如果没有发现就会创建一个新的活动实例
- singleInstance
指定为singleInstance模式的活动会启用一个新的返回栈来管理这个活动(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。
活动的最佳实践
知晓当前是在哪一个活动
创建一个BaseActivity类
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity" , getClass().getSimpleName());
}
}
在onCreate 方法中获取了当前实例的类名,并通过log打印出来
随时随地退出程序
创建专门的集合类对所有的活动进行管理
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<>();
public static void addActivity (Activity activity) {
activities.add(activity);
}
public static void removeActivity (Activity activity) {
activities.remove(activity);
}
public static void finishAll() {
for (Activity activity : activities) {
if (!activity.isFinishing()) {
activity.finish();
}
}
}
}
addActivity:用于向list中添加一个活动
removeActivity:用于从list中移除活动
finishAll:将list中存储的活动全部销毁掉
修改BaseActivity中的代码:
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity" , getClass().getSimpleName());
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
}
杀掉进程的代码:
android.os.Proces.killProcess(android.os.Process.myPid());
killProcess()方法用于杀掉一个进程,它接收一个进程id参数,我们可以通过myPid()方法来获得当前进程的id。注意:killProcess()方法只能用于杀掉当前程序的进程,我们不需要使用这个方法去杀掉其他程序