[关闭]
@mSolo 2015-04-22T23:54:02.000000Z 字数 5879 阅读 1505

Android 经验碎片笔记(一)

Android 网络文章


1. Android 最佳实践之 resources

摘录,版权所属:Android最佳实践

  1. <resources>
  2. <!-- grayscale -->
  3. <color name="white" >#FFFFFF</color>
  4. <color name="gray_light">#DBDBDB</color>
  5. <color name="gray" >#939393</color>
  6. <color name="gray_dark" >#5F5F5F</color>
  7. <color name="black" >#323232</color>
  8. <!-- basic colors -->
  9. <color name="green">#27D34D</color>
  10. <color name="blue">#2A91BD</color>
  11. <color name="orange">#FF9D2F</color>
  12. <color name="red">#FF432F</color>
  13. </resources>
  1. <resources>
  2. <!-- font sizes -->
  3. <dimen name="font_larger">22sp</dimen>
  4. <dimen name="font_large">18sp</dimen>
  5. <dimen name="font_normal">15sp</dimen>
  6. <dimen name="font_small">12sp</dimen>
  7. <!-- typical spacing between two views -->
  8. <dimen name="spacing_huge">40dp</dimen>
  9. <dimen name="spacing_large">24dp</dimen>
  10. <dimen name="spacing_normal">14dp</dimen>
  11. <dimen name="spacing_small">10dp</dimen>
  12. <dimen name="spacing_tiny">4dp</dimen>
  13. <!-- typical sizes of views -->
  14. <dimen name="button_height_tall">60dp</dimen>
  15. <dimen name="button_height_normal">40dp</dimen>
  16. <dimen name="button_height_short">32dp</dimen>
  17. </resources>

2. 图片内存泄漏

摘录,版权所属:Android 加载图片时的内存问题

  1. BitmapFactory.Options options = new BitmapFactory.Options();
  2. options.inSampleSize = 3; //图片宽高都为原来的1/3
  1. public void clearMemery(Bitmap bitmap) {
  2. if (bitmap != null && !bitmap.isRecycled()) {
  3. bitmap.recycle();
  4. bitmap = null;
  5. }
  6. }
  1. FileInputStream fis = new FileInputStream(/sdcard/test.png);
  2. Bitmap bitmap = BitmapFactory.decodeStream(fis);
  3. InputStream inputStream=getBitmapInputStreamFromSDCard("test.png");
  4. Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
  5. Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
  6. String SDCarePath=Environment.getExternalStorageDirectory().toString();
  7. String filePath=SDCarePath+"/"+"test.png";
  8. Bitmap bitmap = BitmapFactory.decodeFile(filePath, null);
  9. Bitmap bitmap = BitmapFactory.decodeStream(getClass().getResourceAsStream("/res/drawable/test.png"));

3. Android中保存和恢复Fragment状态的最好方法

摘录,版权所属:Android中保存和恢复Fragment状态的最好方法

情景一:stack中只有一个Fragment的时候旋转屏幕

这种情况非常简单,你只需在onSaveInstanceState存储会在旋转的时候会丢失的数据,包括变量,然后在onActivityCreated或者onViewStateRestored中取出来:

  1. int someVar;
  2. @Override
  3. protected void onSaveInstanceState(Bundle outState) {
  4. outState.putInt("someVar", someVar);
  5. outState.putString(“text”, tv1.getText().toString());
  6. }
  7. @Override
  8. public void onActivityCreated(Bundle savedInstanceState) {
  9. super.onActivityCreated(savedInstanceState);
  10. someVar = savedInstanceState.getInt("someVar", 0);
  11. tv1.setText(savedInstanceState.getString(“text”));
  12. }

看起来很简单是吧,但是存在这样的情况,View重建,但是onSaveInstanceState未被调用,这意味着UI上的所有东西都丢失了,请看下面的情景二。

情景二:Fragment从回退栈的返回

当Fragment从回退栈中返回的时候,onDestroyView和onCreateView被调用,但是onSaveInstanceState貌似没有被调用,这就导致了一切UI数据都回到了xml布局中定义的初始状态。当然,那些内部实现了状态保存的view,比如有android:freezeText属性的EditText和TextView,仍然可以保持其状态,因为Fragment可以为他们保持数据,但是开发者没法获得这些事件,我们只能手动的在onDestroyView中保存这些数据。

  1. @Override
  2. public void onSaveInstanceState(Bundle outState) {
  3. super.onSaveInstanceState(outState);
  4. // 这里保存数据
  5. }
  6. @Override
  7. public void onDestroyView() {
  8. super.onDestroyView();
  9. // 如果onSaveInstanceState没被调用,这里也可以保存数据
  10. }

但是问题来了onSaveInstanceState中保存数据很简单,因为它有Bundle参数,但是onDestroyView没有,那保存在哪里呢?

  1. Bundle savedState;
  2. @Override
  3. public void onActivityCreated(Bundle savedInstanceState) {
  4. super.onActivityCreated(savedInstanceState);
  5. if (!restoreStateFromArguments()) {
  6. // First Time running, Initialize something here
  7. }
  8. }
  9. @Override
  10. public void onSaveInstanceState(Bundle outState) {
  11. super.onSaveInstanceState(outState);
  12. saveStateToArguments(); // Save State Here
  13. }
  14. @Override
  15. public void onDestroyView() {
  16. super.onDestroyView();
  17. saveStateToArguments(); // Save State Here
  18. }
  19. private void saveStateToArguments() {
  20. savedState = saveState();
  21. if (savedState != null) {
  22. Bundle b = getArguments();
  23. b.putBundle(“internalSavedViewState8954201239547”, savedState);
  24. }
  25. }
  26. private boolean restoreStateFromArguments() {
  27. Bundle b = getArguments();
  28. savedState = b.getBundle(“internalSavedViewState8954201239547”);
  29. if (savedState != null) {
  30. restoreState();
  31. return true;
  32. }
  33. return false;
  34. }
  35. // 取出状态数据
  36. private void restoreState() {
  37. if (savedState != null) {
  38. //比如,tv1.setText(savedState.getString(“text”));
  39. }
  40. }
  41. // 保存状态数据
  42. private Bundle saveState() {
  43. Bundle state = new Bundle();
  44. // 比如,state.putString(“text”, tv1.getText().toString());
  45. return state;
  46. }

现在你可以轻松的在fragment的saveState和restoreState中分别存储和取出数据了。现在看起来好多了,几乎快要成功了,但是还有更极端的情况。

情景三:在回退栈中有一个以上的Fragment的时候旋转两次

当你旋转一次屏幕,onSaveInstanceState被调用,UI的状态会如预期的那样被保存,但是当你再一次旋转屏幕,上面的代码就可能会崩溃。原因是虽然onSaveInstanceState被调用了,但是当你旋转屏幕,回退栈中Fragment的view将会销毁,同时在返回之前不会重建。这就导致了当你再一次旋转屏幕,没有可以保存数据的view。saveState()将会引用到一个不存在的view而导致空指针异常NullPointerException,因此需要先检查view是否存在。如果存在保存其状态数据,将Argument中的数据再次保存一遍,或者干脆啥也不做,因为第一次已经保存了。

  1. private void saveStateToArguments() {
  2. if (getView() != null)
  3. savedState = saveState();
  4. if (savedState != null) {
  5. Bundle b = getArguments();
  6. b.putBundle(“savedState”, savedState);
  7. }
  8. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注