Android面試題
http://topic.csdn.net/u/20101219/21/b6f83d6f-35b5-49ea-b281-d47ca662ea17.html?573241. 請描述下Activity的生命周期。
2. 如果后臺的Activity由于某原因被系統回收了,如何在被系統回收之前保存當前狀態?
3. 如何將一個Activity設置成窗口的樣式。(Edited by Sodino)
4. 如何退出Activity?如何安全退出已調用多個Activity的Application?
5. 請介紹下Android中常用的五種布局。
6. 請介紹下Android的數據存儲方式。(Edited by Sodino)
7. 請介紹下ContentProvider是如何實現數據共享的。(Edited by Sodino)
8. 如何啟用Service,如何停用Service。(Edited by Sodino)
9. 注冊廣播有幾種方式,這些方式有何優缺點?請談談Android引入廣播機制的用意。
10. 請解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關系。
11. AIDL的全稱是什么?如何工作?能處理哪些類型的數據?
12. 請解釋下Android程序運行時權限與文件系統權限的區別。(Edited by Sodino)
13. 系統上安裝了多種瀏覽器,能否指定某瀏覽器訪問指定頁面?請說明原由。
14. 有一個一維整型數組int[]data保存的是一張寬為width,高為height的圖片像素值信息。請寫一個算法,將該圖片所有的白色不透明(0xffffffff)像素點的透明度調整為50%。
15. 你如何評價Android系統?優缺點。
1.activity的生命周期。
2.橫豎屏切換時候activity的生命周期
總結:
1、不設置Activity的android:configChanges時,切屏會重新調用各個生命周期,切橫屏時會執行一次,切豎屏時會執行兩次
2、設置Activity的android:configChanges="orientation"時,切屏還是會重新調用各個生命周期,切橫、豎屏時只會執行一次
3、設置Activity的android:configChanges="orientation|keyboardHidden"時,切屏不會重新調用各個生命周期,只會執行onConfigurationChanged方法
3.android中的動畫有哪幾類,它們的特點和區別是什么
4.handler機制的原理
5.說說activity,intent,service是什么關系
6.android中線程與線程,進程與進程之間如何通信
7.widget相對位置的完成在antivity的哪個生命周期階段實現
8.說說mvc模式的原理,它在android中的運用
9.說說在android中有哪幾種數據存儲方式
10.android中有哪幾種解析xml的類,官方推薦哪種?以及它們的原理和區別
3. 如何將一個Activity設置成窗口的樣式。
設置Activity窗口化:
android:theme="@android:style/Theme.Dialog"
設置Activity透明化:
android:theme="@android:style/Theme.Translucent"
6. 請介紹下Android的數據存儲方式
㈠.文件存儲方式:
在Android中通常使用File存儲方式是用 Context.openFileOutput(String fileName, int mode)和Context.openFileInput(String fileName)。
Context.openFileOutput(String fileName, int mode)生成的文件自動存儲在/data/data/PackageName/file目錄下,其全路徑是/data/data/Package Name/files/fileName 。注意下,這里的參數fileName不可以包含路徑分割符(如"/")。
通常來說,這種方式生成的文件只能在這個apk內訪問。但這個結論是指使用Context.openFileInput(String fileName)的方式。使用這種方式,每個apk只可以訪問自己的/data/data/Package Name/files目錄下的文件,原因很簡單,參數fileName中不可以包含路徑分割符,Android會自動在/data/data /Package Name/files目錄下尋找文件名為fileName的文件。
具體實例如下:
String fn = “moandroid.log”;
FileInputStream fis = openFileInput(fn);
FileOutputStream fos = openFileOutput(fn.Context.MODE_PRIVATE);
㈡.使用SharedPreferences存儲數據
首先說明SharedPreferences存儲方式,它是 Android提供的用來存儲一些簡單配置信息的一種機制,例如:登錄用戶的用戶名與密碼。其采用了Map數據結構來存儲數據,以鍵值的方式存儲,可以簡單的讀取與寫入,具體實例如下:
void ReadSharedPreferences(){
String strName,strPassword;
SharedPreferences user = getSharedPreferences(“user_info”,0);
strName = user.getString(“NAME”,””);
strPassword = user getString(“PASSWORD”,””);
}
void WriteSharedPreferences(String strName,String strPassword){
SharedPreferences user = getSharedPreferences(“user_info”,0);
uer.edit()//獲得編輯器;
user.putString(“NAME”, strName);
user.putString(“PASSWORD” ,strPassword);
user.commit();
}
數據讀取與寫入的方法都非常簡單,只是在寫入的時候有些區別:先調用edit()使其處于編輯狀態,然后才能修改數據,最后使用commit()提交修改的數據。實際上SharedPreferences是采用了XML格式將數據存儲到設備中,在DDMS中的File Explorer中的/data/data/<package name>/shares_prefs下。以上面的數據存儲結果為例,打開后可以看到一個user_info.xml的文件,打開后可以看到:
<?xml version=”1.0″ encoding=”UTF-8″?>
<map>
<string name=”NAME”>moandroid</string>
<string name=” PASSWORD”>SharedPreferences</string>
</map>
使用SharedPreferences是有些限制的:只能在同一個包內使用,不能在不同的包之間使用。
㈢:網絡存儲數據
網絡存儲方式,需要和Android網絡數據包打交道。
㈣.ContentProvider數據存儲
1、ContentProvider簡介
當應用繼承ContentProvider類,并重寫該類用于提供數據和存儲數據的方法,就可以向其他應用共享其數據。雖然使用其他方法也可以對外共享數據,但數據訪問方式會因數據存儲的方式而不同,如:采用文件方式對外共享數據,需要進行文件操作讀寫數據;采用sharedpreferences共享數據,需要使用sharedpreferences API讀寫數據。而使用ContentProvider共享數據的好處是統一了數據訪問方式。與之相關聯的是uri,下面是uri的簡介:
2、Uri類簡介
Uri代表了要操作的數據,Uri主要包含了兩部分信息:需要操作的ContentProvider和對ContentProvider中的什么數據進行操作,一個Uri由以下幾部分組成:
1).scheme:ContentProvider(內容提供者)的scheme已經由Android所規定為:content://。
2).主機名(或Authority):用于唯一標識這個ContentProvider,外部調用者可以根據這個標識來找到它。
3).路徑(path):可以用來表示我們要操作的數據,路徑的構建應根據業務而定,如下:
要操作contact表中id為10的記錄,可以構建這樣的路徑:/contact/10
要操作contact表中id為10的記錄的name字段, contact/10/name
要操作contact表中的所有記錄,可以構建這樣的路徑:/contact?
要操作的數據不一定來自數據庫,也可以是文件等他存儲方式,如下:
要操作xml文件中contact節點下的name節點,可以構建這樣的路徑:/contact/name
如果要把一個字符串轉換成Uri,可以使用Uri類中的parse()方法,如下:
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
3、UriMatcher、ContentUrist和ContentResolver簡介
因為Uri代表了要操作的數據,所以我們很經常需要解析Uri,并從 Uri中獲取數據。Android系統提供了兩個用于操作Uri的工具類,分別為UriMatcher 和ContentUris 。掌握它們的使用,會便于我們的開發工作。
? UriMatcher:用于匹配Uri,它的用法如下:
1).首先把你需要匹配Uri路徑全部給注冊上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼(-1)。
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider /contact路徑,返回匹配碼為1
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就會返回匹配碼
//如果match()方法匹配 content://com.changcheng.sqlite.provider.contactprovider/contact/230路徑,返回匹配碼為2
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#號為通配符
2).注冊完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法對輸入的Uri進行匹配,如果匹配就返回匹配碼,匹配碼是調用 addURI()方法傳入的第三個參數,假設匹配 content://com.changcheng.sqlite.provider.contactprovider/contact路徑,返回的匹配碼為1。
ContentUris:用于獲取Uri路徑后面的ID部分,它有兩個比較實用的方法:
withAppendedId(uri, id)用于為路徑加上ID部分
parseId(uri)方法用于從路徑中獲取ID部分
ContentResolver:當外部應用需要對ContentProvider中的數據進行添加、刪除、修改和查詢操作時,可以使用 ContentResolver 類來完成,要獲取ContentResolver 對象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,來操作數據。
㈤.數據庫存儲方式?
數據庫存儲方式,最長用的是SQLite
8. 如何啟用Service,如何停用Service
● 啟動方式和停止方式:
㈠.Context.startService() / Context.stopService();
㈡. Context.bindService() / Context.unbindService();
9. 注冊廣播有幾種方式,這些方式有何優缺點?請談談Android引入廣播機制的用意。
在android下,要想接受廣播信息,那么這個廣播接收器就得我們自己來實現了,我們可以繼承BroadcastReceiver,就可以有一個廣播接受器了。有個接受器還不夠,我們還得重寫BroadcastReceiver里面的onReceiver方法,當來廣播的時候我們要干什么,這就要我們自己來實現,不過我們可以搞一個信息防火墻。具體的代碼:
public class SmsBroadCastReceiver extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent)
{
Bundle bundle = intent.getExtras();
Object[] object = (Object[])bundle.get("pdus");
SmsMessage sms[]=new SmsMessage[object.length];
for(int i=0;i<object.length;i++)
{
sms[0] = SmsMessage.createFromPdu((byte[])object[i]);
Toast.makeText(context, "來自 "+sms[i].getDisplayOriginatingAddress()+" 的消息是:"+sms[i].getDisplayMessageBody(), Toast.LENGTH_SHORT).show();
}
//終止廣播,在這里我們可以稍微處理,根據用戶輸入的號碼可以實現短信防火墻。
abortBroadcast();
}
}
當實現了廣播接收器,還要設置廣播接收器接收廣播信息的類型,這里是信息:android.provider.Telephony.SMS_RECEIVED
我們就可以把廣播接收器注冊到系統里面,可以讓系統知道我們有個廣播接收器。這里有兩種,
? 一種是代碼動態注冊:
//生成廣播處理
smsBroadCastReceiver = new SmsBroadCastReceiver();
//實例化過濾器并設置要過濾的廣播
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
//注冊廣播
BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver, intentFilter);
? 一種是在AndroidManifest.xml中配置廣播
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="spl.broadCastReceiver"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".BroadCastReceiverActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--廣播注冊-->
<receiver android:name=".SmsBroadCastReceiver">
<intent-filter android:priority="20">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
<uses-sdk android:minSdkVersion="7" />
<!-- 權限申請 -->
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
</manifest>
兩種注冊類型的區別是:
1)第一種不是常駐型廣播,也就是說廣播跟隨程序的生命周期。
2)第二種是常駐型,也就是說當應用程序關閉后,如果有信息廣播來,程序也會被系統調用自動運行
請解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關系。
2.2 Message Queue
在單線程模型下,為了解決類似的問題,Android設計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue并結合Handler和Looper組件進行信息交換。下面將對它們進行分別介紹:
1. Message
Message消息,理解為線程間交流的信息,處理數據后臺線程需要更新UI,則發送Message內含一些數據給UI線程。
2. Handler
Handler處理者,是Message的主要處理者,負責Message的發送,Message內容的執行處理。后臺線程就是通過傳進來的 Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message)
方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。
3. Message Queue
Message Queue消息隊列,用來存放通過Handler發布的消息,按照先進先出執行。
每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法發送消息:sendMessage或post。這兩種消息都會插在message queue隊尾并按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過sendMessage發送的是一個message對象,會被 Handler的handleMessage()函數處理;而通過post方法發送的是一個runnable對象,則會自己執行。
4. Looper
Looper是每條線程里的Message Queue的管家。Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程里并沒有建立Message Queue。所以調用Looper.getMainLooper()得到的主線程的Looper不為NULL,但調用Looper.myLooper() 得到當前線程的Looper就有可能為NULL。
對于子線程使用Looper,API Doc提供了正確的使用方法:
這個Message機制的大概流程:
1. 在Looper.loop()方法運行開始后,循環地按照接收順序取出Message Queue里面的非NULL的Message。
2. 一開始Message Queue里面的Message都是NULL的。當Handler.sendMessage(Message)到Message Queue,該函數里面設置了那個Message對象的target屬性是當前的Handler對象。隨后Looper取出了那個Message,則調用該Message的target指向的Hander的dispatchMessage函數對Message進行處理。
在dispatchMessage方法里,如何處理Message則由用戶指定,三個判斷,優先級從高到低:
1) Message里面的Callback,一個實現了Runnable接口的對象,其中run函數做處理工作;
2) Handler里面的mCallback指向的一個實現了Callback接口的對象,由其handleMessage進行處理;
3) 處理消息Handler對象對應的類繼承并實現了其中handleMessage函數,通過這個實現的handleMessage函數處理消息。
由此可見,我們實現的handleMessage方法是優先級最低的!
3. Handler處理完該Message (update UI) 后,Looper則設置該Message為NULL,以便回收!
在網上有很多文章講述主線程和其他子線程如何交互,傳送信息,最終誰來執行處理信息之類的,個人理解是最簡單的方法——判斷Handler對象里面的 Looper對象是屬于哪條線程的,則由該線程來執行!
1. 當Handler對象的構造函數的參數為空,則為當前所在線程的Looper;
2. Looper.getMainLooper()得到的是主線程的Looper對象,Looper.myLooper()得到的是當前線程的Looper對象。
11. AIDL的全稱是什么?如何工作?能處理哪些類型的數據?
AIDL(AndRoid接口描述語言)是一種接口描述語言; 編譯器可以通過aidl文件生成一段代碼,通過預先定義的接口達到兩個進程內部通信進程的目的. 如果需要在一個Activity中, 訪問另一個Service中的某個對象, 需要先將對象轉化成AIDL可識別的參數(可能是多個參數), 然后使用AIDL來傳遞這些參數, 在消息的接收端, 使用這些參數組裝成自己需要的對象.
AIDL的IPC的機制和COM或CORBA類似, 是基于接口的,但它是輕量級的。它使用代理類在客戶端和實現層間傳遞值. 如果要使用AIDL, 需要完成2件事情: 1. 引入AIDL的相關類.; 2. 調用aidl產生的class.
AIDL的創建方法:
AIDL語法很簡單,可以用來聲明一個帶一個或多個方法的接口,也可以傳遞參數和返回值。由于遠程調用的需要, 這些參數和返回值并不是任何類型.
下面是些AIDL支持的數據類型:
1. 不需要import聲明的簡單Java編程語言類型(int,boolean等)
2. String, CharSequence不需要特殊聲明
3. List, Map和Parcelables類型, 這些類型內所包含的數據成員也只能是簡單數據類型, String等其他比支持的類型.
12. 請解釋下Android程序運行時權限與文件系統權限的區別
要區分apk運行時的擁有的權限與在文件系統上被訪問(讀寫執行)的權限兩個概念。
apk程序是運行在虛擬機上的,對應的是Android獨特的權限機制,只有體現到文件系統上時才使用linux的權限設置
(一)linux文件系統上的權限
-rwxr-x--x system system 4156 2010-04-30 16:13 test.apk
代表的是相應的用戶/用戶組及其他人對此文件的訪問權限,與此文件運行起來具有的權限完全不相關。比如上面的例子只能說明system用戶擁有對此文件的讀寫執行權限;system組的用戶對此文件擁有讀、執行權限;其他人對此文件只具有執行權限。
而test.apk運行起來后可以干哪些事情,跟這個就不相關了。
千萬不要看apk文件系統上屬于system/system用戶及用戶組,或者root/root用戶及用戶組,就認為apk具有system或root權限
(二)Android的權限規則
(1)Android中的apk必須簽名
這種簽名不是基于權威證書的,不會決定某個應用允不允許安裝,而是一種自簽名證書。重要的是,android系統有的權限是基于簽名的。比如:system等級的權限有專門對應的簽名,簽名不對,權限也就獲取不到。
默認生成的APK文件是debug簽名的。
(2)基于UserID的進程級別的安全機制
大家都知道,進程有獨立的地址空間,進程與進程間默認是不能互相訪問的,是一種很可靠的保護機制。
Android通過為每一個安裝在設備上的包(apk)分配唯一的linux userID來實現,名稱為"app_"加一個數字,比如app_43
不同的UserID,運行在不同的進程,所以apk之間默認便不能相互訪問。
Android提供了如下的一種機制,可以使兩個apk打破前面講的這種壁壘。
在AndroidManifest.xml中利用sharedUserId屬性給不同的package分配相同的userID,通過這樣做,兩個package可以被當做同一個程序,
系統會分配給兩個程序相同的UserID。當然,基于安全考慮,兩個package需要有相同的簽名,否則沒有驗證也就沒有意義了。
(這里補充一點:并不是說分配了同樣的UserID,兩程序就運行在同一進程, 下面為PS指令摘取的,
顯然,system、app_2分別對應的兩個進程的PID都不同,不知Android到底是怎樣實現它的機制的)
User PID PPID
system 953 883 187340 55052 ffffffff afe0cbcc S system_server
app_2 1072 883 100264 19564 ffffffff afe0dcc4 S com.android.inputmethod.
system 1083 883 111808 23192 ffffffff afe0dcc4 S android.process.omsservi
app_2 1088 883 156464 45720 ffffffff afe0dcc4 S android.process.acore
(3)默認apk生成的數據對外是不可見的
實現方法是:Android會為程序存儲的數據分配該程序的UserID。
借助于Linux嚴格的文件系統訪問權限,便實現了apk之間不能相互訪問似有數據的機制。
例:我的應用創建的一個文件,默認權限如下,可以看到只有UserID為app_21的程序才能讀寫該文件。
-rw------- app_21 app_21 87650 2000-01-01 09:48 test.txt
如何對外開放?
<1> 使用MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE 標記。
When creating a new file with getSharedPreferences(String, int), openFileOutput(String, int), or openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory), you can use the MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE flags to allow any other package to read/write the file. When setting these flags, the file is still owned by your application, but its global read and/or write permissions have been set appropriately so any other application can see it.
(4)AndroidManifest.xml中的顯式權限聲明
Android默認應用是沒有任何權限去操作其他應用或系統相關特性的,應用在進行某些操作時都需要顯式地去申請相應的權限。
一般以下動作時都需要申請相應的權限:
A particular permission may be enforced at a number of places during your program's operation:
• At the time of a call into the system, to prevent an application from executing certain functions.
• When starting an activity, to prevent applications from launching activities of other applications.
• Both sending and receiving broadcasts, to control who can receive your broadcast or who can send a broadcast to you.
• When accessing and operating on a content provider.
• Binding or starting a service.
在應用安裝的時候,package installer會檢測該應用請求的權限,根據該應用的簽名或者提示用戶來分配相應的權限。
在程序運行期間是不檢測權限的。如果安裝時權限獲取失敗,那執行就會出錯,不會提示用戶權限不夠。
大多數情況下,權限不足導致的失敗會引發一個 SecurityException, 會在系統log(system log)中有相關記錄。
(5)權限繼承/UserID繼承
當我們遇到apk權限不足時,我們有時會考慮寫一個linux程序,然后由apk調用它去完成某個它沒有權限完成的事情,很遺憾,這種方法是行不通的。
前面講過,android權限是經營在進程層面的,也就是說一個apk應用啟動的子進程的權限不可能超越其父進程的權限(即apk的權限),
即使單獨運行某個應用有權限做某事,但如果它是由一個apk調用的,那權限就會被限制。
實際上,android是通過給子進程分配父進程的UserID實現這一機制的。
(三)常見權限不足問題分析
首先要知道,普通apk程序是運行在非root、非system層級的,也就是說看要訪問的文件的權限時,看的是最后三位。
另外,通過system/app安裝的apk的權限一般比直接安裝或adb install安裝的apk的權限要高一些。
言歸正傳,運行一個android應用程序過程中遇到權限不足,一般分為兩種情況:
(1)Log中可明顯看到權限不足的提示。
此種情況一般是AndroidManifest.xml中缺少相應的權限設置,好好查找一番權限列表,應該就可解決,是最易處理的情況。
有時權限都加上了,但還是報權限不足,是什么情況呢?
Android系統有一些API及權限是需要apk具有一定的等級才能運行的。
比如 SystemClock.setCurrentTimeMillis()修改系統時間,WRITE_SECURE_SETTINGS權限好像都是需要有system級的權限才行。
也就是說UserID是system.
(2)Log里沒有報權限不足,而是一些其他Exception的提示,這也有可能是權限不足造成的。
比如:我們常會想讀/寫一個配置文件或其他一些不是自己創建的文件,常會報java.io.FileNotFoundException錯誤。
系統認為比較重要的文件一般權限設置的也會比較嚴格,特別是一些很重要的(配置)文件或目錄。
如
-r--r----- bluetooth bluetooth 935 2010-07-09 20:21 dbus.conf
drwxrwx--x system system 2010-07-07 02:05 data
dbus.conf好像是藍牙的配置文件,從權限上來看,根本就不可能改動,非bluetooth用戶連讀的權利都沒有。
/data目錄下存的是所有程序的私有數據,默認情況下android是不允許普通apk訪問/data目錄下內容的,通過data目錄的權限設置可知,其他用戶沒有讀的權限。
所以adb普通權限下在data目錄下敲ls命令,會得到opendir failed, Permission denied的錯誤,通過代碼file.listfiles()也無法獲得data目錄下的內容。
13. 系統上安裝了多種瀏覽器,能否指定某瀏覽器訪問指定頁面?請說明原由。
如果在你的android系統上安裝了多種瀏覽器,能否指定某瀏覽器訪問指定頁面?答案當然是:肯定的。
問題的關鍵在于我們設置了class name,也就是我們想要跳轉的pakcage的activity。如果你想要跳轉到其它的瀏覽器,只需要修改一下這個函數就OK了。
好,我們現在來讓剛剛的思路來指導我們的實踐。假如我們現在要直接啟動UC瀏覽器,那么我們該怎么做呢?讓我們step by step吧。
1.下載UC apk:http://i-uc.net/read.php?2
2. 用7zip解壓apk文件,得到classes.dex文件
3.下載反編譯dex文件工具:http://nchc.dl.sourceforge.net/project/dedexer/dedexer/1.5/ddx1.5.jar(Dedexer 項目主頁: http://dedexer.sourceforge.net/)
4.執行命令:java -jar ddx1.5.jar -o -D -d c:\ c:\classes.dex
5. 得到package name是:com.uc.browser,啟動的activity是:com.uc.browser.ActivityUpdate(補充:當我在這里選擇采用ActivityBrowser的時候發覺權限不夠,報permiss denied 異常,而且也不是我們要的那個activity,幸運的是在第二次嘗試用ActivityUpdate,剛好能滿足要求)
6.修改上面的代碼為intent.setClassName("com.uc.browser","com.uc.browser.ActivityUpdate");