Android面试简录——组件2
自定义组件 *
- Android怎么动态引用组件?
动态引用:主程序和组件是分离的,组件可以单独升级和卸载。
静态引用:将组件和主程序一起封装在编译后的目标文件中。
可以动态引用的组件有:未安装的apk文件、包括class.dex文件的jar文件、JavaScript脚本、四大应用程序组件(Activity,Service,BroadcastReceiver,Content Provider)。 - 如何将可视组件封装在jar文件中以及如何通过java代码适应不同的屏幕分辨率?
jar文件可以封装很多类型的组件,如可视组件(对Android SDK原生组件的扩展),Activity,Service,BroadcastReceiver,ContentProvider等。
封装:直接将可视组件的.class文件放到jar文件中即可,组件使用的资源文件要放到主工程的res目录的相关子目录中。在XML布局文件中使用组件要指定全名(包名+类名)。
在自定义可视化组件时需要考虑屏幕分辨率的问题,需要将与屏幕分辨率无关的dp或sp转换成实际的像素点:
DisplayMetrics displayMetrics = new DisplayMetrics();
displayMetrics.setToDefaults();
int pixel = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dip, displayMetrics); - 怎么编写一个自定义可视组件?
开发模式:
1.扩展现有的组件。
2.组合多种组件。
3.可以从View继承。 - Android支持的四大应用程序组件可以封装在jar文件中吗?使用时该注意什么?
可以,并在Android工程中静态引用jar文件。使用时需要在AndroidManifest.xml文件中注册。 - 如何动态装载apk文件(未安装)的类?
//my.apk表示要动态加载的apk文件,my_temp.apk表示为了优化临时生产的apk文件
DexFile dexFile = dalvik.system.DexFile.loadDex(
"/sdcard/my.apk", "/sdcard/my_temp.apk", 0);
//装载apk文件中的类并创建该类的对象实例
Object obj = dexFile.loadClass(
"mobile.android.file.explorer.widget.Test", null).newInstance();
//利用反射技术获取getName方法的Method对象
Method method = obj.getClass().getDeclaredMethod("getName", null);
//调用类中的方法,并获取方法返回值
String result = String.valueOf(method.invoke(obj, null));
【拓展】强类型与aidl文件
如果使用强类型访问apk文件中的类,一般需要将该类实现的接口提供给调用者,或者提供一个aidl文件(mobile.android.file.explorer.widget包中),如:
package mobile.android.file.explorer.widget;
interface MyInterface {
String getName();
}
在编译Android工程时ADT会在gen目录中自动生产MyInterface接口,直接引用该接口即可。
- Android应用程序是否可以动态引用jar文件?
JVM格式格式的jar文件不能被Android应用程序动态调用,但包含class.dex文件的jar文件可以。
打包:
jar cvf my.jar classes.dex - 如何判断包含某个Activity Action的Android应用程序是否安装?
调用PackageManager.queryIntentActivities方法查询系统中是否注册了某个Activity Action,如果未返回任何结果,说明系统中没安装包含指定Activity Action的apk程序。
PackageManager packageManager = getPackageManager();
Intent intent = new Intent("com.android.phone.action.TOUCH_DIALER");
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(
intent, PackageManager.GET_INTENT_FILTERS);
if (resolveInfo.size() == 0)
Log.d("Activity Action", "Activity Action不存在");
【拓展】判断四大应用程序组件是否安装
1.BroadcastReceiver:(与Activity类似)
PackageManager packageManager = new PackageManager();
Intent intent = new Intent("mobile.android.MYBROADCAST");
List<ResolveInfo> resolveInfos = packageManager.queryBroadcastReceivers(
intent, PackageManager.GET_INTENT_FILTERS);
if (resolveInfos.size() == 0)
Log.d("Broadcast Action", "不存在");
2.Service(AIDL Service):AIDL Service在调用时需要使用bindService进行绑定,如果AIDL Service不存在则绑定失败。
if (! bindService(new Intent("mobile.android.IMyService"),
serviceConnection, Context.BIND_AUTO_CREATE)) {
Log.d("AIDL Service", "不存在");
}
3.ContentProvider:根据ContentResolver对象的相应方法的返回值进行判断。
Uri uri = Uri.parse("content://mobile.android.regioncontentprovider/cities");
Cursor cursor = getContentResolver().query(uri,
new String[] {"city_code as_id", "city_name"}, null, null, null);
if (cursor == null)
Log.d("Content Provider", "不存在");
- 在Android应用程序中Java与JavaScript如何交互?
WebView组件——可以执行JavaScript脚本,也允许在JavaScript脚本中执行java代码。
1. Java执行JavaScript脚本:
WebView webView = new WebView(this);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setWebChromeClient(new WebChromeClient());
webView.loadDataWithBaseURL(null, s, "text/html", "utf-8", null);
2.Java与JavaScript间传递数据,JavaScript脚本执行Java代码:
WebView.addJavascriptInterface(new Object(){
public void move(int x, int, y) {
//Java代码
}
}, "demo"); //demo为JavaScript中可访问的对象,通过该对象调用move方法
在JavaScript中调用move方法:
<script language="javascript">
window.demo.move(20, 100);
</script>
【拓展】Java与JavaScript交互的传统方法
在Java代码中通过占位符替换的方式向JavaScript脚本中传递参数。
JavaScript代码:
<script language="javascript">
function myFun(age, salary) {
//JavaScript脚本
};
myFun(#age#, #salary#);
</script>
将整个JavaScript脚本读到内存中,并将#age#和#salary#替换成相应值,再执行JavaScript脚本。
有返回值:使用alert函数弹出一个对话框,或者在JavaScript中通过HTTP请求发送一个返回值。
-
请描述NDK方法的命名规则,并描述NDK方法中前两个参数的作用。
jstring Java_调用NDK方法的java类全名_本地方法名(JNIEnv *env, jobject obj) {......}
例如:调用NDK方法的java类全名:mobile.android.HelloWorldJNI
本地方法名:process
jstring java_mobile_android_HelloWorldJNI_process(JNIEnv env, jobject obj) {......}
JNIEnv ~ 当前NDK环境的对象指针,可以通过该参数值访问NDK中的内置成员。
jobject ~ 调用当前NDK方法的Java对象,可以用该参数值访问调用当前NDK方法的Java对象的成员。 -
NDK程序怎么访问Java类成员?
根据jobject访问当前NDK方法的Java对象成员。
java类:
public class HelloWorldJNI extends Activity {
String name = "Jobs";
......
}
NDK代码:
jstring Java_mobile_android_jni_helloword_HelloWorldJni_setName(JNIEnv* env, jobject obj) {
jclass cls;
jfieldID fid;
cls = (env) -> GetObjectClass(env, obj);
fid = (env) -> GetFieldID(env, cls, "name", "Ljava/lang/String");
char str;
char str1 = (char)(env) -> GetStringUTFChars(env, (env) -> GetObjectField(env, obj, fid), NULL);
str = (char) malloc(128);
memset(str, 0x0, 128);
strcpy(str, "你好");
strcat(str, str1);
return (*env) -> NewStringUTF(env, str);
} -
如何用Java代码让Android Market显示指定的程序以使用户方便下载?
程序直接调用内置在手机中的Android Market程序进行下载。
通过Activity Action直接调用Android Market的窗口。
>让Android Market直接显示我们所期望的程序:
Uri uri = Uri.parse("market://search?q=应用名称");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
>根据应用程序ID查找:
Uri uri = Uri.parse("market://details?id=mobile.android.library");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent); -
请写出安装apk程序的代码
Intent intent = new Intent(Intent.ACTION_VIEW);
String filePath = "/sdcard/FileExplorer.apk";
intent.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
startActivity(intent);