基础4 Android基础
1. Activity与Fragment的生命周期。
Activity生命周期
打开应用 onCreate()->onStart()->onResume
按BACK键 onPause()->onStop()->onDestory()
按HOME键 onPause()->onStop()
再次启动 onRestart()->onStart()->onResume()
Fragment的生命周期
切换到该Fragment onAttach() onCreate() onCreateView() onActivityCreated() onStart() onResume()
屏幕灭掉 onPause() onSaveInstanceState() onStop()
屏幕解锁 onStart() onResume()
切换到其他Fragment onPause() onStop() onDestroyView()
切换回本身的Fragment onCreateView() onActivityCreated() onStart() onResume()
回到桌面 onPause() onSaveInstanceState() onStop()
回到应用 onStart() onResume()
退出应用 onPause() onStop() onDestroyView() onDestroy() onDetach()
2. Acitivty的四种启动模式与特点。
当应用运行起来后就会开启一条线程,线程中会运行一个任务栈,当Activity实例创建后就会放入任务栈中 Activity启动模式的设置在AndroidManifest.xml文件中,通过配置Activity的属性android:launchMode=""设置
Standard模式(默认) 只要你创建了Activity实例,一旦激活该Activity,则会向任务栈中加入新创建的实例,退出Activity则会在任务栈中销毁该实例
SingleTop模式 考虑当前要激活的Activity实例在任务栈中是否正处于栈顶,如果处于栈顶则无需重新创建新的实例,会重用已存在的实例,否则会在任务栈中创建新的实例
SingleTask模式 如果任务栈中存在该模式的Activity实例,则把栈中该实例以上的Activity实例全部移除,调用该实例的newInstance()方法重用该Activity,使该实例处於栈顶位置,否则就重新创建一个新的Activity实例
SingleInstance模式 当该模式Activity实例在任务栈中创建后,只要该实例还在任务栈中,即只要激活的是该类型的Activity,都会通过调用实例的newInstance()方法重用该Activity,
此时使用的都是同一个Activity实例,它都会处于任务栈的栈顶。 此模式一般用于加载较慢的,比较耗性能且不需要每次都重新创建的Activity
3. Activity缓存方法。
onSaveInstanceState() 和 onRestoreInstanceState()不属于Activity的生命周期,只有意外销毁一个Activity时才被调用,
如内存不足,按下了HOME键(注:按下BACK键则是主动销毁一个Activity,这两个方法不会被调用)。当需要改变屏幕方向时,也可以用这两个方法来暂存一些数据。
下面百度地图应用中的例子,就用到了这两种方法,用来保存和恢复地图的视图。
@Override protected void onSaveInstanceState(Bundle outState) { cPoint = mapView.getMapCenter(); //得到当前MapView的中心点。 outState.putInt("lat", cPoint.getLatitudeE6()); //暂存在outState中 outState.putInt("lon", cPoint.getLongitudeE6()); super.onSaveInstanceState(outState); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { int lat = savedInstanceState.getInt("lat"); //从保存的数据中恢复 int lon = savedInstanceState.getInt("lon"); cPoint = new GeoPoint(lat, lon); super.onRestoreInstanceState(savedInstanceState); }
4. Service的生命周期,两种启动方法,有什么区别。
startService 访问者退出 Service仍然允许 onCreate onStartCommand onDestroy
bindService 访问者退出 Service终止onCreate onBind onUnbind onDestroy
5. 怎么保证service不被杀死。
1 onStartCommand方法,返回START_STICKY
2 提升service优先级 android:priority = "1000"
3 提升service进程优先级
4 onDestroy方法里重启service
6. 广播的两种注册方法,有什么区别。
1.在AndroidManifest.xml文件中注册。
好处:一旦应用程序被安装到手机里,BroadCast Receiver就开始生效。 无论应用程序进程是否运行,运用程序是否在开启状态下都可以接受到广播事件
<receiver android:name=".receiver.SMSReceiver" >
<intent-filter android:priority="1000" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter> </receiver>
2.通过代码的方式注册广播 好处:一旦运用程序停止,广播也跟着停止
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.setPriority(1000);
LockScreenReceiver myReceiver = new LockScreenReceiver();
registerReceiver(myReceiver, filter);
7. Intent的使用方法,可以传递哪些数据类型。
putExtra()
基本数据类型 boolean byte char short int long float double
String CharSequence Parcelable Serializable Bundle 数组 集合
8. ContentProvider使用方法。
增删改查
ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://media/internal/images"); //添加一条记录 ContentValues values = new ContentValues(); values.put("name", "linjiqin"); values.put("age", 25); resolver.insert(uri, values); //获取person表中所有记录 Cursor cursor = resolver.query(uri, null, null, null, null); while(cursor.moveToNext()){ } //把id为1的记录的name字段值更改新为zhangsan ContentValues updateValues = new ContentValues(); updateValues.put("name", "zhangsan"); Uri updateIdUri = ContentUris.withAppendedId(uri, 2); resolver.update(updateIdUri, updateValues, null, null); //删除id为2的记录 Uri deleteIdUri = ContentUris.withAppendedId(uri, 2); resolver.delete(deleteIdUri, null, null);
9. Thread、AsycTask、IntentService的使用场景与特点。
Thread
方式1 class MyThread extends Thread { @Override public void run() { // 处理具体的逻辑 } } new MyThread().start(); 方式2 class MyThread implements Runnable { @Override public void run() { // 处理具体的逻辑 } } MyThread myThread = new MyThread(); new Thread(myThread).start();
Handler+Thread更新
public class MainActivity extends Activity implements OnClickListener { public static final int UPDATE_TEXT = 1; private TextView text; private Button changeText; private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case UPDATE_TEXT: // 在这里可以进行UI操作 text.setText("Nice to meet you"); break; default: break; } } }; @Override public void onClick(View v) { switch (v.getId()) { case R.id.change_text: new Thread(new Runnable() { @Override public void run() { Message message = new Message(); message.what = UPDATE_TEXT; handler.sendMessage(message); // 将Message对象发送出去 } }).start(); break; default: break; } } }
Message 是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据
Message 的what 字段,除此之外还可以使用arg1 和arg2 字段来携带一些整型数据,
使用obj 字段携带一个Object 对象
Handler 处理者 主要是用于发送和处理消息的 发送消息一般是使用Handler 的sendMessage()方法,
而发出的消息经过一系列地辗转处理后,最终会传递到Handler 的handleMessage()方法中
MessageQueue
消息队列 存放所有通过Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。
每个线程中只会有一个MessageQueue对象
Looper
每个线程中的MessageQueue 的管家,调用Looper 的loop()方法后,就会
进入到一个无限循环当中,然后每当发现MessageQueue 中存在一条消息,就会将它取
出,并传递到Handler 的handleMessage()方法中。每个线程中也只会有一个Looper 对象
AsyncTask 从子线程切换到主线程 基于异步消息处理机制的封装
AsyncTask 是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。
在继承时我们可以为AsyncTask 类指定三个泛型参数,这三个参数的用途如下
Params 在执行AsyncTask 时需要传入的参数,可用于在后台任务中使用
Progress 后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位
Result 当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型
需要去重写的方法有以下四个
onPreExecute() 后台任务开始执行之前调用,用于进行一些界面上的初始化操作
doInBackground(Params...) 这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务
不可以进行UI 操作
onProgressUpdate(Progress...) 后台任务中调用了publishProgress(Progress...)方法后,这个方法就会很快被调用
可以对UI 进行操作
onPostExecute(Result) 当后台任务执行完毕并通过return 语句进行返回时,这个方法就很快会被调用
class DownloadTask extends AsyncTask<Void, Integer, Boolean> { @Override protected void onPreExecute() { progressDialog.show(); // 显示进度对话框 } @Override protected Boolean doInBackground(Void... params) { try { while (true) { int downloadPercent = doDownload(); // 这是一个虚构的方法 publishProgress(downloadPercent); if (downloadPercent >= 100) { break; } } } catch (Exception e) { return false; } return true; } @Override protected void onProgressUpdate(Integer... values) { // 在这里更新下载进度 progressDialog.setMessage("Downloaded " + values[0] + "%"); } @Override protected void onPostExecute(Boolean result) { progressDialog.dismiss(); // 关闭进度对话框 // 在这里提示下载结果 if (result) { Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, " Download failed", Toast.LENGTH_SHORT).show(); } } } new DownloadTask().execute();
10. 五种布局: FrameLayout 、 LinearLayout 、 AbsoluteLayout 、 RelativeLayout 、 TableLayout 各自特点及绘制效率对比。
11. Android的数据存储形式。
SharedPreference
文件
SQLite
ContentProvider
12. Sqlite的基本操作。
13. Android中的MVC模式。
MVC是三个单词的缩写,分别为: 模型(Model),视图(View)和控制Controller
Model层实现系统中的业务逻辑。 View层用于与用户的交互。 Controller层是Model与View之间沟通的桥梁,
它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作
GridView显示
GridView就是MVC中的View负责显示
获取设备上安装的应用信息所有对应的方法,这就是对应的Model
BaseAdapter,是Model和View中的桥梁,就是 Controller
14. Merge、ViewStub的作用。
<include />标签能够重用布局文件
<merge /> 删减多余的层级
<ViewStub /> 当你需要时才会加载
加载布局时
((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
或者
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
15. Json有什么优劣势。
JSON的优点:
A.数据格式比较简单,易于读写,格式都是压缩的,占用带宽小;
B.易于解析,客户端JavaScript可以简单的通过eval()进行JSON数据的读取;
C.支持多种语言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等服务器端语言,便于服务器端的解析;
D.在PHP世界,已经有PHP-JSON和JSON-PHP出现了,偏于PHP序列化后的程序直接调用,PHP服务器端的对象、数组等能直接生成JSON格式,便于客户端的访问提取;
E.因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。
JSON的缺点
A.没有XML格式这么推广的深入人心和喜用广泛,没有XML那么通用性;
B.JSON格式目前在Web Service中推广还属于初级阶段。
C 可读性不太好
16. 动画有哪两类,各有什么特点?
一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转、平移、放缩和渐变)
alpha 渐变
scale 大小
translate 移动
rotate 旋转
二类就是Frame动画,即顺序的播放事先做好的图像,与gif图片原理类似
http://www.cnblogs.com/bastard/archive/2012/06/29/2570405.html
17. Handler、Loop消息队列模型,各部分的作用。
http://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html
18. 怎样退出终止App。
public void exit(){ for (Activity activity : activities) { if (activity!=null) { activity.finish(); } } System.exit(0); }
19. Asset目录与res目录的区别。
1 assets目录下的资源文件不会在R.java自动生成ID 所以读取assets目录下的文件必须指定文件的路径
2 assets目录能获取子目录下的资源
Bitmap bgImg = getImageFromAssetFile( "background.png" ); /** * 从assets中读取图片 */ private Bitmap getImageFromAssetsFile(String fileName) { Bitmap image = null; AssetManager am = getResources().getAssets(); try { InputStream is = am.open(fileName); image = BitmapFactory.decodeStream(is); is.close(); } catch (IOException e) { e.printStackTrace(); } return image; }
20. Android怎么加速启动Activity。
硬件加速
android:hardwareAccelerated="true"
21. Android内存优化方法:ListView优化,及时关闭资源,图片缓存等等。
22. Android中弱引用与软引用的应用场景。
软引用
描述一些还有用但非必须的对象 SoftReference
弱引用
描述非必须对象 强度比软引用更弱
垃圾回收器工作时 无论当前内存是否足够 都会回收掉 WeakReference
23. Bitmap的四中属性,与每种属性队形的大小。
图片压缩质量参数
枚举变量
public static final Bitmap.Config ALPHA_8
public static final Bitmap.Config ARGB_4444
public static final Bitmap.Config ARGB_8888
public static final Bitmap.Config RGB_565
ARGB指的是一种色彩模式,里面A代表Alpha,R表示red,G表示green,B表示blue,
其实所有的可见色都是红绿蓝组成的,所以红绿蓝又称为三原色,每个原色都存储着所表示颜色的信息值
所以就ALPHA_8就是Alpha由8位组成
ARGB_4444就是由4个4位组成即16位,
ARGB_8888就是由4个8位组成即32位,
RGB_565就是R为5位,G为6位,B为5位共16位
由此可见:
ALPHA_8 代表8位Alpha位图
ARGB_4444 代表16位ARGB位图
ARGB_8888 代表32位ARGB位图
RGB_565 代表8位RGB位图
24. View与View Group分类。自定义View过程:onMeasure()、onLayout()、onDraw()。
25. Touch事件分发机制。
http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html
事件分发 dispatchTouchEvent
Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式
(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)
将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,
并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下:
如果 return true,事件会分发给当前 View 并由 dispatchTouchEvent 方法进行消费,同时事件会停止向下传递;
如果 return false,事件分发分为两种情况:
如果当前 View 获取的事件直接来自 Activity,则会将事件返回给 Activity 的 onTouchEvent 进行消费;
如果当前 View 获取的事件来自外层父控件,则会将事件返回给父 View 的 onTouchEvent 进行消费。
如果返回系统默认的 super.dispatchTouchEvent(ev),事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。
事件拦截 onInterceptTouchEvent
在外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,
事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件拦截逻辑如下:
如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理;
如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传递到子 View 上,
再由子 View 的 dispatchTouchEvent 来开始这个事件的分发;
如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默认会被拦截,
并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理。
事件响应 onTouchEvent
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true
或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下:
如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View 向上传递,
并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。
如果返回了 true 则会接收并消费该事件。
如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。
26. Android长连接,怎么处理心跳机制。
27. Zygote的启动过程。
28. Android IPC:Binder原理。
29. 你用过什么框架,是否看过源码,是否知道底层原理。
30. Android5.0、6.0新特性。
Android的话,多是一些项目中的实践,使用多了,自然就知道了,还有就是多逛逛一些名人的博客,书上能讲到的东西不多。另外android底层的东西,有时间的话可以多了解一下,加分项。
推荐书籍:《疯狂android讲义》《深入理解android》