今天,首先对Activity的生命周期进行复习:
(下面的截图部分是借鉴自赵雅智老师的博客。。。)
Activity的完整生命周期自第一次调用onCreate()开始,直至调用onDestroy()为止。Activity在onCreate()中设置所有“全局”状态以完成初始化,而在onDestroy()中释放所有系统资源。例如,如果Activity有一个线程在后台运行从网络下载数据,它会在onCreate()创建线程,而在 onDestroy()销毁线程。
刚进入activity:
按返回:
1和2显示完整的生命周期
可视生命周期
Activity的可视生命周期自onStart()调用开始直到相应的onStop()调用结束。在此期间,用户可以在屏幕上看到Activity,尽管它也许并不是位于前台或者也不与用户进行交互。在这两个方法之间,我们可以保留用来向用户显示这个Activity所需的资源。例如,当用户不再看见我们显示的内容时,我们可以在onStart()中注册一个BroadcastReceiver来监控会影响UI的变化,而在onStop()中来注消。onStart() 和 onStop() 方法可以随着应用程序是否为用户可见而被多次调用。
按下home键/第二个activity/黑屏在进入
再次进入:
完整的声明周期
前台声明周期
Activity的前台生命周期自onResume()调用起,至相应的onPause()调用为止。在此期间,Activity位于前台最上面并与用户进行交互。Activity会经常在暂停和恢复之间进行状态转换——例如当设备转入休眠状态或者有新的Activity启动时,将调用onPause() 方法。当Activity获得结果或者接收到新的Intent时会调用onResume() 方法。
当activity在AndroidMenifest.xml文件中配置
android:theme="@android:style/Theme.Dialog"
如果是普通的dialog 则不改变声明周期
横竖屏切换
默认情况下,当“屏幕方向”或“键盘显示隐藏” 变化时都会销毁当前Activity,创建新的Activity。
如果不希望重新创建Activity实例,可以按如下配置Activity:
方式一:
4.0以上配置
android:configChanges="orientation|screenSize|keyboardHidden"
4.0一下设置
android:configChanges="orientation|keyboardHidden"
方式二:
android:screenOrientation="landscape"
实际应用:在OnStart里设置网络连接:
- package com.example.main;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.content.DialogInterface.OnClickListener;
- import android.net.ConnectivityManager;
- import android.net.NetworkInfo;
- import android.os.Bundle;
- import android.widget.Toast;
- public class MainActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
- @Override
- protected void onStart() {
- super.onStart();
- checkNetWork();
- }
- public void checkNetWork() {
- //获取连接的管理对象
- ConnectivityManager connectivityManager= (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
- //获取当前正在使用的网络
- NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
- //判断网络是否可用
- if(networkInfo!=null&&networkInfo.isConnected()){
- if(networkInfo.getType()==ConnectivityManager.TYPE_MOBILE){
- Toast.makeText(this,"...正在使用手机流量...", Toast.LENGTH_LONG).show();
- }else if(networkInfo.getType()==ConnectivityManager.TYPE_WIFI){
- Toast.makeText(this, "...正在使用无线网...", Toast.LENGTH_LONG).show();
- }
- }else{
- new AlertDialog.Builder(this)
- .setTitle("请设置网络连接")
- .setMessage("网络没有打开,请进行设置")
- .setIcon(R.drawable.ic_launcher)
- .setPositiveButton("确定", new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Toast.makeText(MainActivity.this, "确定", Toast.LENGTH_LONG).show();
- }
- }).setNegativeButton("去设置", new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Toast.makeText(MainActivity.this, "去设置", Toast.LENGTH_LONG).show();
- Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
- startActivity(intent);
- }
- }).create().show();
- }
- }
- }
onSaveInstanceState()和onRestoreInstanceState()
Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState() 会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
另外,当屏幕的方向发生了改变, Activity会被摧毁并且被重新创建,如果你想在Activity被摧毁前缓存一些数据,并且在Activity被重新创建后恢复缓存的数据。可以重写Activity的 onSaveInstanceState() 和 onRestoreInstanceState()方法,如下:
public class PreferencesActivity extends Activity {
private String name;
protected void onRestoreInstanceState(Bundle savedInstanceState) {
name = savedInstanceState.getString("name"); //被重新创建后恢复缓存的数据
super.onRestoreInstanceState(savedInstanceState);
}
protected void onSaveInstanceState(Bundle outState) {
outState.putString("name", "liming");//被摧毁前缓存一些数据
super.onSaveInstanceState(outState);
}
}
三、加载模式:
配置Activity时可指定android:launchMode属性,该属性用于配置该Activity的加载模式,其属性值有:
standard 标准模式,默认加载模式
singleTop Task顶单例模式
singleTask Task内单例模式
singleInstance 全局单例模式
Activity的加载模式,就负责管理实例化、加载Activity的方式、并可以控制Activity与Task之间的加载关系
Task:
ndroid采用Task来管理多个Activity,当我们启动一个应用时,android就会为之创建了一个Task,然后启动这个应用的入口(即<intent-filter.../>中配置MAIN和LAUNCHER的Activity)
android并没有为Task提供API,因此开发者无法真正访问Task,只能调用Activity的getTaskId()方法来获取它所在的Task的ID。
standard模式:
每次通过这种模式启动目标Activity时,Android总会为目标Activity创建一个新的实例,并将该实例Activity添加到当前Task栈中-这种模式不会启动新的Task,新Activity将被添加到原有的Task中,事实上我们可以把Task理解为Activity的栈,Task以栈的形式来管理Activity,先启动的Activity被放在Task栈底,后启动的Activity被放在Task栈顶。
singleTop模式:
与standard模式基本相似,但有一点不同,当将要被启动的目标Activity已经位于Task栈顶时,系统不会重新创建目标Activity实例,而是直接复用已有的Activity实例。
SingleTask模式:
采用这种加载模式的Activity在同一个Task内只有一个实例,当系统采用singleTask模式启动目标Activity时,有如下三种情况
如果将要启动的目标不存在,系统将会创建目标Activity的实例,并将它加入Task栈顶
如果将要启动的目标Activity已经位于Task栈顶,此时与singleTop模式行为相同
如果将要启动的目标Activity已经存在,但没有位于Task栈顶,系统将会把位于该Activity上面的所有Activity移出Task栈,从而使的目标Activity转入栈顶。
singleInstance模式:
这种加载模式下,系统保证无论从那个Task中启动目标Activity,只会创建一个目标Activity实例,并会使用一个全新的Task栈来装载该Activity实例。分为如下两种情况
如果将要启动的目标Activity不存在,系统会先创建一个全新的Task,再创建目标Activity实例,并将它加入新的Task栈顶
如果将要启动的目标Activity已经存在,无论它位于那个应用程序中,无论它位于那个Task中,系统将会把Activity所在的Task转到前台,从而使用该Activity显示出来.
四、内部存储数据的读取和回显:
- package com.example.internalstorage;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.content.DialogInterface.OnClickListener;
- import android.os.Bundle;
- import android.text.TextUtils;
- import android.view.View;
- import android.widget.CheckBox;
- import android.widget.EditText;
- import android.widget.Toast;
- public class MainActivity extends Activity {
- private EditText et_name, et_pass;
- private CheckBox chbx_rem;
- private String fileName = "mima.txt";
- private InternalStorage internalStorage;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- et_name = (EditText) findViewById(R.id.editusername);
- et_pass = (EditText) findViewById(R.id.editpass);
- // 记住密码的控件
- chbx_rem = (CheckBox) findViewById(R.id.checkbox);
- // 实例化存储对象
- internalStorage = new InternalStorage(MainActivity.this);
- // 通过存储对象得的方法来读取文件内容
- String values[] = internalStorage.readFile(fileName);
- if (values != null) {
- // 设置记住的用户名和密码
- et_name.setText(values[0]);
- et_pass.setText(values[1]);
- }
- }
- public void login(View v) {
- String username = et_name.getText().toString();
- String userpass = et_pass.getText().toString();
- if (TextUtils.isEmpty(username) || TextUtils.isEmpty(userpass)) {
- Toast.makeText(this, "用户名和密码不能为空 ", Toast.LENGTH_LONG).show();
- } else {
- //设置保存的用户名和密码的格式
- final String content = username + ";" + userpass;
- if (!chbx_rem.isChecked()) {
- new AlertDialog.Builder(this).setMessage("请勾选记住密码,方便以后登录")
- .setPositiveButton("否", new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- }
- }).setNegativeButton("是", new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- chbx_rem.setChecked(true);
- internalStorage.save(fileName, content, Context.MODE_PRIVATE);
- }
- }).create().show();
- } else {
- // 直接操作
- internalStorage.save(fileName, content, Context.MODE_PRIVATE);
- Toast.makeText(this, "文件已保存", Toast.LENGTH_LONG).show();
- }
- }
- }
- }
调用的save()和read方法:
- package com.example.internalstorage;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import www.csdn.net.util.StreamTools;
- import android.content.Context;
- public class InternalStorage {
- private Context context;
- public InternalStorage(Context context) {
- this.context = context;
- }
- /*
- * 文件保存 文件名称,文件内容,文件保存的模式
- */
- public void save(String fileName, String content, int mode) {
- try {
- FileOutputStream fos = context.openFileOutput(fileName, mode);
- fos.write(content.getBytes());
- // 立即写入
- fos.flush();
- // 关闭
- fos.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- // 根据文件的名称去读取文件的内容
- public String[] readFile(String fileName) {
- String values[] = null;
- // 创建一个文件属性
- File file = new File(context.getFilesDir(), fileName);
- // 判断文件存在不存在
- if (file.exists()) {
- // 在这里操作
- try {
- // 根据文件创建出文件的输入流
- InputStream is = new FileInputStream(file);
- // 文件存在,通过工具类读取文件内容
- String value = StreamTools.streamToStr(is);
- // 按照;进行拆分,返回数组对象
- values = value.split(";");
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- }
- // 记得申明返回对象
- return values;
- }
- }
五、将数据文件存储在SD卡上的操作,保存成私密文件。读取也是私密文件:
1、ManAcvitity主文件:
- package com.example.externalstorage;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import com.example.service.FileService;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Environment;
- import android.view.View;
- import android.widget.CheckBox;
- import android.widget.EditText;
- import android.widget.Toast;
- public class MainActivity extends Activity {
- private EditText et_name, et_pass;
- private CheckBox chbx_rem;
- private String fileName = "csdn1.txt";
- private FileService fileService;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- // 获取控件对象
- et_name = (EditText) findViewById(R.id.et_name);
- et_pass = (EditText) findViewById(R.id.et_pass);
- chbx_rem = (CheckBox) findViewById(R.id.chbx_rem);
- // 创建业务对象
- fileService = new FileService();
- // 获取sdcard上读取到的文件内容
- String values[] = fileService.readFile(this, Environment.DIRECTORY_DOWNLOADS, fileName);
- if (values != null) {
- // 设置用户名
- et_name.setText(values[0]);
- // 设置用户密码
- et_pass.setText(values[1]);
- }
- }
- /**
- * 检测你的外部存储设备是否安装,并且是否可读和可写
- *
- * @return
- */
- public boolean isExternalStorageAvailable() {
- // 声明返回的变量
- boolean flag = false;
- // 获取设备的状态
- String state = Environment.getExternalStorageState();
- // 判断设备是否安装,并且是否可读和可写
- if (Environment.MEDIA_MOUNTED.equals(state)) {
- // 返回真
- flag = true;
- }
- // 记得修改返回变量
- return flag;
- }
- public void login(View v) {
- String userName = et_name.getText().toString();
- String userPass = et_pass.getText().toString();
- String content = userName + ";" + userPass;
- if (chbx_rem.isChecked()) {
- // 如果要操作外部存储设备,1.需要添加权限。 2.需要判断有没有外部存储设备
- // 判断你的外部设备是否安装,是否可读可写
- if (isExternalStorageAvailable()) {
- // 公共文件
- fileService.saveFile(this,fileName, content,Environment.DIRECTORY_DOWNLOADS);
- // 私密文件
- Toast.makeText(this, "文件保存成功.", Toast.LENGTH_LONG).show();
- } else {
- Toast.makeText(this, "请检查你的外部设备的操作", Toast.LENGTH_LONG).show();
- }
- } else {
- }
- }
- }
2.FileService(具体方法实现类):
- package com.example.service;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import android.content.Context;
- import android.os.Environment;
- import com.example.util.StreamTools;
- public class FileService {
- /**
- * 文件存储到SDCard上的操作(公共文件)
- *
- * @param fileName
- * :文件名称
- * @param content
- * :文件内容
- * @param dir
- * :文件存储到SDCard的目录文件
- */
- public void saveFile(String fileName, String content, String dir) {
- // 演示公共文件
- File sdCardDir = Environment.getExternalStoragePublicDirectory(dir);
- //Environment.getExternalStorageDirectory()
- // 创建文件对象
- File file = new File(sdCardDir, fileName);
- try {
- // 创建文件输出流对象
- FileOutputStream fos = new FileOutputStream(file);
- // 通过文件输出流对象写入
- fos.write(content.getBytes());
- // 立即写入
- fos.flush();
- // 关闭
- fos.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- /**
- * 读取文件(公共文件)
- *
- * @param dir
- * :sdcard的目录
- * @param fileName
- * :文件的名称
- * @return:返回的是用户名和密码
- */
- public String[] readFile(String dir, String fileName) {
- // 声明返回值
- String values[] = null;
- // 根据sdcard的目录创建文件对象
- File file = new File(
- Environment.getExternalStoragePublicDirectory(dir), fileName);
- // 判断文件是否存在
- if (file.exists()) {
- try {
- // 根据文件,创建文件输出流对象的时候有一个文件找不到的异常
- InputStream is = new FileInputStream(file);
- // 利用工具类处理
- String value = StreamTools.streamToStr(is);
- values = value.split(";");
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- // 记得修改返回值
- return values;
- }
- /**
- * 保存文件(私密文件)
- *
- * @param context
- * :上下文件对象
- * @param fileName
- * :文件名称
- * @param content
- * :文件内容
- * @param dir
- * :文件sdcard的目录
- */
- public void saveFile(Context context, String fileName, String content,
- String dir) {
- // 演示公共文件
- File sdCardDir = context.getExternalFilesDir(dir);
- // 创建文件对象
- File file = new File(sdCardDir, fileName);
- System.out.println("---------------------------"+file.getPath()+"--------------------");
- try {
- // 创建文件输出流对象
- FileOutputStream fos = new FileOutputStream(file);
- // 通过文件输出流对象写入
- fos.write(content.getBytes());
- // 立即写入
- fos.flush();
- // 关闭
- fos.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- System.out.println("=================================================================");
- }
- /**
- * 读取文件(私密文件)
- *
- * @param context
- * :上下文对象
- * @param dir
- * :文件目录
- * @param fileName
- * :文件名称
- * @return:读取到的用户名和密码
- */
- public String[] readFile(Context context, String dir, String fileName) {
- // 声明返回值
- String values[] = null;
- // 根据sdcard的目录创建文件对象
- File file = new File(context.getExternalFilesDir(dir), fileName);
- // 判断文件是否存在
- if (file.exists()) {
- try {
- // 根据文件,创建文件输出流对象的时候有一个文件找不到的异常
- InputStream is = new FileInputStream(file);
- // 利用工具类处理
- String value = StreamTools.streamToStr(is);
- values = value.split(";");
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- // 记得修改返回值
- return values;
- }
- }
3、StreamTools(将字节流转换为字符流的工具类):
- package com.example.util;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- public class StreamTools {
- public static String streamToStr(InputStream is) {
- try {
- // 字节数组输出流对象
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- // 读取长度
- int len = 0;
- // 读取的缓冲区
- byte buffer[] = new byte[1024];
- // 输入流循环读取 直到结尾
- while ((len = is.read(buffer)) != -1) {
- // 读取的内容写入到字节数组输出流对象中
- os.write(buffer, 0, len);
- }
- // 关闭流
- is.close();
- os.close();
- // 把字节数组输出流对象 转换成字节数组
- byte data[] = os.toByteArray();
- // 通过String构造函数把字节数组转换成字符串 并返回
- return new String(data);
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- }