• android学习四(Activity的生命周期)


       要学好活动(Activity)。就必需要了解android中Activity的声明周期。灵活的使用生命周期。能够开发出更好的程序,在android中是使用任务来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈。栈的特性是后进先出,在默认的情况下,每当我们启动了一个新的活动。它会在返回栈中入栈。并处于栈顶的位置。而每当我们按下Back键或调用finish方法去销毁一个活动时。处于栈顶的活动会出栈,这时前一个入栈的活动就会又一次处于栈顶的位置。系统总是会显示处于栈顶的活动给用户。

    1.活动的四种状态:

    执行状态:当一个活动位于返回栈的栈顶时,这是活动就处于执行状态。系统不会回收处于执行状态的活动。

    暂停状态:当一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态。

    停止状态:当一个活动不在处于栈顶位置,而且全然不可见的时候,就进入了停止状态

    销毁状态:当一个活动从返回栈中移除后就变成了销毁状态。


    2.活动的生命周期。活动中定义了7个回调方法

    onCreate方法在活动第一次被创建的时候调用,在这种方法中。应该完毕活动的初始话操作。比方载入布局,绑定事件等。

    onStart方法在活动由不可见变为可见的时候调用

    onResume在活动准备好和用户进行交互的时候调用,此时活动处于返回栈的栈顶。

    onPause方法在系统准备去启动或者恢复还有一个活动的时候调用。一般会在这种方法中将一些销毁cpu的资源释放掉。以及保存一些重要数据。但这种方法的运行速度一定要快,不然会影响新的栈顶活动的使用。

    onStop这种方法在活动全然不可见的时候调用。

    它和onPause方法的主要差别在于,假设启动的新活动是一个对话框式的活动。那么onPause方法会得到运行。而onStop方法并不会运行。

    onDestory方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。

    onRestart方法在活动由停止状态变为执行状态之前调用,也就是活动的重新启动了。


    3.活动的3个周期

    完整生命周期:活动在onCreate方法和onDestroy方法之间所经历的。就是完整生存周期。普通情况下一个活动会在onCreate方法中完毕各种初始话操作。而在onDestory方法中完毕释放操作。

    可见生存周期:活动在onStart方法和onStop方法之间所经历的,就是可见生存周期。在可见生存周期内。活动对于用户总是可见的,即便有可能无法和用户进行交互。

    我们能够通过这两个方法,合理的管理那些对用户可见的资源。比方在onStart方法中对资源进行载入,而在onStop方法中对资源进行释放,从而保证处于停止状态的活动不会占用过多的内存。

    前台生存期:活动在onResume方法和onPause方法之间所经历的。就是前台生存期。

    在前台生存期内。活动总是处于执行状态。此时活动是能够和用户进行交互的。



    上面说了那么多的理论知识,以下就让我们開始编程測试下活动的生命周期吧!

    !。

    1.先建一个android项目,项目名为ActivityLifeCycleTest。採用默认的设置,填写好包名。

        以下还须要创建2个活动,进行生命周期的測试。

    2.建立一个布局文件。文件名称为normal_layout.xml。代码例如以下

    <span style="font-size:18px;"><?

    xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="this is a normal activity"/> </LinearLayout></span>


    3.在建立一个布局文件。文件名称为dialog_layout.xml代码例如以下:

    <?

    xml version="1.0" encoding="utf-8"?

    > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="this is a dialog activity"/> </LinearLayout>


    4.新建一个活动,类名为NormalActivity。继承Activity代码例如以下:

    package com.wj.activitylifecycletest;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Window;
    
    public class NormalActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		// TODO Auto-generated method stub
    		super.onCreate(savedInstanceState);
    		requestWindowFeature(Window.FEATURE_NO_TITLE);
    		setContentView(R.layout.normal_layout);
    	}
    
    	
    }
    

    5.在新建一个活动,活动名为DialogActivity代码例如以下:

    package com.wj.activitylifecycletest;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Window;
    
    public class DialogActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		// TODO Auto-generated method stub
    		super.onCreate(savedInstanceState);
    		requestWindowFeature(Window.FEATURE_NO_TITLE);
    		setContentView(R.layout.dialog_layout);
    	}
    
    	
    }
    


    6.给活动进行注冊。代码例如以下:

    <activity android:name=".NormalActivity">
                
            </activity>
            
            <!--android:theme="@android:style/Theme.Dialog"是让活动以对话框的新式显示  -->
            <activity android:name=".DialogActivity"
                android:theme="@android:style/Theme.Dialog">
                
            </activity>

    7.改动主布局文件acitvity_main.xml代码例如以下:

    <?

    xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/start_normal_activity" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start NomalActivity"/> <Button android:id="@+id/start_dialog_activity" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start DialogActivity"/> </LinearLayout>


    上面定义了2个button,用来启动一个正常的活动,和一个以对话框形式显示的活动。



    8.改动MainActivity里面的方法,重写activity的生命周期方法,对button进行监听。代码例如以下:

    package com.wj.activitylifecycletest;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Menu;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.Window;
    import android.widget.Button;
    
    public class MainActivity extends Activity {
    
    	public static final String TAG="MainActivity";
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		Log.d(TAG, "onCreate");
    		requestWindowFeature(Window.FEATURE_NO_TITLE);
    		setContentView(R.layout.activity_main);
    		
    		//获得组件
    		Button startNormalActivity=(Button) findViewById(R.id.start_normal_activity);
    		Button startDialogActivity=(Button) findViewById(R.id.start_dialog_activity);
    		
    		startNormalActivity.setOnClickListener(new OnClickListener(){
    
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    				Intent intent =new Intent(MainActivity.this,NormalActivity.class);
    				startActivity(intent);
    			}
    			
    		});
    		
    		
    		startDialogActivity.setOnClickListener(new OnClickListener(){
    
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    				Intent intent =new Intent(MainActivity.this,DialogActivity.class);
    				startActivity(intent);
    			}
    			
    		});
    		
    		
    	}
    
    	
    	
    	
    	
    	
    	
    	@Override
    	protected void onDestroy() {
    		// TODO Auto-generated method stub
    		super.onDestroy();
    		Log.d(TAG, "onDestroy()");
    	}
    
    
    
    
    
    
    
    	@Override
    	protected void onPause() {
    		// TODO Auto-generated method stub
    		super.onPause();
    		Log.d(TAG, "onPause()");
    	}
    
    
    
    
    
    
    
    	@Override
    	protected void onRestart() {
    		// TODO Auto-generated method stub
    		super.onRestart();
    		Log.d(TAG, "onRestart()");
    	}
    
    
    
    
    
    
    
    	@Override
    	protected void onResume() {
    		// TODO Auto-generated method stub
    		super.onResume();
    		Log.d(TAG, "onResume()");
    	}
    
    
    
    
    
    
    
    	@Override
    	protected void onStart() {
    		// TODO Auto-generated method stub
    		super.onStart();
    		Log.d(TAG, "onStart()");
    	}
    
    
    
    
    
    
    
    	@Override
    	protected void onStop() {
    		// TODO Auto-generated method stub
    		super.onStop();
    		Log.d(TAG, "onStop()");
    	}
    
    
    
    
    
    
    
    	@Override
    	public boolean onCreateOptionsMenu(Menu menu) {
    		// Inflate the menu; this adds items to the action bar if it is present.
    		getMenuInflater().inflate(R.menu.main, menu);
    		return true;
    	}
    
    }
    

    代码比較的简单。就不啰嗦了。以下我们执行观察结果吧!!



    9.执行程序,观察Logcat的输出

       执行程序:


    能够看到运行了onCreate,onStart,onResume方法。

    在点击start nomalActivitybutton




    启动新的活动后,调用了onPause和onStop方法。

    NormalActivity显示在界面了。

    在按back键进行返回



    能够观察到调用了onRestart。onStart和onResume方法,在点击start DailogActivitybutton




    能够看到,指调用了onPause方法,由于MainActivity仅仅有部分被遮盖了。在按back键。观察仅仅调用了onResume方法。


    在按back键观察例如以下输出:


    可见程序调用了onPause,onStop。onDestory方法后就销毁了活动了

    通过上面的演示。相信你对活动的生命周期有了一定的了解了吧,有不懂的,还能够交流啊!

    。!




    以下我们来学习,保存用户的数据的activity。

    在Activity中提供了一个onSaveInstanceState方法,这种方法会保证一定在活动被回收之前调用,因此我们能够通过这种方法来解决活动被回收时零时数据得不到保存的问题。

    在活动中重写onSaveInstanceState(Bundle outState)方法,代码例如以下:

    @Override
    	protected void onSaveInstanceState(Bundle outState) {
    		// TODO Auto-generated method stub
    		super.onSaveInstanceState(outState);
    		String tempData="something you just typed";
    		/*
    		 * onSaveInstanceState方法携带了一个Bundle类型的參数,Bundle提供了一系列的
    		 * 方法用于保存数据,详细的能够查看api,主要方法都有key-value參数。来保存数据的。
    		 * */
    		outState.putString("data_key", tempData);
    	}

    这种话,在活动被回收的时候。onStop方法被调用之前。使用了onSaveInstanceState(Bundle outState)进行数据的保存了,那么该在哪里进行数据的恢复了?观察onCreate方法的參数有一个Bunndle的參数,所以就应该在onCreate函数中进行数据的恢复,例如以下:

    if(savedInstanceState!=null){
    			String tempData=savedInstanceState.getString("data_key");
    			Log.d(TAG, tempData);
    		}

    onSaveInstanceState(Bundle outState)方法在活动暂停的时候调用了onPause方法后也会调用onSaveInstanceState(Bundle outState)方法,onSaveInstanceState(Bundle outState)方法在onStop方法之前得到调用了。在onCreate方法中进行恢复。


    活动的启动模式

    活动的启动模式一共同拥有四种。在实际的项目中,能够依据特定的需求为每一个活动指定恰当的启动模式。四种模式各自是standard,singleTop,singleTask,singleInstance,能够在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。


    在这里我们使用ActivityTest这个项目进行模式的測试。ActivityTest这个项目的源代码我已经在前面给出来了,所以这里就不在给出完整的代码了。

    standard是活动默认的启动模式,在不进行显示指定的情况下,全部活动都会自己主动使用这样的模式。

    因此。到眼下为止我们写过的全部活动都是使用的standard模式。我们知道android中是使用返回栈来管理活动的。在standard模式下。每当启动一个新的活动。它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的活动。系统不会在乎这个活动释放已经在返回栈中。每次启动都会创建该活动的一个新实例。

    改动FirstActivity中的onCreate方法里面的代码。

    package com.wj.test;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.Window;
    import android.widget.Button;
    import android.widget.Toast;
    
    public class FirstActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		// TODO Auto-generated method stub
    		super.onCreate(savedInstanceState);
    		Log.d("FirstActivity", this.toString());
    		requestWindowFeature(Window.FEATURE_NO_TITLE);
    		setContentView(R.layout.first_layout);
    		Button button1=(Button) findViewById(R.id.button1);
    		button1.setOnClickListener(new OnClickListener(){
    
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    /*				Toast.makeText(FirstActivity.this, "you clicked button1",
    					Toast.LENGTH_SHORT).show();*/
    				/*
    				 * Intent的使用分为显示的Intent和隐式的Intent,以下的是显示的Intent
    				 * Intent有多个构造函数,我使用的是一个简单的的,第一个參数Context要求提供一个启动
    				 * 活动的上下文。第二个參数Class则是指定想要启动的目标活动,通过这个构造函数构建出Intent
    				 * 的“意图”,然后使用startActivity(intent);启动目标活动。

    * Intent是android程序中个组件之间进行交互的一种重要的方式。它不紧能够指明当前组想要运行 * 的动作,还能够在不同组件之间传递数据。Intent一般可被用于启动活动,服务。以及发送广播等。

    * */ /*Intent intent=new Intent(FirstActivity.this, SecondActivity.class); startActivity(intent);*/ //使用隐式的Intent /*Intent intent=new Intent("com.wj.test.activitytest.ACTION_START"); intent.addCategory("com.wj.activitytest.MY_CATEGORY"); startActivity(intent);*/ //很多其它隐式的Intent的使用方法 //打开浏览器 /* * 这里我们指定了Intent的action是Intent.ACTION_VIEW,这是一个android系统内置的动作, * 其常量为android.intent.action.VIEW,然后通过Uri.parse方法,将一个网址字符串解析成一个 * Uri对象。在调用Intent的setData()方法将这个对象传递进去。 * */ /*Intent intent=new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.baidu.com")); startActivity(intent);*/ //实现拨打电话 /*Intent intent=new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:10086")); startActivity(intent);*/ //向下一个活动传递数据 /* * Intent中提供了一系列putExtra()方法的重载,能够把我们想要传递的数据暂存在Intent中 * ,启动了还有一个活动后,仅仅需把这些数据再从Intent中取出就能够了。

    * */ /*String data="Hello SecondActivity"; Intent intent =new Intent(FirstActivity.this,SecondActivity.class); intent.putExtra("extra_data", data); startActivity(intent);*/ //返回数据给上一个活动 //Intent intent=new Intent(FirstActivity.this,SecondActivity.class); /* * startActivityForResult方法接收2个參数,一个參数是Intent,第二个參数是请求码 * ,用于在之后的的回调中推断数据的来源 * */ //startActivityForResult(intent, 1); //測试android活动的standard模式 Intent intent=new Intent(FirstActivity.this,FirstActivity.class); startActivity(intent); } }); } //重写onActivityResult方法获取返回的结果数据 //@Override /*protected void onActivityResult(int requestCode, int resultCode, Intent data) { // TODO Auto-generated method stub switch(requestCode){ case 1: if(resultCode==RESULT_OK){ String returnedData=data.getStringExtra("data_return"); Log.d("FirstActivity", returnedData); } break; default:break; } }*/ @Override public boolean onCreateOptionsMenu(Menu menu) { // TODO Auto-generated method stub getMenuInflater().inflate(R.menu.main, menu); /** * getMenuInflater()方法能够得到MenuInflater对象,在调用他的inflate方法就能够给 * 当前活动创建菜单了。inflate方法接收两个參数,第一个參数用于指定我们通过哪一个资源文件来创建 * 菜单,这里当然传入R.menu.main。第二个參数用于指定我们的菜单将加入到哪一个Menu对象中,这里直接 * 使用onCreateOptionsMenu(Menu menu)传入的menu參数。然后给这种方法返回true,表。示 * 同意创建的菜单显示出来。假设返回false,创建的菜单将无法显示 * */ return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // TODO Auto-generated method stub /* * 通过调用item.getItemId()来推断我们点击的是哪一个菜单项。 * */ switch(item.getItemId()){ case R.id.add_item: Toast.makeText(FirstActivity.this, "you clicked add", Toast.LENGTH_SHORT).show(); break; case R.id.remove_item: Toast.makeText(FirstActivity.this, "you clicked remove", Toast.LENGTH_SHORT).show(); break; default:break; } //return super.onOptionsItemSelected(item); return true; } }



    执行程序,点击button1出现以下的输出,能够知道,每次点击都重写创建了一个活动了,由于他们的地址不一样了。
    10-29 14:10:25.231: D/FirstActivity(3961): com.wj.test.FirstActivity@40cf61d8

    10-29 14:10:34.391: D/FirstActivity(3961): com.wj.test.FirstActivity@40cfd590

    10-29 14:11:59.410: D/FirstActivity(3961): com.wj.test.FirstActivity@40d045e0

    每次点击都会创建一个新的FirstActivity实例,返回时,你创建了几个实例就须要按几次back键才干退出程序。



    singleTop:当活动的启动模式指定是singleTop,在启动活动时,假设发现返回栈的栈顶已经是该活动,则觉得能够直接使用它,不会在创建新的活动实例。

    我们改动下AndroidManifest.xml中的FirstActivity的启动模式,例如以下所看到的:

    <activity 
                android:name="com.wj.test.FirstActivity"
                android:launchMode="singleTop"
                android:label="this is firstactivity">
                <intent-filter >
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>

    再次执行程序,你会看到已经创建了一个FirstActivity的实例了,之后无论你点击多少下,都不会有新的信息出现了,由于眼下FirstActivity已经处于返回栈的栈顶了,每当想要启动一个FirstActivity时都会直接使用栈顶的活动,由于FirstActivity也仅仅会有一个实例。仅按一次back键就能够退出程序了。

    只是当FirstActivity并为处于栈顶的位置时,这时启动FirstActivity,还是会创建新的实例的。


    singleTask:当活动的启动模式指定为singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例。假设发现已经存在则直接使用该实例,并把在这个活动之上的活动统统出栈,假设没有发现就会创建一个新的活动。


    singleInstance:指定为singleInstance模式的活动会启用一个新返回栈来管理这个活动。如果我们的程序中有一个活动是同意其它程序调用的。如果我们想实现其它程序和我们的程序能够共享这个活动的实例。其它的三种模式就不能实现这中共享了。由于每一个应用程序都会有自己的返回栈的。而我们使用singleInstance模式就能够解决问题,在这样的模式下会有一个单独的返回栈来管理这个活动,无论是哪个应用程序来訪问这个活动,都共用一个返回栈,也就攻克了共享活动的实例的问题。



    活动的最佳实践。


    知晓当前是哪相应一个活动:这主要是为了解决看别人的代码的时候。不知道当前的界面相应的是哪个活动的问题。

    建立一个基类。继承Activity代码例如以下:

    package com.wj.test;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    
    public class BaseActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		// TODO Auto-generated method stub
    		super.onCreate(savedInstanceState);
    		Log.d("BaseActivity", getClass().getSimpleName());
    	}
    
    	
    }
    


    我们在onCreatey方法中获取了当前实例的类名,并通过Log打印出来,以后仅仅要让BaseActivity成为全部活动的父类,这样当我们每进入一个活动的界面,该活动的类名就会被打印出来了,这样我们就能够知道当前界面相应哪一个活动了。



    随时随地的退出程序:当我们在程序中接连启动几个程序时,须要按几次back键才干退出程序,按home键仅仅能把程序挂起,并没有退出。

    那么我们该怎么实现注销或者退出的功能了?必须随时随地都能退出程序的方案才行。解决思路:用一个专门的集合类对全部的活动进行管理就能够了,以下实现部分代码。

    首先来一个管理活动的类代码例如以下:

    package com.wj.test;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import android.app.Activity;
    /*
     * 在活动的管理中我们,通过一个List来暂存活动。然后提供了一个addActivity(Activity activity)
     * 方法用于向List中加入活动,提供了一个removeActivity(Activity activity)方法用于从List中
     * 移除活动,提供了一个finishAll()方法用于将存储的活动所有都销毁掉。
     * */
    public class ActivityCollector {
    
    	public static List<Activity> activities=new ArrayList<Activity>();
    	//加入活动
    	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();
    			}
    		}
    	}
    	
    	
    }
    


    然后在改动BaseActivity类的代码:

    package com.wj.test;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    
    public class BaseActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		// TODO Auto-generated method stub
    		super.onCreate(savedInstanceState);
    		Log.d("BaseActivity", getClass().getSimpleName());
    		ActivityCollector.addActivity(this);
    	}
    
    	@Override
    	protected void onDestroy() {
    		// TODO Auto-generated method stub
    		super.onDestroy();
    		ActivityCollector.removeActivity(this);
    	}
    
    	
    	
    	
    	
    }
    

    在BaseActivity的onCreate方法中调用了ActivityCollector的addActivity方法,表明将当前正在创建的活动加入到活动管理器中。然后在onDestory方法中调用ActivityCollector的removeActivity方法,表明将一个立即要销毁的活动从活动管理器里移除。从此。无论想在什么地方退出程序,仅仅须要调用ActivityCollector的finishAll方法即可了。

    你能够在销毁全部活动后,在加上杀掉当前进程的代码。



    启动活动的最佳实践:解决对接的问题。我们不知道启动活动。须要哪些參数的情况下

    我们在一个活动中增加以下的一个函数:

    public static void actionStart(Context context,
    			String data1,String data2){
    		Intent intent =new Intent(context,SecondActivity.class);
    		intent.putExtra("param1", data1);
    		intent.putExtra("param2", data2);
    	}


    当我们要启动SecondActivity这个活动的时候,仅仅须要在在其它的活动中调用actionStart方法。并传入对应的參数就可以了。


    活动的使用就写到着把,以后有什么更好的样例了,我在进行补充。

    我总结的内容都来至第一行代码android,学了后感觉收获非常多,写的非常easy理解,在此感谢第一行代码android的作者,郭神


    转载请注明来至:http://blog.csdn.net/j903829182/article/details/40555119






  • 相关阅读:
    Razor 视图
    可选参数和命名参数
    CPU性能分析工具原理
    从硬件到语言,详解C++的内存对齐(memory alignment)
    谈谈C++的volatile关键字以及常见的误解
    C++11的value category(值类别)以及move semantics(移动语义)
    C++基于范围循环(range-based for loop)的陷阱
    C++模板入门教程(一)——模板概念与基本语法
    自己动手实现深度学习框架-8 RNN文本分类和文本生成模型
    自己动手实现深度学习框架-7 RNN层--GRU, LSTM
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/7388463.html
Copyright © 2020-2023  润新知