在之前也谢了几篇关于CXF进行服务的发布的文章,基于Spring以及基于jetty
本文同样实现基于Jetty内置服务器进行服务的发布,主要解决的问题就是发布出来的WSDL中方法参数名称不一致的问题
接口文件:
package demo.hw.server; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; @WebService public interface HelloWorld { @WebMethod @WebResult(name="callBack") String sayHi(@WebParam(name="username")String username); }
实现类:
package demo.hw.server; public class HelloWorldImpl implements HelloWorld { public String sayHi(String text) { System.out.println("sayHi called"); return "Hello " + text; } }
发布:(1)
package demo.hw.server; import javax.xml.ws.Endpoint; public class Server { public static void main(String args[]) throws Exception { Endpoint endpoint = Endpoint.publish( "http://localhost:8080/WSCXF/helloService", new HelloWorldImpl());// 这里是实现类 System.out.println("WS发布成功!"); } }
发布(2)
HelloWorldImpl helloworldimp = new HelloWorldImpl(); JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean(); factoryBean.setAddress("http://localhost:8080/WSCXF/helloService"); factoryBean.setServiceClass(HelloWorld.class);//接口类 factoryBean.setServiceBean(helloworldimp); factoryBean.create();
实现结果:
http://localhost:8080/WSCXF/helloService?wsdl
总结: 在之前探究了一段时间,实现了Spring无注解的发布服务,并实现了拦截器等功能,但是现在项目需求能够对服务进行控制,能够控制启动和停止,于是个人认为利用内置 Jetty服务器则可以实现对服务的控制,这样的话就需要进行注解编程,个人在探索中学习,如果童靴你又好的方法,希望能够分享一下。
又到10点半,时间真是过的真快。在项目中,遇到不能ListView及时更新的问题。写了一个demo,其中也遇到一些问题,一并写出来。前几个月总是有点懒,但是这个月总算是凑够4篇了。
代码比较简单,遇到点简单的问题,弄到了现在。
好吧,上代码:
public class PersonAdapter extends BaseAdapter { private ArrayList<PersonBean> mList; private Context mContext; public PersonAdapter(ArrayList<PersonBean> list, Context context) { mList = list; mContext = context; } public void refresh(ArrayList<PersonBean> list) { mList = list; notifyDataSetChanged(); } @Override public int getCount() { return mList.size(); } @Override public Object getItem(int position) { return mList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { Holder holder = null; if (convertView == null) { LayoutInflater inflater = LayoutInflater.from(mContext); convertView = inflater.inflate(R.layout.list_item, null); holder = new Holder(); holder.mNameText = (TextView)convertView.findViewById(R.id.name_text); holder.mIDText = (TextView)convertView.findViewById(R.id.id_text); convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); } holder.mNameText.setText(mList.get(getCount() - position - 1).getName()); holder.mIDText.setText(mList.get(getCount() - position - 1).getID()); return convertView; } class Holder { private TextView mNameText, mIDText; } }
PersonAdapter继承自BaseAdapter,里面的代码都应该比较熟悉。里面注意这点代码:
public void refresh(ArrayList<PersonBean> list) { mList = list; notifyDataSetChanged(); }
在初始化PersonAdapter的时候,需要外部导入一个mList。
public PersonAdapter(ArrayList<PersonBean> list, Context context) { mList = list; mContext = context; }
在使用这种类型时,在Activity使用mAdapter.notifyDataSetChanged()时候,有时候会发现数据不能够及时的更新。这个时候,就比较需要调用refresh()这个方法了。
下面看一下主Activity:
public class ListViewRefreshActivity extends Activity { private ListView mListView; private ArrayList<PersonBean> mList; private PersonAdapter mAdapter; private Handler mHandler; private String mName, mID; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mListView = (ListView)findViewById(R.id.listView); mList = new ArrayList<PersonBean>(); mAdapter = new PersonAdapter(mList, ListViewRefreshActivity.this); mListView.setAdapter(mAdapter); mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); mList.add((PersonBean) msg.obj); Log.v("@@@@@@", "this is get message"); mAdapter.refresh(mList); // mAdapter.notifyDataSetChanged(); } }; // final Message message = new Message(); new Thread(new Runnable() { @Override public void run() { try { for (int i = 0; i < 10; i++) { mName = "hao :" + i; mID = "" + i; PersonBean bean = new PersonBean(); bean.setID(mID); bean.setName(mName); Message message = new Message(); message.obj = bean; Thread.sleep(3000); mHandler.sendMessage(message); // mHandler.sendMessageDelayed(message, 10000); }}catch (Exception e) { e.printStackTrace(); } } }).start(); } }先说一个小bug吧,看一下在new Thread上面有一句注释掉的
final Message message = new Message();
如果用这个message,注释run方法体内的message,运行程序,在我机子上,发送第四个消息时,就会报android.util.AndroidRuntimeException:This message is already in use这个错,message已经被使用。所以,每一次发送,都要重新创建一个新的message。也可以使用一下语句:
message = mHandler.obtainMessage();里面主要看一下handler中重写handlerMessage这个方法:
@Override public void handleMessage(Message msg) { super.handleMessage(msg); mList.add((PersonBean) msg.obj); Log.v("@@@@@@", "this is get message"); mAdapter.refresh(mList); // mAdapter.notifyDataSetChanged(); }
当然,在这个小例子中,使用mAdapter.refresh这个方法更麻烦点,直接调用notifyDataSetChange就可以达到效果,如果你的代码里面不能达到效果,就可以使用mAdapter.refresh试一下。
notifyDataSetChanged这个方法的设计是典型观察者模式。看一下源代码:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { private final DataSetObservable mDataSetObservable = new DataSetObservable(); public boolean hasStableIds() { return false; } public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } /** * Notifies the attached observers that the underlying data has been changed * and any View reflecting the data set should refresh itself. */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } /** * Notifies the attached observers that the underlying data is no longer valid * or available. Once invoked this adapter is no longer valid and should * not report further data set changes. */ public void notifyDataSetInvalidated() { mDataSetObservable.notifyInvalidated(); }
有一个数据被观察者:mDataSetObservable。当被观察者数据发生改变时,通知观察者。我们使用registerDataSetObserver这个方法注册观察者。都是调用notifyDataSetChanged方法。就是告诉观察者,数据有所改变。在这个方法中,又调用了DataSetObserveable的notifyChanged方法:
/** * Invokes onChanged on each observer. Called when the data set being observed has * changed, and which when read contains the new state of the data. */ public void notifyChanged() { synchronized(mObservers) { // since onChanged() is implemented by the app, it could do anything, including // removing itself from {@link mObservers} - and that could cause problems if // an iterator is used on the ArrayList {@link mObservers}. // to avoid such problems, just march thru the list in the reverse order. for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } }
看一下他的方法说明:当数据被观察到已经改变,调用每一个观察者的onChanged方法去读取数据的最新状态。
mObservers的定义如下:
protected final ArrayList<T> mObservers = new ArrayList<T>();
通过遍历一个ArrayList来通知各个观察者。
前面说到了,我们可以调用registerDataSetObserver注册为观察者,但是是在哪注册的呢?因为如果没有注册,adapter就不应该发生变化。所以,我们看下ListView的SetAdapter这个方法:
@Override public void setAdapter(ListAdapter adapter) { if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } resetList(); mRecycler.clear(); if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; // AbsListView#setAdapter will update choice mode states. super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); checkFocus(); mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver); mRecycler.setViewTypeCount(mAdapter.getViewTypeCount()); int position; if (mStackFromBottom) { position = lookForSelectablePosition(mItemCount - 1, false); } else { position = lookForSelectablePosition(0, true); } setSelectedPositionInt(position); setNextSelectedPositionInt(position); if (mItemCount == 0) { // Nothing selected checkSelectionChanged(); } } else { mAreAllItemsSelectable = true; checkFocus(); // Nothing selected checkSelectionChanged(); } requestLayout(); }如果mAdapter和mDataSetObserver都不为空的话,取消mAdapter对mDataSetObserver的注册。
if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); }然后,把传入的adapter这个参数,赋值给mAdapter:
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; }
赋值成功后:
if (mAdapter != null) { mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver);
重新为mDataSetObserver赋值,然后把mAdapter注册为mDataSetObserver的观察者。
至此,思路应该清晰了:在listview的setAdapter中把adapter注册为mDataSetObserver的观察者。当数据变化时,就可以调用notifyDataSetChanged方法来提示观察者数据已经变化。
关于观察者的详细情况:浅学设计模式之观察者<Observer>模式及在android中的应用
最后就是说一下,里面PersonBean类,就是一个实体类,很简单,不在详述。
最后,源代码:http://download.csdn.net/detail/aomandeshangxiao/4704585
1.回顾
在上一节已经成功的导入AndEngine源代码项目,我们就利用它来实现我们的工程.lib文件在bin目录下:
2.建立工程
在eclipse下file->new->project...->Android Application Project
点击next
设置工程明等参数,例如:MoveBall,为了兼容工程版本,将SDk版本修改为2.1,如图所示:
接着下一步,可以随便选择你要的图标
然后next ....finish就完成了初始工程的创建
3.修改原始工程
鼠标放在MoveBall项目上,右键选择Build Path->Configure build path
然后选择Projects,点击右边的Add.选择上AndEngine
点击OK就可以将AndEngine项目添加到工程了
打开MoveBall,java,将MoveBall extends Activity修改为MoveBall extends BaseGameActivity.
接着写代码:
package season.lxx.moveball; import org.andengine.engine.camera.Camera; import org.andengine.engine.options.EngineOptions; import org.andengine.engine.options.ScreenOrientation; import org.andengine.engine.options.resolutionpolicy.IResolutionPolicy; import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy; import org.andengine.entity.scene.Scene; import org.andengine.entity.scene.background.RepeatingSpriteBackground; import org.andengine.entity.sprite.AnimatedSprite; import org.andengine.entity.sprite.TiledSprite; import org.andengine.entity.sprite.vbo.ITiledSpriteVertexBufferObject; import org.andengine.opengl.texture.TextureOptions; import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas; import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory; import org.andengine.opengl.texture.atlas.bitmap.source.AssetBitmapTextureAtlasSource; import org.andengine.opengl.texture.region.ITiledTextureRegion; import org.andengine.opengl.texture.region.TiledTextureRegion; import org.andengine.opengl.vbo.VertexBufferObjectManager; import org.andengine.ui.activity.BaseGameActivity; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.support.v4.app.NavUtils; public class MoveBall extends BaseGameActivity { private static final int CAMERA_WIDTH = 800; private static final int CAMERA_HEIGHT = 480; private final static float BALL_VELOCITY = 100f;//球的移动速度 private Camera mCamera; private Scene mScene; private RepeatingSpriteBackground background; private TiledTextureRegion mFaceTextureRegion; @Override public EngineOptions onCreateEngineOptions() { // TODO Auto-generated method stub mCamera = new Camera(0,0,CAMERA_WIDTH,CAMERA_HEIGHT); EngineOptions mEngineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_SENSOR, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), mCamera); return mEngineOptions; } @Override public void onCreateResources( OnCreateResourcesCallback pOnCreateResourcesCallback) throws Exception { // TODO Auto-generated method stub this.background = new RepeatingSpriteBackground(CAMERA_WIDTH, CAMERA_HEIGHT, getTextureManager(), AssetBitmapTextureAtlasSource.create( this.getAssets(), "background.png"), getVertexBufferObjectManager()); BitmapTextureAtlas mTexture = new BitmapTextureAtlas(getTextureManager(),64,32,TextureOptions.BILINEAR_PREMULTIPLYALPHA); mFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "face_circle_tiled.png", 0, 0,2,1); /** * 参数说明: * mTexure是在内存中放置贴图资源用的,64,32是图片要求的宽和高,必须是2的n次方大小.如:2,4,8,16,32,64,128,512,1024.... * 并且要比原图的宽高要大 * * mFaceTextureRegion相当于从mTexure中扣图,因为mTexure是由很多图集组成的,要从中截取一片出来 * 0,0代表截图的top,right坐标(起点坐标),2和1分别代表贴图中一张存在2列1行 * */ mTexture.load(); pOnCreateResourcesCallback.onCreateResourcesFinished(); } @Override public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) throws Exception { // TODO Auto-generated method stub mScene = new Scene(); mScene.setBackground(background); final float centerX = (CAMERA_WIDTH - mFaceTextureRegion.getWidth()) / 2;//计算贴图的中心坐标 final float centerY = (CAMERA_HEIGHT - mFaceTextureRegion.getHeight()) / 2; final Ball mBall = new Ball(centerX, centerY,32, 32,this.mFaceTextureRegion,getVertexBufferObjectManager()); mScene.attachChild(mBall); pOnCreateSceneCallback.onCreateSceneFinished(mScene); } @Override public void onPopulateScene(Scene pScene, OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception { // TODO Auto-generated method stub pOnPopulateSceneCallback.onPopulateSceneFinished(); } private static class Ball extends AnimatedSprite{ float mVelocityX = BALL_VELOCITY;//球的x方向速度 float mVelocityY = BALL_VELOCITY ;//球的y方向速度 public Ball(float pX, float pY, float pWidth, float pHeight, ITiledTextureRegion pTiledTextureRegion, VertexBufferObjectManager pVertexBufferObjectManager) { super(pX, pY, pWidth, pHeight, pTiledTextureRegion, pVertexBufferObjectManager); // TODO Auto-generated constructor stub mX = 100; mY = 100; } @Override protected void onManagedUpdate(float pSecondsElapsed) { // TODO Auto-generated method stub if(this.mX < 0) { setVelocityX(BALL_VELOCITY); } else if( this.mX + this.getWidth() > CAMERA_WIDTH){ setVelocityX(-BALL_VELOCITY); } if(this.mY < 0 ) { setVelocityY(BALL_VELOCITY); } else if(this.mY + this.getHeight() > CAMERA_HEIGHT){ setVelocityY(-BALL_VELOCITY); } mX += mVelocityX * pSecondsElapsed; mY += mVelocityY * pSecondsElapsed; this.setPosition(mX, mY); Log.d("Season",pSecondsElapsed + ""); super.onManagedUpdate(pSecondsElapsed); } void setVelocityX(float vx){ mVelocityX = vx; } void setVelocityY(float vy){ mVelocityY = vy; } } }
很重要的一步,为了让游戏顺利运行,一定要将AndEngine/bin/andengine.jar拷贝到MoveBall/libs下
本例子用到两张图片:
把这两张图片拷贝到MoveBall/assets目录下
然后运行就可以看到一个运动的小脸蛋了.呵呵
本例子源代码:http://download.csdn.net/detail/cen616899547/4701606