J2ME游戏开发(J2ME_Game_Development_with_MIDP2中文版)

这个是本博主在2004年翻译的一篇文章,希望对大家有帮助。


[J2ME游戏开发(第一版)的PDF文档]

  I have a dream! It’s “Play
Games Everywhere…”.

  我有一个梦想,就是”让游戏无处不在”!

时光匆匆滑过了2004年,也带来了很多改变。从MIDP
2.0发布开始到现在已经有两年多了,它的出现让移动设备上的游戏开发更加方便、也更为简单快捷。当我一年前发现MIDP
2.0技术的时候,我同时感觉到我们离随时随地玩游戏的那一天不再遥远。

[J2ME游戏开发(第一版)的PDF文档]

  I have a dream! It’s “Play
Games Everywhere…”.

  我有一个梦想,就是”让游戏无处不在”!

时光匆匆滑过了2004年,也带来了很多改变。从MIDP
2.0发布开始到现在已经有两年多了,它的出现让移动设备上的游戏开发更加方便、也更为简单快捷。当我一年前发现MIDP
2.0技术的时候,我同时感觉到我们离随时随地玩游戏的那一天不再遥远。


一个人都会玩游戏,都喜欢玩游戏;但是并不是每一个人都会开发制作游戏。要让游戏无处不在,还需要更多的人学会开发游戏。相信好学的你在玩过几个好玩的游
戏后总会问:这个游戏是怎么做出来的?我是否也可以做出同样出色的游戏?我该如何学习游戏的制作?…… 
游戏有很多种——这在本书中会讲到——在当今的2004年如果想找一种游戏,它甚至只需要一个人业余很少的时间和精力就可以制作出,而且有可能会非常受欢
迎的游戏,我想非移动游戏莫属!

本书就是J2ME移动游戏(主要是手机游戏)制作的入门读物,只要你具备JAVA编程的基础知识并且了解一些J2ME的背景知识,通过本书的学习,你就能创造出自己的游戏。当然,最最重要的还是读者你的创意!毕竟知识有崖,创意无限!


者本身也是一个业余的游戏制作者,本着自由软件的精神翻译这本书,读者可以在确保完整性的前提下自由的分发本电子书,出版本书请联系译者,出版原英文版请
联系原作者。由于本书原文还没有完成,译者将在原作者写作的同时进行翻译。由于翻译都是在业余时间进行,在工作了一整天后,精力难免难以集中,本书中肯定
会有很多错误,期待读者的批评指正,译者绝对知错就改。JJJJJ

接下来,译者准备制作几个基于MIDP 2.0的手机游戏,并且打算翻译J2ME
API,感兴趣的朋友请跟我联系。此外,也希望同对RUP感兴趣的读者交个朋友。

Escape_MIDP2.0 Demo1

刚刚翻了下2004年的博客,发现了一些有用的古董,放到这里给大家看看吧。

也许对你有用哦,呵呵。

Escape_MIDP2.0 Demo1 ——类似于”是男人就飞10000米”

Author:deaboway
Email: [email protected]
Copy Right by deaboway 2004

版权声明Licence:
————————
此软件为共享软件,任何个人和单位均可免费复制,拷贝,复制时请注明出处。但如需商业用途或者使用,修改其中的全部或者部分代码,图片。请先和作者联系.

概述OverView:
————————
是男人就飞一万米”想必大家都玩过的,这是它的手机clone版本的Demo。当然很多地方还不完善,但是已经可以玩了……本游戏在WTK2.2
Beta 2上运行良好,等游戏进一步完善再考虑是否放出源代码……:)

操作说明Introduction:
————————
单键操作:\n按住”select”或”5″键是向上飞;\n松开是向下飞。很快会出正式版,当然会放在这个blog上面enjoy!!!

版本更新:
Escape_MIDP2.0_v0.1.0 2004-12-16
————————
建立初始Demo版本
————————

下载DownLoad
————————

 escape_midp2.0_v0.1.0.rar

视图View
————————

Demo1″ />
Demo1″ />

Android开发实例详解之IMF(Android SDK Sample—SoftKeyboard)

最近工作比较忙,加班出差,因此更新慢了些。今天刚好有空,写一篇实例详解吧。

本博前面的文章介绍了Android开发环境的搭建和模拟器的常用操作。本次,将以Android
Sample中经典的SoftKeyboard项目为例,详细解析Android上一个小型项目的开发过程和注意事项。

从SDK 1.5版本以后,Android就开放它的IMF(Input Method
Framework),让我们能够开发自己的输入法。而开发输入法最好的参考就是Android自带的Sample-SoftKeyboard,虽然这个例子仅包含英文和数字输入,但是它本身还算完整和清楚,对我们开始Android开发实战有很大帮助。

一、IMF简介

一个IMF结构中包含三个主要的部分:

input method
manager:管理各部分的交互。它是一个客户端API,存在于各个应用程序的context中,用来沟通管理所有进程间交互的全局系统服务。

input
method(IME):实现一个允许用户生成文本的独立交互模块。系统绑定一个当前的输入法。使其创建和生成,决定输入法何时隐藏或者显示它的UI。同一时间只能有一个IME运行。

client application:通过输入法管理器控制输入焦点和IME的状态。一次只能有一个客户端使用IME。

1、InputManager

由UI控件(View,TextView,EditText等)调用,用来操作输入法。比如,打开,关闭,切换输入法等。

它是整个输入法框架(IMF)结构的核心API,处理应用程序和当前输入法的交互。可以通过Context.getSystemService()来获取一个InputMethodManager的实例。

在开发过程中,最基础最重要的就是养成阅读API的习惯。优秀的程序员要养成把自己关在小黑屋里,断绝与外界的联网和联系,仅仅靠自己电脑中的开发环境和API文档,以及漂亮女仆送来的每天三顿饭,写出优秀的程序。这个在武侠小说中叫闭关,在软件开发中叫Clean
Room,哈哈。

Android的API文档在:%SDK_ROOM%/docs/reference/index.html,

InputManager类的位置:%SDK_ROOM%/docs/reference/android/view/inputmethod/InputMethodManager.html

由于,该类跟本次要讲的Sample关系不大,这里就不详细分析,请各位自行阅读API doc吧。

2、InputMethodService

包括输入法内部逻辑,键盘布局,选词等,最终把选出的字符通过commitText提交出来。实现输入法的基础就是名为InputMethodService的类,比如你要实现一个谷歌输入法,就是要extends本类。我们接下来要学习的SoftKeyboard
Sample也是extends本类。InputMethodService类的位置在:%SDK_ROOM%/docs/reference/android/inputmethodservice/InputMethodService.html

InputMethodService是InputMethod的一个完整实现,你可以再在其基础上扩展和定制。它的主要方法如下:

  • onInitializeInterface()
    顾名思义,它在初始化界面的时候被调用,而一般是由于配置文件的更改导致该函数的执行
  • onBinndInput() 它在另外的客户端和该输入法连接时调用
  • onStartInput()
    非常重要的一个回调,它在编辑框中用户已经开始输入的时候调用。比如,当点击一个输入框,我们需要根据这个输入框的信息,设置输入法的一些特性,这个在Sample中很有体会。
  • onCreateInputView() 返回一个层次性的输入视图,而且只是在这个视图第一次显示的时候被调用
  • onCreateCandidatesView()
    同onCreateInputView(),只不过创建的是候选框的视图。
  • onCreateExtractTextView() 比较特殊,是在全屏模式下的一个视图。
  • onStartInputView() 在输入视图被显示并且在一个新的输入框中输入已经开始的时候调用。

基本上输入法的定制,都是围绕在这个类来实现的,它主要提供的是一个基本的用户界面框架(包括输入视图,候选词视图和全屏模式),但是这些都是要实现者自己去定制的。这里的实现是让所有的元素都放置在了一个单一的由InputMethodService来管理的窗口中。它提供了很多的回调API,需要我们自己去实现。一些默认的设置包括:

  • 软键盘输入视图,它通常都是被放置在屏幕的下方。
  • 候选词视图,它通常是放置在输入视图的上面。
  • 当我们输入的时候,需要改变应用程序的界面来适应这些视图的放置规则。比如在Android上面输入,编辑框会自动变形腾出一个软键盘的位置来。

两个非常重要的视图:

1. 软输入视图。是与用户交互的主要发生地:按键,画图或者其他的方式。通常的实现就是简单的用一个视图来处理所有的工作,并且在调用
onCreateInputView()的时候返回一个新的实例。通过调用系统的onEvaluateInputViewShow()来测试是否需要显示输入视图,它是系统根据当前的上下文环境来实现的。当输入法状态改变的时候,需要调用updateInputViewShown()来重新估计一下。

2.
候选词视图。当用户输入一些字符之后,输入法可能需要提供给用户一些可用的候选词的列表。这个视图的管理和输入视图不大一样,因为这个视图是非常的短暂的,它只是在有候选词的时候才会被显示。可以用setCandidatesViewShow()来设置是否需要显示这个视图。正是因为这个显示的频繁性,所以它一般不会被销毁,而且不会改变当前应用程序的视图。

最后,关于文本的产生,这是一个IME的最终目的。它通过InputConnection来链接IME和应用程序的:能够直接产生想要的按键信息,甚至直接在候选和提交的文本中编辑。当用户在不同的输入目标之间切换的时候,IME会不断的调用onFinishInput()
和 onStartInput()。在这两个函数中,需要反复做的就是复位状态,并且应对新的输入框的信息。

以上是一个输入法的最基本的介绍,下面将根据Sample中的SoftKeyboard来说明这些问题。

二、创建Eclipse工程

这里使用最新版本的Android SDK 2.3.3下的SoftKeyboard
Sample来创建工程,其实,从1.5版本,该Sample就已经存在了。同时,由于SoftKeyboard会使人误解为KeyBoard的子类,这里特别改名为InputMethodServiceSample,更符合其功能和特性。

clip_image002

点击Finish,完成项目的创建,可以看到项目工程结构如下:

clip_image004

在Android SDK
2.3.3模拟器上运行本Sample,需要在Setting中选择使用本Sample,需要在Language&keyboard中选中本Sample的名称。

clip_image006clip_image008

当尝试选中Sample Soft
Keyboard时,Android会出现安全提示。IME的确要选择自己信任的,因为它可以收集和记录所有你的输入,这个特性如果被有心人利用会很恐怖。

选中Sample Soft
Keyboard作为我们的输入法之后,进入需要输入法的地方,这里以短信界面作为范例,在输入框中长按,会出现“编辑文本”选单,点击“输入法”即可进入当前输入界面的输入法选择框。就可以使用输入法切换到本输入法看到它的keyboard。

clip_image010clip_image012

之后就可以看到Soft keyboard键盘如下:

clip_image013

三、配置和资源文件解析

除去源代码将在后文统一分析之外,这里介绍下配置和资源文件。

1. AndroidMainifest.xml

每个Android应用都会有的配置描述文件。在这里,Sample把自己声明成了服务,而且绑定在了输入法之上。它的intent-filter是直接用的InputMethod接口,这也是所有的输入法的接口。

2. res目录

放置resource,即资源文件,里面蛮多东西的,具体如下。

(1) drawable目录,放置的是图标文件。

(2) values目录,包含strings.xml以及一些自定义的类型和值的xml文件。

strings.xml

― ime_name 定义了该输入法的名字

― word_separators 词的分隔符,即输入过程中可能用来表示一个词输入完成的符号,比如空格,标点等等)

― label_xx_key
为软键盘定义确认键的标签。在后面代码解析中可以看到,程序会根据输入框的信息来设置EnterKey的图标或者标签。如:在一个网址上面输入,就会显示一个搜索的图标,而在编辑短信时,如果在收信人写,那么EnterKey就是Next标签,用来直接跳到短信正文部分。

dimens.xml,定义软键盘的尺寸信息,包括键高(key_height),候选词字体的高度(candidate_font_height),候选词垂直间隙(candidate_vertical_padding)。

color.xml,定义候选词的背景颜色,比如正常(candidate_normal),推荐(candidate_recommended),背景(candidate_background)和其它(candidate_other)等颜色。

(3)
layout目录,保存布局配置文件。这里只有一个配置文件:input.xml,它定义的是输入视图的信息,包括id(android:id=”@+id/keyboard”),放置在屏幕下方(android:layout_alignParentBottom=”true”),水平最大填充(android:layout_width=”match_parent”),垂直包含子内容(android:layout_height=”wrap_content”)。

(4) xml目录,文件如下:

method.xml,为搜索管理提供配置信息。

qwerty.xml,英文字符的全键盘布局文件。定义很直观,很容易就可以看懂。

symbols_shift.xml和symbols.xml,是标点字符的全键盘布局文件。

四、源代码解析

(一)概述

从InputMethodServiceSample项目可以看出实现一个输入法至少需要CandidateView,
LatinKeyboard, LatinKeyboardView,SoftKeyboard这四个文件:

  • CandidateView负责显示软键盘上面的那个候选区域。
  • LatinKeyboard负责解析并保存键盘布局,并提供选词算法,供程序运行当中使用。其中键盘布局是以XML文件存放在资源当中的。比如我们在汉字输入法下,按下b、a两个字母。LatinKeyboard就负责把这两个字母变成爸、把、巴等显示在CandidateView上。
  • LatinKeyboardView负责显示,就是我们看到的按键。它与CandidateView合起来,组成了InputView,就是我们看到的软键盘。
  • SoftKeyboard继承了InputMethodService,启动一个输入法,其实就是启动一个InputMethodService,当SoftKeyboard输入法被使用时,启动就会启动SoftKeyboard这个Service。

(二)LatinKeyboard.java

软键盘类,直接继承了Keyboard类,并定义一个xml格式的Keyboard的布局,来实现一个输入拉丁文的键盘。这里只是创建一个键盘对象,并不对具体的布局给出手段。

为了更好的理解LatinKeyboard类,这里简单介绍一下Keyboard类。Keyboard可以载入一个用来显示键盘布局的xml来初始化自己,并且可以保存这些键盘的键的属性。他有三个构造函数:

  • Keyboard(Context context, int
    xmlLayoutResId),用语境和xml资源id索引xml文件来创建。
  • Keyboard(Context context, int xmlLayoutResId, int
    modeId),这个和上面差不多,只不过多了一个modeld。
  • Keyboard(Context context, int layoutTemplateResId, CharSequence
    characters, int columns, int
    horizontalPadding),这个比较复杂,用一个空xml布局模板创建一个键盘,然后用指定的characters按照从左往右,从上往下的方式填满这个模板。

本文件源码前面完全继承keyboard,直接用了父类构造函数进行初始化。

这里因为重写了Keyboard类的createKeyFromXml(Resources res, Row parent, int
x, int y, XmlResourceParser
parser),为了要返回一个Key对象,干脆直接创建LatinKey对象好了。从这里我们能看出面向对象和使用框架的要求。

接着,本文件重载了一个createKeyFromXml的函数,这是一个回调函数,它在键盘描绘键的时候调用,从一个xml资源文件中载入一个键,并且放置在(x,y)坐标处。它还判断了该键是否是回车键,并保存起来。在这里,为了要返回一个Key对象,于是直接创建内部类的LatinKey对象。从这里我们能看出面向对象和使用框架的要求。

此外,还有一个函数是:setImeOptions,它是根据编辑框的当前信息,来为这个键盘的回车键设置适当的标签。输入框的不同,会产生不同的回车键的label或者icon。在这个函数中,有一个技巧是用了一些imeOption的位信息,比如IME_MASK_ACTION等等。主要是查看的EditorInfo的Action信息,这里有:

  • IME_ACTION_GO: go操作,将用户带入到一个该输入框的目标的动作。确认键将不会有icon,只有label:
    GO
  • IME_ACTION_NEXT: next操作,将用户带入到该文本框的写一个输入框中。如:
    编辑短消息的时候,内容就是收件人手机号码框的next文字域。它也只是一个NEXT label就行了。
  • IME_ACTION_SEARCH: search操作,默认动作就是搜索。如:
    在URL框中输入的时候,默认的就是search操作,它提供了一个像放大镜一样的icon。
  • IME-ACTION_SEND: send操作,默认动作就是发送当前的内容。如:
    短消息的内容框里面输入的时候,后面通常就是一个发送操作。它也是只提供一个Label:SEND
  • DEFAULT: 默认情况下表示文本框并没有什么特殊的要求,所以只需要设置return的icon即可。

最后,它还定义了一个内部类——LatinKey,它直接继承了Key,来定义一个单独的键,它唯一重载的函数是isInside(int x
, int y
),用来判断一个坐标是否在该键内。它重载为判断该键是否是CANCEL键,如果是则把Y坐标减少10px,按照他的解释是用来还原这个可以关掉键盘的键的目标区域。

(三)LatinKeyboardView.java

这里就是个View,自然也继承自View,因为前面创建的键盘只是一个概念,并不能实例出来一个UI,所以需要借助于一个VIEW类来进行绘制。这个类简单的继承了KeyboardView类,然后重载了一个动作方法,就是onLongPress。

它在有长时间按键事件的时候会调用,首先判断这个按键是否是CANCEL键,如果是的话就通过调用
KeyboardView被安置好的OnKeyboardActionListener对象,给键盘发送一个OPTIONS键被按下的事件。它是用来屏蔽CANCEL键,然后发送了一个未知的代码的键。

(四)CandidateView.java

CandidateView是一个候选字显示view,它提供一个候选字选择的视图,直接继承于View类即可。在我们输入字符时,它应该能根据字符显示一定的提示,比如拼音同音字啊,联想的字啊之类的。

1. 先看它定义了那些重要变量:

  • mService: candidateView的宿主类,即该view是为什么输入法服务的。
  • mSuggestions: 建议。比如说当我们输入一些字母之后输入法希望根据输入来进行联想建议。
  • mSelectedIndex: 用户选择的词的索引。
  • mSelectionHighlight: 描绘选择区域高亮的类。
  • mTypedWordValid: 键入的word是否合法正确。
  • mBgPadding: 背景填充区域。
  • mWordWidth: 每个候选词的宽度。
  • mWordX:每个候选词的X坐标。有了这两个变量,就能够在屏幕上准确的绘制出该候选键。
  • mColor*:定义了各种颜色。
  • mPaint: 一个绘图类,后面会用到
  • mVerticalPadding: 垂直填充区域。
  • mTargetScrollX: 目标滚动的横坐标,即要将目标滚动到何处。
  • mTotalWidth: 总的宽度
  • mGestureDetector: 声明一个手势监测器

GestureDetector对象似乎很少见,让我们了解一下android.view.GestureDetector。这是一个与动作事件相关的类,可以用来检测各种动作事件,这里称之为:手势监测器。它的回调函数是GestureDetector.OnGestureListener,在动作发生时执行,而且只能在触摸时发出,用滚动球无效。要使用这个通常要先建立一个对象,如同代码里体现的,然后设置GestureDetector.OnGestureListener
同时在 onTouchEvent(MotionEvent)中写入动作发生要执行的代码。

2. 构造函数,主要是对一些变量的初始化工作。

首先初始化了mSelectionHighlight,这是一个drawable对象,并利用drawable的setState方法设置这个drawable的初始状态。同时在res目录下加入一个color.xml文件来定义用到的所有颜色资源,然后用R索引,这些资源可以被加入到自己的R.java的内容里,可以直接引用。
剩下的内容就是初始化背景,选中,未选中时的view的背景颜色,这里都是在前面color.xml内定义的了。用这样的方式获得:

Resources r = context.getResources();

获得当前资源对象的方法。

setBackgroundColor(r.getColor(R.color.candidate_background));

然后初始化了一个手势检测器(gesturedetector),它的Listener重载了一个方法,就是onScroll,这个类是手势检测器发现有scroll动作的时候触发。在这个函数里,主要是进行滑动的判断。

这里用到了很多view下的方法:getScrollX();getWidth();scrollTo(sx,
getScrollY());invalidate();我们分别解释如下:

  • getScrollX():获得滚动后view的横坐标
  • scrollTo():滚动到目标坐标
  • getScrollY():获得滚动后view的纵坐标
  • invalidate():使view重画

在这里,distanceX是上次调用onscroll后滚动的X轴距离。假设这个view之前没有被滚动过,第一次滚动且坐标在显示区域内,sx=getScrollX()+distanceX,则view就scrollTo这个位置。如果sx超过了最大显示宽度,则scrollTo就滚想原先sx处,也就是不动。也就是说:系统滚动产生一个惯性的感觉,当你把view实际到了X坐标点,系统再给你加一个distanceX,这个distanceX不是两个动作之间的距离,应该是上一个滚动动作的停止点和本次滚动动作的停止点之间的距离,这个距离系统自己算,我们不用管,只要到了最大边界,view就不再滚动,或者说是原地滚动。

接下来:

  • setHorizontalFadingEdgeEnabled(true);//
    设置view在水平滚动时,水平边是否淡出。
  • setWillNotDraw(false);// view不自己绘制自己
  • setHorizontalScrollBarEnabled(false);// 不设置水平滚动条
  • setVerticalScrollBarEnabled(false);// 不设置垂直滚动条

3. setService是设置宿主输入法。

4.
computeHorizontalScrollRange
,表示这个view的水平滚动区域,返回的是候选视图的总体宽度。

5.
onMeasure
,重载自view类,在布局阶段被父视图所调用。比如当父视图需要根据其子视图的大小来进行布局时,就需要回调这个函数来看该view的大小。当调用这个函数时必须在内部调用setMeasureDimension来对宽和高进行保存,否则将会有异常出现。这里重载它是为了系统检测要绘制的字符区的大小,因为字体可能有大小,应根据字体来。它首先计算自己的期望的宽度,调用resolveSize来看是否能够得到50px的宽度;然后是计算想要的高度,根据字体和显示提示区的padding来确定。

6.
onDraw
,view的主要函数,每个view都必须重写这个函数来绘制自己。它提供了一块画布,如果为空,则直接调用父类来画。

在这里的内部逻辑大概如下:

判断是否有候选词,没有的话就不用绘制。

初始化背景的填充区域,直接view的背景中得到即可。

对于每一个候选词,得到其文本,然后计算其宽度,然后再加上两边的空隙。

判断是否选择了当前词:触摸的位置+滚动了的位置。如果是在当前词的左边到右边之间,则将高亮区域绘制在画布上面,高亮区域设置的大小即为当前词的大小,并且保存被选词的索引。

将文本绘制在这个候选词的画布上面,它进行了一个判断,判断哪个才是推荐词。默认情况下是候选词的第一个词,但是它判断第一个词是否是合法的,如果是,则第一个词是候选词,否者第二个词才是候选粗,然后进行绘制。

绘制一条线,来分割各个候选词。上面提到的总共的宽度在所有的词都绘制出来之后,就能够得到了。

判断目标滚动是否是当前的,不是就需要滚动过去。

7.
scrollToTarget
,滚到到目标区域。得到当前值,然后加上一个滚动距离,看是否超过并进行相应调整,之后滚动到相应坐标。

8. setSuggestions,设置候选词,之后进行绘制。

9.
onTouchEvent
,触摸事件产生时调用。首先判断是否为gesturedetector监听的动作,如果不是就进行下面处理。初始化动作,把发生的动作记录下来,点触的坐标也记录下来。然后,根据动作类型分类反应:

  • 向下:没动作;
  • 移动:如果是向左移动就要手动的选择候选词;
  • 向上:需要手动选择候选词。

10.
takeSuggestionAt
,选择在坐标x处的词,这个处理的是用户轻轻点击键盘,也就是选择候选词。

11. removeHighlight,去除高亮显示。

(五)SoftKeyboard.java

整个输入法的总体的框架,包括什么时候创建,什么时候显示输入法,和怎样和文本框进行通讯等等。上面的文件,都是为了这个类服务的。总体来说,一个输入法需要的是一个输入视图,一个候选词视图,还有一个就是和应用程序的链接。

基本时序图如下:

clip_image015

输入法在Android中的本质就是一个Service,假设用户刚刚启动Android,用户移动焦点首次进入文本编辑框时,Android便会通知Service开始进行初始化工作。于是便有了如图中的一系列动作。

追根溯源,onCreate方法继承至Service类,其意义和其他Service的是一样的。Sample在这里,做了一些非UI方面的初始化,即字符串变量词汇分隔符的初始化。

接下来执行onInitializeInterface,这里是进行UI初始化的地方,创建以后和配置修改以后,都会调用这个方法。Sample在这里对Keyboard进行了初始化,从XML文件中读取软键盘信息,封装进Keyboard对象。

第三个执行的就是onStartInput方法,在这里,我们被绑定到了客户端,接收所有关于编辑对象的详细信息。

第四个执行的方法是onCreateInputView,在用户输入的区域要显示时,这个方法由框架调用,输入法首次显示时,或者配置信息改变时,该方法就会被执行。在该方法中,对inputview进行初始化:读取布局文件信息,设置onKeyboardActionListener,并初始设置
keyboard。

第五个方法是onCreateCandidatesView,在要显示候选词汇的视图时,由框架调用。和onCreateInputView类似。在这个方式中,对candidateview
进行初始化。

第六个方法,也是最后一个方法,即onStartInputView,正是在这个方法中,将inputview和当前keyboard重新关联起来。

在上面的六个方法中,onCreateInputView和onCreateCandidatesView两个方法只有在初始化时才会执行一次,除非有配置信息发生改变。那么究竟什么是配置信息发生改变呢?在看InputMethodService的API文档时,可以看到有一个方法onConfigurationChanged,根据文档解释,这个方法主要负责配置更改的情况。在示例中,其没有override这个方法,但是在android源码包中的PinyinIME中,有使用这个方法,有兴趣的朋友可以在看完SoftKeyboard
Sample之后,看看PinyinIME的源码。

关于本类中其它的一些方法,由于比较直观,就不进行讲解了,感兴趣的朋友可以参考《android
sdk中 softkeyboard的自己解析(4)
》。

五、输入法调试

通过使用调试模式加断点的方式,有助于我们更好的理解输入法的时序和每个类及其方法的功能和调用持续。

这里使用Eclipse的DDMS透视图进行调试,具体介绍参考《用Eclipse开发和调试Android应用程序

首先切换到DDMS模式,在这个模式下面,DDMS将链接到正在运行的手机或模拟器,并且能够提取手机上面的各种信息,比如线程,还有各个正在后台运行的服务等等。点击工具条上的“Debug
selected Process”,就能够将调试器植入到这个服务上面。

clip_image017

之后切换到debug模式,就会发现调试器已经链接到了这个模拟器,然后就可以像调试普通的程序一样调试这个输入法了。

clip_image019

通过debug模式,我们可以发现,输入法首先执行的onCreateInputView->
onCreateCandidatesView,而在这个时候,这个输入法的界面一点儿都还没有显现出来。当我们在一个输入框中点击鼠标时,系统会产生一个事件,最开始就被输入法捕获,然后再将控制权交给这个输入法。另外,切换对象的时候,输入法总是认为是一次输入的结束,然后进行一系列的reset工作。所有的键盘等事件,都会首先传递给输入法,所以,如果一个按键事件不是我们所能够处理的问题,我们需要将这个事件继续传递下去,而不要丢弃了,因为这可能是别的控件的事情。

在发送消息的界面,在输入完TO某人之后,点击content输入框,首先调用的是onFinishInput,也就是结束上一次的输入,准备这次的输入。之后调用的是onStartInputView,让界面显示出来。接着调用onStartInput,表示开始正式的输入。在这过程中,要完成根据不同的输入框,选择不同的键盘,当你输入一个键,首先触发的是onKey回调,在这里要判断是输入的普通字符,还是控制性的字符,比如删除,返回等等。比如这里输入一个
‘g’,然后会调用处理普通字符的函数handleCharacter。这里的策略就是,输入一个普通字符,就将Composing增加,并且更新这个候选词的列表。这里有一个很微妙的开关,就是mPrediction,它就是判断是否是需要保存这个Composing。在比如说URL框中输入的时候,就会置这个开关为关,直接将键入的输入到文本框中去。

为了测试所有的函数,你必须想出一种输入方式,让每个函数你都能执行到,那你就能够看清楚输入法的本来面目。

请各位朋友自己试试,对阅读和理解源代码的流程、时序和生命周期很有好处。也可以方便的找到自己的代码的bug。

六、输入法的调用

希望从一个View上调用输入法和接收输入法传过来的字符串,可以通过调用EditText这个widget。但是,如果要做出很炫很个性的输入法,就必须自己去和EditText一样连接输入法,介绍如下:

首先,定义一个继承自BaseInputConnection的类。前文提到过,输入法是通过commitText来提交选中字符。

public class MyBaseInputConnection extends
BaseInputConnection{

public MyBaseInputConnection(View targetView, boolean
fullEditor) {

super(targetView, fullEditor);

}

public static String tx=””;

//输入法程序就是通过调用这个方法把最终结果输出来的

@Override

public boolean commitText(CharSequence text, int
newCursorPosition) {

tx = text.toString();

return true;

}

}

BaseInputConnection相当于一个InputMethodService和View之间的一个通道。每当InputMethodService产生一个结果时,都会调用BaseInputConnection的commitText方法,把结果传递出来。

之后,采用如下方式,呼出输入法,并且把自定义的BaseInputConnection通道传递给InputMethodService。

public class MyView extends XXView …{

//得到InputMethodManager

InputMethodManager input = (InputMethodManager)
context.getSystemService(Context.INPUT_METHOD_SERVICE);

//定义事件处理器

ResultReceiver receiver = new ResultReceiver(new Handler() {

public void handleMessage(Message msg) {

}

});

//在你想呼出输入法的时候,调用这一句

input.showSoftInput(this, 0, mRR);

@Override

//这个方法继承自View。把自定义的BaseInputConnection通道传递给InputMethodService

public InputConnection onCreateInputConnection(EditorInfo
outAttrs) {

return new MyBaseInputConnection(this, false);

}

}

低级界面上面,自己调用输入法并接收输入法的输出结果,就是这样的。

更多相关文章,请访问:

http://blog.sina.com.cn/deaboway

http://blog.csdn.net/deaboway

以上两个blog同步更新。

JAVA-JDK里的设计模式

Structural(结构模式)

Adapter:
把一个接口或是类变成另外一种。
    
java.util.Arrays#asList()
    
javax.swing.JTable(TableModel)
    
java.io.InputStreamReader(InputStream)
    
java.io.OutputStreamWriter(OutputStream)
    
javax.xml.bind.annotation.adapters.XmlAdapter#marshal()
    
javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal()
Bridge:
把抽象和实现解藕,于是接口和实现可在完全独立开来。

    • AWT
(提供了抽象层映射于实际的操作系统)
    • JDBC
Composite:
让使用者把单独的对象和组合对象混用。

    
javax.swing.JComponent#add(Component)
    
java.awt.Container#add(Component)
    
java.util.Map#putAll(Map)
    
java.util.List#addAll(Collection)
    
java.util.Set#addAll(Collection)

Decorator:
为一个对象动态的加上一系列的动作,而不需要因为这些动作的不同而产生大量的继承类。这个模式在JDK中几乎无处不在,所以,下面的列表只是一些典型的。

    
java.io.BufferedInputStream(InputStream)
    
java.io.DataInputStream(InputStream)
    
java.io.BufferedOutputStream(OutputStream)
    
java.util.zip.ZipOutputStream(OutputStream)
    
java.util.Collections#checked[List|Map|Set|SortedSet|SortedMap]()
Facade:
用一个简单的接口包状一组组件,接口,抽象或是子系统。

    
java.lang.Class
    
javax.faces.webapp.FacesServlet
Flyweight:
有效率地存储大量的小的对象。

    
java.lang.Integer#valueOf(int)
    
java.lang.Boolean#valueOf(boolean)
    
java.lang.Byte#valueOf(byte)
    
java.lang.Character#valueOf(char)
Proxy:
用一个简单的对象来代替一个复杂的对象。

    
java.lang.reflect.Proxy
    
RMI

Creational(创建模式)

Abstract factory:
创建一组有关联的对象实例。这个模式在JDK中也是相当的常见,还有很多的framework例如Spring。我们很容易找到这样的实例。

    
java.util.Calendar#getInstance()
    
java.util.Arrays#asList()
    
java.util.ResourceBundle#getBundle()
    
java.sql.DriverManager#getConnection()
    
java.sql.Connection#createStatement()
    
java.sql.Statement#executeQuery()
    
java.text.NumberFormat#getInstance()
    
javax.xml.transform.TransformerFactory#newInstance()
Builder:
主要用来简化一个复杂的对象的创建。这个模式也可以用来实现一个 Fluent Interface。

    
java.lang.StringBuilder#append()
    
java.lang.StringBuffer#append()
    
java.sql.PreparedStatement
    
javax.swing.GroupLayout.Group#addComponent()
Factory:
简单来说,按照需求返回一个类型的实例。

    
java.lang.Proxy#newProxyInstance()
    
java.lang.Object#toString()
    
java.lang.Class#newInstance()
    
java.lang.reflect.Array#newInstance()
    
java.lang.reflect.Constructor#newInstance()
    
java.lang.Boolean#valueOf(String)
    
java.lang.Class#forName()
Prototype:
使用自己的实例创建另一个实例。有时候,创建一个实例然后再把已有实例的值拷贝过去,是一个很复杂的动作。所以,使用这个模式可以避免这样的复杂性。

    
java.lang.Object#clone()
    
java.lang.Cloneable
Singleton:
只允许一个实例。在 Effective Java中建议使用Emun.

    
java.lang.Runtime#getRuntime()
    
java.awt.Toolkit#getDefaultToolkit()
    
java.awt.GraphicsEnvironment#getLocalGraphicsEnvironment()
    
java.awt.Desktop#getDesktop()

Behavioral(行为模式)

Chain of responsibility:
把一个对象在一个链接传递直到被处理。在这个链上的所有的对象有相同的接口(抽象类)但却有不同的实现。

    
java.util.logging.Logger#log()
    
javax.servlet.Filter#doFilter()
Command:
把一个或一些命令封装到一个对象中。

    
java.lang.Runnable
    
javax.swing.Action
Interpreter:
一个语法解释器的模式。

    
java.util.Pattern
    
java.text.Normalizer
    
java.text.Format
Iterator:
提供一种一致的方法来顺序遍历一个容器中的所有元素。

    
java.util.Iterator
    
java.util.Enumeration
Mediator:
用来减少对象单的直接通讯的依赖关系。使用一个中间类来管理消息的方向。

    
java.util.Timer
    
java.util.concurrent.Executor#execute()
    
java.util.concurrent.ExecutorService#submit()
    
java.lang.reflect.Method#invoke()
Memento:
给一个对象的状态做一个快照。Date类在内部使用了一个long型来做这个快照。

    
java.util.Date
    
java.io.Serializable
Null Object:
这个模式用来解决如果一个Collection中没有元素的情况。

    
java.util.Collections#emptyList()
    
java.util.Collections#emptyMap()
    
java.util.Collections#emptySet()
Observer:
允许一个对象向所有的侦听的对象广播自己的消息或事件。

    
java.util.EventListener
    
javax.servlet.http.HttpSessionBindingListener
    
javax.servlet.http.HttpSessionAttributeListener
    
javax.faces.event.PhaseListener
State:
这个模式允许你可以在运行时很容易地根据自身内部的状态改变对象的行为。

    
java.util.Iterator
    
javax.faces.lifecycle.LifeCycle#execute()
Strategy:
定义一组算法,并把其封装到一个对象中。然后在运行时,可以灵活的使用其中的一个算法。

    
java.util.Comparator#compare()
    
javax.servlet.http.HttpServlet
    
javax.servlet.Filter#doFilter()
Template method:
允许子类重载部分父类而不需要完全重写。

    
java.util.Collections#sort()
    
java.io.InputStream#skip()
    
java.io.InputStream#read()
    
java.util.AbstractList#indexOf()
Visitor:

作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作.

    
javax.lang.model.element.Element
和javax.lang.model.element.ElementVisitor
    
javax.lang.model.type.TypeMirror
和javax.lang.model.type.TypeVisitor
(全文完)

转自:http://coolshell.cn/articles/3320.html
参考:http://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns

在eclipse上用lwuit的过程

下面是国外一个人发的在eclipse上用lwuit的过程。(是有很多注意的地方,感觉这个东西还是用sun的netbean方便)

Hello all

if you are an Eclipse developer like me, than you are probably
missing the possibility to build LWUIT with Eclipse. This small
How-To describes what I did to get this done:

What you need
a. Love to work with Eclipse 🙂
b. A subversion client (I use TortoiseSVN) and some subversion
know-how
c. A good internet connection

Setup Eclipse and create a new Midlet project
1. Install the Eclipse MJT plugin (http://www.eclipse.org/dsdp/mtj/) and set it up
correctly (http://www.eclipse.org/dsdp/mtj/ …
/gettingstarted.php
)
2. Create a new “Midlet Project”
3. Open the “Application Descriptor” file and change the
“Microedition Profile” from version 2.1 to 2.0

Checkout LWUIT
4. Open a file explorer and navigate to the new project in your
Eclipse workspace (You can see where this is in the project
properties (Alt-Enter) on the “Resource”-tab)
5. Checkout the LWUIT directory with the URL
“https://lwuit.dev.java.net/svn/lwuit/trunk/MIDP/LWUIT”
(guest/guest) directly into your project directory with your svn
client

Fix compilation errors
6. Go back to Eclipse and refresh (F5) your project: now there
“src” folder should show some “com.sun.lwuit” folders and also
(unfortunately) some compiling errors
7. To fix the compiling errors (maybe if someone of the developer
team reads this, he can fix this directly in the repository), open
the erroneous classes and put a “this.” in front of every
expression marked as error (“setLayout…” ->
“this.setLayout…”)

Download necessary build files
8. Now comes the circumstantially part. You have to download
Netbeans! Yes, I’m afraid so. All you need is a JAR file with about
200K, that’s inside the Netbeans distribution. But I don’t want to
post it here, because I am not sure if this offend against any SUN
licenses.
9. After you downloaded and installed Netbeans, create a “lib”
directory inside your project. Then copy the
“org-netbeans-modules-mobility-antext.jar” from the
“NETBEANS_INSTALLATION\mobility8\modules” directory into your new
“lib” directory.

Fix the build for Eclipse
10. Open “nbproject/build-impl.xml” and delete “${netbeans.user}/”
in line 7. The line should now appear as:
<property name=”user.properties.file”
location=”build.properties”/>
(I know, that this file should not be edited (see line 2), maybe
someone has a better idea here)
10. Create a new “build.properties” file right under the project
(next to “build.xml”) with your settings for the build. You need at
least this three entries here:
* “project.LWUIT” = the path to the LWUIT project (in our case this
is “.”)
* “libs.j2me_ant_ext.classpath” = the path to the netbeans lib (in
our case this is now
“lib/org-netbeans-modules-mobility-antext.jar”)
* “platform.home” = the path to your WTK (this depends on your WTK
installation)

My “build.properties” looks like this:

project.LWUIT=.
libs.j2me_ant_ext.classpath=lib/org-netbeans-modules-mobility-antext.jar

platform.home=C:\\WTK2.5.2

These are the minimum entries for the “build.properties” file. If
someone finds more useful settings, please post it here.

Run the build
Now everything should be ready to run the build. Right-Click on
“build.xml” and say “Run as/Ant Build”. The build should finish
successfully and you should find the resulting “LWUIT.jar” in the
“dist” directory of the project.

I hope I can make some Eclipse developers happy with this How-To.
Any comments are welcome.