真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Robotium中調(diào)用getActivity()方法導(dǎo)致程序掛起的研究淺析

1. 問題背景描述

在工作中需要在沒有項(xiàng)目源碼的情況下直接使用robotium測試目標(biāo)android平臺launcher,平臺的版本基于當(dāng)前最新的android 4.4.2。之前在驗(yàn)證可行性的時(shí)候使用本人同樣使用android4.4.2的測試手機(jī)htc incredable s針對一個(gè)只有apk的notepad應(yīng)用做過同樣的驗(yàn)證,在測試手機(jī)上運(yùn)行完全沒有問題。該測試代碼如下:

成都創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的河池網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

package com.example.android.notepad.tryout;  import com.robotium.solo.Solo;  import android.test.ActivityInstrumentationTestCase2; import android.widget.TextView; import android.app.Activity;  @SuppressWarnings("rawtypes") public class NotePadTest extends ActivityInstrumentationTestCase2{  	private static Solo solo = null; 	public Activity activity; 	 	private static final int NUMBER_TOTAL_CASES = 2; 	private static int run = 0; 	 	private static Class launchActivityClass; 	//對應(yīng)re-sign.jar生成出來的信息框里的兩個(gè)值 	private static String mainActiviy = "com.example.android.notepad.NotesList"; 	private static String packageName = "com.example.android.notepad";  	static {  		try {  			launchActivityClass = Class.forName(mainActiviy);  		} catch (ClassNotFoundException e) {  			throw new RuntimeException(e);  		}  	} 	 	 	@SuppressWarnings("unchecked") 	public NotePadTest() { 		super(packageName, launchActivityClass); 	}  	 	@Override 	public void setUp() throws Exception { 		//setUp() is run before a test case is started.  		//This is where the solo object is created. 		super.setUp();  		//The variable solo has to be static, since every time after a case's finished, this class TCCreateNote would be re-instantiated 		// which would lead to soto to re-instantiated to be null if it's not set as static 		//TextView title = (TextView)getActivity().findViewById(Ref.id.title); 		 		if(solo == null) { 			 			NotePadTest.solo = new Solo(getInstrumentation(),getActivity()); 			 		} 	} 	 	@Override 	public void tearDown() throws Exception { 		//Check whether it's the last case executed. 		run += countTestCases(); 		if(run >= NUMBER_TOTAL_CASES) { 			solo.finishOpenedActivities(); 		} 	}  	public void testAddNoteCNTitle() throws Exception { 		//Thread.sleep(5000); 		solo.clickOnMenuItem("Add note"); 		solo.enterText(0, "中文標(biāo)簽筆記"); 		solo.clickOnMenuItem("Save"); 		solo.clickInList(0); 		solo.clearEditText(0); 		solo.enterText(0, "Text 1"); 		solo.clickOnMenuItem("Save"); 		solo.assertCurrentActivity("Expected NotesList Activity", "NotesList"); 		 		solo.clickLongOnText("中文標(biāo)簽筆記"); 		solo.clickOnText("Delete"); 		 		 	} 	 	 	public void testAddNoteEngTitle() throws Exception { 		solo.clickOnMenuItem("Add note"); 		solo.enterText(0, "English Title Note"); 		solo.clickOnMenuItem("Save"); 		solo.clickInList(0); 		solo.clearEditText(0); 		solo.enterText(0, "Text 1"); 		solo.clickOnMenuItem("Save"); 		solo.assertCurrentActivity("Expected NotesList Activity", "NotesList"); 		 		solo.clickLongOnText("English Title Note"); 		solo.clickOnText("Delete"); 	} }


但在工作的測試目標(biāo)平臺launcher中使用同樣的方法去setup并運(yùn)行簡單的測試時(shí)碰到問題:測試程序一直掛起沒有返回,程序掛起在以下getaActivity()方法(因是公司代碼,故以notepad測試代碼取代之):
	@Override 	public void setUp() throws Exception { 		//setUp() is run before a test case is started.  		//This is where the solo object is created. 		super.setUp();  		//The variable solo has to be static, since every time after a case's finished, this class TCCreateNote would be re-instantiated 		// which would lead to soto to re-instantiated to be null if it's not set as static 		 		if(solo == null) {		 			NotePadTest.solo = new Solo(getInstrumentation(),getActivity());	 		} 	}

當(dāng)時(shí)一直懷疑是否系統(tǒng)launcher的robotium初始化和setup方法跟普通的apk不一樣,google上有歷史文章描述getActivity()在Android 2.xx.xx上確實(shí)有這個(gè)問題,但后來的版本已經(jīng)解決,而本人使用的時(shí)當(dāng)前最的4.4.2,所以不應(yīng)該還存在這種問題。針對這個(gè)思路去嘗試找解決辦法終無果。

2.問題分析

既然是getActvity()方法出現(xiàn)問題,而該方法原有的bug也已經(jīng)在最新的版本fixed,在google無所獲的情況下也只能剩下分析源碼這條路了。因?yàn)槭亲约簞傇赽ackbook上搭建的自動(dòng)化研究平臺,為了節(jié)省時(shí)間,當(dāng)時(shí)沒有下載android的相應(yīng)源碼,只有sdk,所以第一步必須是先在項(xiàng)目中配置使用上android的源碼,其理與配置javadoc相近,請查看本人之前的一篇文章《How to Configure Javadoc for Robotium Library》,這里不做累術(shù)。

加入源碼后調(diào)試分析,最終程序掛起在android.test.InstrumentationTestCase中的launchActivityWithIntent方法中,以下是eclipse中的調(diào)試截圖示例:
Robotium中調(diào)用getActivity()方法導(dǎo)致程序掛起的研究淺析
以下是該方法的完整代碼片段:
/**      * Utility method for launching an activity with a specific Intent.      *       * 

NOTE: The parameter pkg must refer to the package identifier of the * package hosting the activity to be launched, which is specified in the AndroidManifest.xml * file. This is not necessarily the same as the java package name. * * @param pkg The package hosting the activity to be launched. * @param activityCls The activity class to launch. * @param intent The intent to launch with * @return The activity, or null if non launched. */ @SuppressWarnings("unchecked") public final T launchActivityWithIntent( String pkg, Class activityCls, Intent intent) { intent.setClassName(pkg, activityCls.getName()); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); T activity = (T) getInstrumentation().startActivitySync(intent); getInstrumentation().waitForIdleSync(); return activity; }


導(dǎo)致掛起的位置是里面的getInstrumentation().waitForIdleSync()方法,到了這里再代碼跟蹤進(jìn)去看到的就是android.app.instrumentation這個(gè)基類里面:
    /**      * Synchronously wait for the application to be idle.  Can not be called      * from the main application thread -- use {@link #start} to execute      * instrumentation in its own thread.      */     public void waitForIdleSync() {         validateNotAppThread();         Idler idler = new Idler(null);         mMessageQueue.addIdleHandler(idler);         mThread.getHandler().post(new EmptyRunnable());         idler.waitForIdle();     }
這里按照本人的理解做的事情大概如下:
  • 首先確保調(diào)用這個(gè)方法的來源不是application的主線程
  • 然后把當(dāng)前等待application變成idle的請求放到消息隊(duì)列中
  • 最后等待app在處理完所有事件達(dá)到idle狀態(tài)的時(shí)候返回
看到這里我幡然領(lǐng)悟,在目標(biāo)平臺上面我們有一個(gè)天氣預(yù)報(bào)的功能,在不停的發(fā)送事件給application(也就是launcher)來更新當(dāng)前的天氣情況,所以一直沒有達(dá)到idle的狀態(tài),這樣這個(gè)函數(shù)也就一直沒有返回而掛起了。而在本人的測試手機(jī)上測試的notepad這個(gè)apk,一進(jìn)去的launchable activity就是idle的,所以不會碰到這個(gè)問題。

帶著這個(gè)思路在調(diào)整google關(guān)鍵字在stackoverflow中找到了國外同行碰到的一個(gè)類似的問題:http://stackoverflow.com/questions/20860832/why-does-getactivity-block-during-junit-test-when-custom-imageview-calls-start
這里總結(jié)下本人研究過程中了解到的robotium初始化solo的時(shí)候new Solo(getInstrumentation(),getActivity())中g(shù)etActivity所做的事情:
  • 如果目標(biāo)activity沒有起來,那么啟動(dòng)該activity并放在前臺
  • 如果目標(biāo)activity已經(jīng)起來,那么直接放在前臺等待被測試
  • 如果該該activity所屬application在自動(dòng)不停的接受事件,直接調(diào)用getActivity會因?yàn)橐恢钡却齛pplication變成idle狀態(tài)而掛起

3. 解決方法

本人按照項(xiàng)目中的目標(biāo)測試launcher的實(shí)際情況想到的解決方法是在初始化solo的時(shí)候不去調(diào)用getActivity()這個(gè)InstrumentationTestCase2的方法:
solo = new Solo(getInstrumentation());
因?yàn)槲覀兊膌auncher在robotium在kill掉原來的launcher進(jìn)程的時(shí)候就會自動(dòng)起來,所以并不需要手動(dòng)的去getActivity()去啟動(dòng)。這種方法在不能啟動(dòng)起來的apk如notepad上面就不行,不信你去掉getActivity()的調(diào)用,保證notepad不會啟動(dòng)或者放到前臺。但是如果你在開始測試前先把notepad手動(dòng)起來并放到前臺,測試還是會正常進(jìn)行的。比如以下的驗(yàn)證性代碼:
package com.example.android.notepad.tryout;  import com.robotium.solo.Solo;  import android.test.ActivityInstrumentationTestCase2; import android.widget.TextView; import android.app.Activity;  @SuppressWarnings("rawtypes") public class NotePadTest extends ActivityInstrumentationTestCase2{  	private static Solo solo = null; 	public Activity activity; 	 	private static final int NUMBER_TOTAL_CASES = 2; 	private static int run = 0; 	 	private static Class launchActivityClass; 	//對應(yīng)re-sign.jar生成出來的信息框里的兩個(gè)值 	private static String mainActiviy = "com.example.android.notepad.NotesList"; 	private static String packageName = "com.example.android.notepad";  	static {  		try {  			launchActivityClass = Class.forName(mainActiviy);  		} catch (ClassNotFoundException e) {  			throw new RuntimeException(e);  		}  	} 	 	 	@SuppressWarnings("unchecked") 	public NotePadTest() { 		super(packageName, launchActivityClass); 	}  	 	@Override 	public void setUp() throws Exception { 		//setUp() is run before a test case is started.  		//This is where the solo object is created. 		super.setUp();  		//The variable solo has to be static, since every time after a case's finished, this class TCCreateNote would be re-instantiated 		// which would lead to soto to re-instantiated to be null if it's not set as static 		//TextView title = (TextView)getActivity().findViewById(Ref.id.title); 		 		if(solo == null) { 			 			NotePadTest.solo = new Solo(getInstrumentation());//, getActivity()); 			 		} 	} 	 	@Override 	public void tearDown() throws Exception { 		//Check whether it's the last case executed. 		run += countTestCases(); 		if(run >= NUMBER_TOTAL_CASES) { 			solo.finishOpenedActivities(); 		} 	}  	public void testAddNoteCNTitle() throws Exception { 		//getActivity(); 		Thread.sleep(5000); 		solo.clickOnMenuItem("Add note"); 		solo.enterText(0, "中文標(biāo)簽筆記"); 		solo.clickOnMenuItem("Save"); 		solo.clickInList(0); 		solo.clearEditText(0); 		solo.enterText(0, "Text 1"); 		solo.clickOnMenuItem("Save"); 		solo.assertCurrentActivity("Expected NotesList Activity", "NotesList"); 		 		solo.clickLongOnText("中文標(biāo)簽筆記"); 		solo.clickOnText("Delete"); 		 		 	} }
初始化solo的時(shí)候和testcase里面都沒有去調(diào)用getActivity(),但是在testcase開始前先睡眠5秒,如果在這5秒的過程中你手動(dòng)把notepad給啟動(dòng)起來,那么睡眠時(shí)間過后測試會繼續(xù)正常運(yùn)行。

剛才stackoverflow上提到的另外一個(gè)方法是重寫getActivity()這個(gè)IntrumentationTestCase2的方法(注意我們所有的robotium測試類都是繼承于該class的):
@Override     public MyActivity getActivity() {         if (mActivity == null) {             Intent intent = new Intent(getInstrumentation().getTargetContext(), MyActivity.class);             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);             // register activity that need to be monitored.             monitor = getInstrumentation().addMonitor(MyActivity.class.getName(), null, false);             getInstrumentation().getTargetContext().startActivity(intent);             mActivity = (MyActivity) getInstrumentation().waitForMonitor(monitor);             setActivity(mActivity);         }         return mActivity;     }
鑒于本人現(xiàn)在只是做前期的可行×××,夠用就好,且周末手頭上也沒有目標(biāo)機(jī)器在手進(jìn)行驗(yàn)證,所以有興趣的朋友就自己去嘗試下吧,


    •  

      作者

      自主博客

      微信

      CSDN

      天地會珠海分舵

      http://techgogogo.com


      服務(wù)號:TechGoGoGo

      掃描碼:

      Robotium中調(diào)用getActivity()方法導(dǎo)致程序掛起的研究淺析

      http://weahome.cn/article/jdcgjs.html

      在線咨詢

      微信咨詢

      電話咨詢

      028-86922220(工作日)

      18980820575(7×24)

      提交需求

      返回頂部

      <strike id="ugs0e"></strike>
    • <ul id="ugs0e"><sup id="ugs0e"></sup></ul>