Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android學習四(Activity的生命周期)

android學習四(Activity的生命周期)

編輯:關於Android編程

要學好活動(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,代碼如下



    
    
    



3.在建立一個布局文件,文件名為dialog_layout.xml代碼如下:



    

    
    


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.給活動進行注冊,代碼如下:

            
        
        
        
        
            
        

7.修改主布局文件acitvity_main.xml代碼如下:



    
    

上面定義了2個按鈕,用來啟動一個正常的活動,和一個以對話框形式顯示的活動。



8.修改MainActivity裡面的方法,重寫activity的生命周期方法,對按鈕進行監聽,代碼如下:

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 nomalActivity按鈕<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PGltZyBzcmM9"/uploadfile/Collfiles/20141030/2014103009063148.jpg" alt="\">



啟動新的活動後,調用了onPause和onStop方法。NormalActivity顯示在界面了。

在按back鍵進行返回

\


可以觀察到調用了onRestart,onStart和onResume方法,在點擊start DailogActivity按鈕

\

\


可以看到,指調用了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中通過給標簽指定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的啟動模式,如下所示:

            
                
                
            
        

再次運行程序,你會看到已經創建了一個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 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();
			}
		}
	}
	
	
}


然後在修改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,學了後感覺收獲很多,寫的很容易理解,在此感謝第一行代碼android的作者,郭神


轉載請注明來至:http://blog.csdn.net/j903829182/article/details/40555119






  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved