返回列表 发帖

[转录]记得要在程式中,处理键盘开启或关闭的动作

from http://ysl-paradise.blogspot.com/2008/12/blog-post.html

Handle the open/close keyboard usage for your Android applications

之前写了一个 Android 版的世界时钟 (world clock) 程式,自认为应该没什麽大问题了,就丢上网让使用者开始下载。嗯,下载数是不少,心喜之余,还是有几个人反应,无法完成注册的问题。

由於,当时 G1 手机没有到手,只能用模拟机测,测了半天,一直无法重现使用者提到的问题。只好再检视注册相关的程式码,一样,看了不下十遍,还是没看到什麽问题。终於,有天想到使用者要注册时,应该要输入使用者名称及注册码,而实机不像我们在模拟机上,直接用 PC 的键盘输入,他应该要打开键盘输入才行。会不会,是这个问题的关系?

首先,第一个是做的是,要如何在模拟机上,模拟打开键盘这个动作?告诉你,你在网路上一定找不到这样的资讯。今天就分享给你,这可是我尝试了许久,才发现的秘诀。

告诉你,答案就是按下 PC 键盘上的 KEYPAD_7 or KEYPAD_9 键。疑,这不就是 如何以程式的方式,旋转 Android 萤幕 文章中,提到的旋转模拟机萤幕方向 (直立  水平) 的按键吗?的确是,所有的文件都只说明,这是用来旋转萤幕的按键,根本没人提到,这也是模拟键盘打开或关闭的按键。

还来我才知道,在实机上,系统并不会自动随着机器的旋转,而自动旋转萤幕方向。只有当你打开键盘时,系统才会自动将萤幕转成水平。当你收起键盘时,才又将萤幕转成垂直方向。

那这开启或关闭键盘 (正确地,应该说旋转萤幕方向) 的动作,为什麽会造成程式的问题呢?

原来,这萤幕的旋转,是靠重新起动你的 activity (不是整个应用程式喔) 而达成的。虾米,这是什麽意思?我发现,当萤幕准备要开始旋转时,系统会先杀掉你现在的 activity,接着呼叫底层的显示系统,旋转萤幕的方向,最後才又重新启动你的 activity。从使用者看来,只是萤幕转个方向而已,什麽事也没发生。但从程式面来看,这可是已经经历过一次生死轮回了。

我写个简单的程式,证明给你看。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

public class activity_lift_cycle extends Activity {  
  public void   
  onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.main);  
      
    Log.d("", "onCreate("   savedInstanceState   ")");  
  }  
  
  protected void   
  onRestart() {  
    super.onRestart();  
    Log.d("", "onRestart()");  
  }  
  
  protected void   
  onStart() {  
    super.onStart();  
    Log.d("", "onStart()");  
  }  
  
  protected void   
  onRestoreInstanceState(Bundle savedInstanceState) {  
    super.onRestoreInstanceState(savedInstanceState);  
    Log.d("", "onRestoreInstanceState()");  
  }  
  
  protected void   
  onPostCreate(Bundle savedInstanceState) {  
    super.onPostCreate(savedInstanceState);  
    Log.d("", "onPostCreate()");  
  }  
  
  protected void   
  onResume() {  
    super.onResume();  
    Log.d("", "onResume()");  
  }  
  
  protected void   
  onPostResume() {  
    super.onPostResume();  
    Log.d("", "onPostResume()");  
  }  
  
  protected void   
  onSaveInstanceState(Bundle outState) {  
    outState.putInt("key", 123);  
    super.onSaveInstanceState(outState);  
    Log.d("", "onSaveInstanceState()");  
  }  
  
  protected void   
  onPause() {  
    super.onPause();  
    Log.d("", "onPause()");  
  }  
  
  protected void   
  onStop() {  
    super.onStop();  
    Log.d("", "onStop()");  
  }  
  
  protected void   
  onDestroy() {  
    super.onDestroy();  
    Log.d("", "onDestroy()");  
  }  
  
  protected void   
  onNewIntent(Intent intent) {  
    super.onNewIntent(intent);  
    Log.d("", "onNewIntent()");  
  }  
}  

首先,当你执行这个程式後,你会看到底下这样的结果。

onCreate(null)
onStart()
onPostCreate()
onResume()
onPostResume()

可是当你按下 KEYPAD_7 ,将萤幕转成水平的方向,你会看到底下这样的结果。

onSaveInstanceState()
onPause()
onStop()
onDestroy()
onCreate(Bundle[{android:viewHierarchyState=
  Bundle[{android:views=
  android.util.SparseArray@43370a48}], key=123}])
onStart()
onRestoreInstanceState()
onPostCreate()
onResume()
onPostResume()

看到了吗? onDestroy() 证明系统杀了你的 activity, onCreate() 则是又重新启动你的 activity。

我原先无法让使用者无法完成注册的问题,就是有些 local variables 的值,因为这重起 activity 的动作,而不见了。

这个经验,让我学到了,千万要有程式随时会被系统杀掉的准备。

有经验的你,可能会发现为什麽 activity 上 EditText 内的文字,不会随着旋转萤幕的动作,而重设。翻翻 EditText 的原始码,你会发现其实 EditText 也有特别针对这样的行为来处理。所以说,如果你有写自己的 custom widget 时,别忘了也要做类似的处理。不过, widget 的处理动作,和 activity 完全不同。有机会的话,再谈这部份。

後记,在写这篇时,又去 Google 了 一下,看到 Rotational Forces…On Your Android App 中,也有详细提到关於旋转萤幕的问题处理。值得参考。
       


最近要固定萤幕
发现如果只有设定
android:screenOrientation="portrait"
虽然会固定,但是仍会呼叫onDestroy,onCreate...这样

得加上
android:configChanges="orientation|keyboardHidden"
才不会重新来..0rz..

koji

TOP

返回列表