Android面试简录——组件3

作者: nancymi | 来源:发表于2015-04-07 15:15 被阅读805次

    四大应用程序组件


    Android中的窗口:Activity

    • 如何配置Activity才能让程序启动时将该Activity作为启动窗口?
      在AndroidManifest.xml文件中指定MAIN动作。
      <action android:name="android.intent.action.MAIN" />
    • 请阐述Activity有哪几个生命周期方法以及在Activity现实和销毁的过程中生命周期方法执行的顺序。
      protected void onCreate(Bundle savedInstanceState)
      protected void onStart()
      protected void onRestart()
      protected void onResume()
      protected void onPause()
      protected void onStop()
      protected void onDestroy()
      Activity显示:onCreate -> onStart ->onResume.
      Activity销毁:onPause -> onStop -> onDestroy.
      onStop时Activity重新获得焦点:onRestart -> onStart -> onResume.
    • 调用Activity都有哪几种方法?
      1.显式调用:直接指定Activity
      2.隐式调用:通过Activity Action来调用Activity
    • 在Activity之间如何传递数据?
      1.Intent对象:
      Intent.putExtra ~ 设置要传递的数据
      Intent.getXxxExtra ~ 获取传递的数据
      2.静态变量:public static
      3.剪切板:
      数据保存:
      Intent intent = new Intent(this, MyActivity.class);
      ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
      clipboard.setText("数据");
      startActivity(intent);
      获取数据:
      ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
      String text = clipboard.getText().toString();
      4.全局对象:继承自android.app.Application类
      package mobile.android.transmit.data;
      import android.app.application;
      public class MyApp extends Application {
      public String country;
      public Data data = new Data();
      }
      需要在AndroidManifest.xml中定义该类。
      获取:
      MyApp myApp = (MyApp) getApplicationContext();

    【拓展】通过剪切板传递复杂数据
    问题提出:高版本中支持剪切板保存Intent支持的类型,但是低版本中不支持。
    解决办法:使用字符串传递任何二进制数据(包括可序列化对象、图像的等)。
    1.将可序列化对象转换成Base64编码,然后保存到剪切板中:
    Intent intent = new Intent(this, MyActivity3.class);
    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    Data clipboardData = new Data();
    clipboardData.id = 6666;
    clipboardData.name = "通过Clipboard传递的数据";
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    String base64Str = "";
    try {
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(clipboardData);
    base64Str = Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
    oos.close();
    } catch (Exception e) {
    }
    clipboard.setText(base64Str);
    startActivity(intent);
    2.从剪切板中获取Base64编码格式的字符串,并进行解码,最后还原成Data对象。
    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    String base64Str = clipboard.getText().toString();
    byte[] buffer = Base64.decode(base64Str, Base64.DEFAULT);
    ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
    try {
    ObjectInputStream ois = new ObjectInputStream(bais);
    Data data = (Data) ois.redObject();
    textView.setText(base64Str + "\n\ndata.id:" + data.id + "\ndata.name" + data.name);
    } catch (Exception e) {
    }

    • 请写出直接拨号、将电话号码传入拨号程序、调用拨号程序、调用系统浏览器浏览网页、调用系统程序查看联系人、显示系统设置界面和现实Wi-Fi设置界面的Java程序。
      拨号代码:
      Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678"));
      startActivity(callIntent);
      将电话号码传入拨号程序:
      Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:87654321"));
      startActivity(dialIntent);
      调用拨号程序:
      Intent touchDialerIntent = new Intent("com.android.phone.action.TOUCH_DIALER");
      startActivity(touchDialerIntent);
      调用系统浏览器网页:
      Intent webIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://nokiaguy.blogjava.net"));
      startActivity(webIntent);
      调用系统程序查看联系人:
      Intent contactListIntent = new Intent("com.android.contacts.action.LIST_CONTACTS");
      startActivity(contactListIntent);
      显示系统设置页面:
      Intent settingIntent = new Intent("android.settings.SETTINGS");
      startActivity(settingIntent);
      显示Wi-Fi设置界面:
      Intent wifiSettingsIntent = new Intent("android.settings.WIFI_SETTINGS");
      startActivity(wifiSettingsIntent);
    • 如何将Activity变成半透明的对话框?
      对话框:Theme.Dialog
      半透明:android:windowBackground
      1.定义一个新的主题:
      <style name="MyTheme" parent="@android:style/Theme.Dialog">
      <item name="android:windowBackground">@drawable/msg_background</item>
      </style>
      2.指定主题
      <activity android:name=".Main" android:label="@string/appname" android:theme="@style/MyTheme">
    • 如何设置Activity显示和关闭时的动画效果?
      overridePendingTransition方法
      1.在res/anim中建立对应的动画资源文件
      2.在代码中添加动画效果:
      Intent intent = new Intent(this, AnimationActivity.class);
      startActivity(intent);
      overridePendingTransition(R.anim.fade_in, R.anim.fade_out);

    广播接收器:Broadcast Receiver

    • 如何接收广播?
      接收单个广播:
      1.编写广播接收类。从BroadcastReceiver或其子类继承。
      2.在BroadcastReceiver.onReceive(Context context, Intent intent)方法中编写处理广播的代码。
      *在AndroidManifest.xml文件中注册。
      接收多个广播:
      使用intent.getAction判断当前接收到的是哪个广播。
      if ("action1".equals(intent.getAction())) {
      ...
      }
      if ("action2".equals(intent.getAction())) {
      ...
      }
    • 如何获取短信内容?
      1.编写广播接收器
      onReceive方法如下:
      public void onReceive(Context context, Intent intent) {
      Bundle bundle = new intent.getExtras();
      if (bundle != null) {
      Object[] objArray = (Object[]) bundle.get("pdus");
      SmsMessage[] messages = new SmsMessage[objArray.length];
      for (int i = 0; i < objArray.length; i ++) {
      messages[i] = SmsMessage.createFromPdu((byte[]) objArray[i]);
      String s = "手机号:" + messages[i].getOriginationAddress() + "\n";
      s += "短信内容:" = messages[i].getDisplayMessageBody();
      Toast.makeText(context, s, Toast.LENGTH_LONG).show();
      }
      }
      }
      2.在AndroidManifest.xml文件中定义该广播接收器时添加短信广播Action。
      <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    • 如何拦截来电,并在检测到某些特定号码时自动挂断电话?
      编写一个广播接收类来拦截来电。
      通过反射技术访问Android SDK的内部功能来挂断电话。
      拦截来电的onReceive方法:
      public void onReceive(final Context context, Intent intent) {
      TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
      switch (tm.getCallState()) {
      case TelephonyManager.CALL_STATE_RINGING:
      String incomingNumber = intent.getStringExtra("incoming_number");
      if ("12345678".equals(incomingNumber)) {
      Class<TelephonyManager> telephonyManagerClass = TelephonyManager.class;
      Method telephonyMethod = telephonyManagerClass.getDeclaredMethod("getITelephony", (Class[]) null);
      telephonyMethod.setAccessible(true);
      Object obj = telephonyMethod.invoke(tm, (Object[], null));
      Method endCallMethod = obj.getCLass().getMethod("endCall", null);
      endCallMethod.setAccessible(true);
      endCallMethod.invoke(obj, null);
      }
      break;
      case TelephonyManager.CALL_STATE_OFFHOOK:
      Log.d("call_state", "offhook");
      break;
      case TelephonyManager.CALL_STATE_IDLE:
      closeToast();
      }
      }
      在AndroidManifest.xml文件中设置定义广播接收器:
      <action android:name="android.intent.action.PHONE_STATE"/>
    • 如何拦截手机屏幕休眠和唤醒动作?
      [注意] 该功能的广播接收器只能通过Java代码注册,不能在AndroidManifest.xml文件中注册。
      通过如下两个Broadcast Action可以拦截屏幕休眠和唤醒动作:
      休眠状态:Intent.ACTION_SCREEN_ON
      唤醒状态:Intent.ACTION_SCREEN_OFF
      注册广播接收器(ScreenOnOffReceiver)的代码如下:
      ScreenOnOffReceiver screenOnOffReceiver = new ScreenOnOffReceiver();
      IntentFilter intentFilter = new IntentFilter();
      intentFilter.addAction(Intent.ACTION_SCREEN_ON);
      intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
      registerReceiver(screenOnOffReceiver, intentFilter);
    • 如何让一个Acitivity在开机后自动显示?
      使用广播接收器(StarupReceiver)拦截手机启动广播,然后在onReceive方法中打开Activity。
      public void onReceive(Context context, Intent intent) {
      Intent mainIntent = new Intent(context, Main.class);
      mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      context.startActivity(mainIntent);
      }
      注册:
      <action android:name="android.intent.action.BOOT_COMPLETED"/>
      * 如何发送广播?
      sendBroadcast:
      public void sendBroadcast(Intent intent);

    服务:Service

    • 请描述一下Service的生命周期。
      3个生命周期。
      public void onCreate(); //创建服务
      public void onStart(Intent intent, int startId); //开始服务
      public void onDestroy(); //销毁服务
      首次创建:onCreate() -> onStart().
      再次调用startService/使用startService开始一个已经停止的服务:onStart().
      调用stopService:onDestroy().
    • 请描述一下开发AIDL服务的步骤。
      AIDL:允许一个应用程序访问另一个应用程序的对象。
      建立AIDL服务的步骤:
      1.建立aidl文件(Android工程的Java源文件目录)
      2.如果aidl文件内容正确 -> 自动生成Java接口文件(*.java)
      3.建立一个服务类
      4.实现aidl文件生成的java接口
      5.在AndroidManifest.xml文件中配置AIDL服务。[注意]<action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类构造方法的参数值。
    • AIDL服务支持哪些类型的数据?
      1.Java的简单类型(int,char,boolean等)
      2.String和CharSequence
      3.List和Map
      4.AIDL自动生成的接口类型
      5.实现android.os.Parcelable接口的类

    内容提供者:Content Provider

    • 如何读取联系人信息?
      ListView listView = (ListView) findViewById(R.id.listView);
      Cursor cursor = getContentResolver().query(
      ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
      SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(
      this, android.R.layout.simple_list_item_1, cursor,
      new String[] {ContactsContract.Contacts.DISPLAY_NAME},
      new int[] {android.R.id.text1});
      listView.setAdapter(simpleCursorAdapter);

    • 如何查询收发的短信信息,以及只查收件箱和发件箱?
      ListView lvShortMessages = (ListView) findViewById(R.id.lvShortMessages);
      Cursor cursor = getContentResolver().query(
      Uri.parse("content://sms"), null, "address like ?",
      new String[] {"1%"}, null);
      SMSAdapter smsAdapter = new SMSAdapter(this, cursor);
      lvShortMessages.setAdapter(smsAdapter);
      只查收件箱:"content://sms" -> "content://sms/inbox"
      只查发件箱:"content://sms" -> "content://sms/outbox"

    • 请描述Content Provider URI有哪几部分组件?
      四部分:
      1.content:// ~ 相当于HTTP URI的http://
      2.authority ~ 相当于HTTP URI的域名
      3.路径(path)
      4.参数(param)
      举例:content://mobile.android.mydata/product/20
      分析:authority:mobile.android.mydata
      path:product
      param:20

    • 开发一个Content Provider的步骤。
      1.编写一个类,继承自ContentProvider
      2.实现ContentProvider中所有的抽象方法
      3.定义Content Provider的URI
      4.在static块中使用UriMatcher对象映射Uri和返回码
      static {
      uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
      uriMatcher.addURI(AUTHORITY, "cities", 1);
      uriMatcher.addURI(AUTHORITY, "code/#", 2);
      uriMatcher.addURI(AUTHORITY, "cities_in_province/*", 3);
      }
      5.根须实际的需要实现相应的方法
      6.实现query,insert,delete,update方法时要使用UriMatcher.match方法将URI映射成第4步与URI对应的代码(addURI方法的最后一个参数值)
      public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
      Cursor cursor = null;
      switch (uriMatcher.match(uri)) {
      case 1:
      ...
      break;
      case 2:
      ...
      break;
      default:
      throw new IllegalArgumentException("<" + uri + ">格式不正确");
      }
      return cursor;
      }
      7.在AndroidManifest.xml文件中使用<provider>标签注册Content Provider。
      <provider android:name="RegionContentProvider"
      android:authorities="mobile.android.mydata" />

    • 如何为Content Provider添加访问权限?
      在AndroidManifest.xml文件中的<provider>设置相应的权限,并定义这个权限。
      只读:readPermission
      只写:wirtePermission
      读写:permission
      1.设置权限:
      <provider
      android:name="RegionContentProvider"
      android:authorities="mobile.android.ch11.permission.regioncontentprovider"

          android:readPermission="mobile.android.ch11.permission.regioncontentprovider.READ_REGION" />
      2.定义权限:
      <permission
          android:name="mobile.android.ch11.permission.regioncontentprovider.READ_REGION"
          android:protectionLevel="normal"
          android:label="@string/label"
          android:description="@string/description"
          />

    相关文章

      网友评论

      本文标题:Android面试简录——组件3

      本文链接:https://www.haomeiwen.com/subject/rgkaxttx.html