我决定学习Scala / Play(服务器端),并决定同时学习 Android (客户端)游戏开发,以增加开发。
我有一个关于如何在Android中为HTTP请求设计好的问题
根据我的理解,最好的方法是将HTTP请求委托给扩展抽象AsyncTask
类的类
您是否必须为您覆盖的AsyncTask
方法中的每个不同逻辑执行doInBackground
的新扩展?
对我来说,为每个请求逻辑创建一个类并不是很自然,而是在一个类中封装几个连贯的方法。
我刚刚开始玩一点,但我对设计不满意,因为我不喜欢doInBackground(Object... params)
中设计的varargs对象。
通过这种设计,我放松了类型安全性,并且params对象远非直观和直观,这是我在我的代码中努力的目标。
以下是我想要改进的代码。
public class GameActivity extends Activity {
private class MyCellListener implements ICellListener {
public void onCellSelected() {
ServerProxy.postSelectedCell(row, col, player.getUser());
...
// ServerProxy.other();
public class ServerProxy extends AsyncTask<Object, Void, Void>{
private static final String TAG = ServerProxy.class.getSimpleName();
private static final String SERVER_ADDRESS = "http://127.0.0.1";
// Prevent external instantiation
private ServerProxy(){};
public static void postSelectedCell(int row, int cell, User user){
List<NameValuePair> postParameters = new ArrayList<NameValuePair>(3);
postParameters.add(new BasicNameValuePair("row", String.valueOf(row)));
postParameters.add(new BasicNameValuePair("cell", String.valueOf(cell)));
postParameters.add(new BasicNameValuePair("userName", user.getUserName()));
new ServerProxy().doInBackground("setSelectedCell" , postParameters);
}
// public static void postOther() {
// new ServerProxy().doInBackground("other" , //some parameters);
// }
/**
* @param postParameters First object URL postfix<br/>
* Second parameter is post parameters inform of {@code List<NameValuePair>}
* @return null
*/
@SuppressWarnings("unchecked")
@Override
protected Void doInBackground(Object... params) {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(SERVER_ADDRESS +"/" + params[0]);
httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
try {
httppost.setEntity(new UrlEncodedFormEntity((List<NameValuePair>) params[1]));
httpclient.execute(httppost);
} catch (ClientProtocolException e) {
Log.e(TAG,e.toString());
} catch (IOException e) {
Log.e(TAG,e.toString());
}
return null;
}
}
答案 0 :(得分:5)
我认为你不明白AsyncTask的作用。你无法在单个AsyncTask子类上定义postLastName,postFirstName,postWhatever等方法,并让它从UI线程执行该方法调用。 AsyncTask旨在使您更容易执行需要更新UI的后台作业,而不必强制您直接处理线程。
为了与您正在使用HttpClient的服务器通信,调用HttpClient.execute()将阻塞,直到服务器的响应返回。这可能需要很长时间,特别是如果服务器繁忙,死机或电池无线电发生故障。当该调用时间过长时,您不希望UI停止响应用户。你想展示一个旋转器,让用户知道发生了什么。如果您使用了您提供的代码,那么您将在返回的HttpClient.execute()调用之前使用您的UI来进行绘制,因为您在UI线程上调用它。
解决这个问题的方法是将此UI调用关闭到另一个线程。让该线程等待响应,然后让它通知UI线程完成它并使用UI线程用新数据更新UI。为什么不能让后台线程更新UI?因为这会违反Android的线程规则,该规则只表示UI线程可以更新UI。
AsyncTask允许您在UI线程(doInBackground())中运行某些内容,并将返回值发布到UI线程(onPostExecute()),以便它可以安全地更新UI而不违反Android的规则。你不直接调用doInBackground()或onPostExecute(),而是调用AsyncTask.execute(),AsyncTask中的代码将在后台线程上调用doInBackground(),当它完成时,它将在UI线程上调用onPostExecute() 。这样你就不会因为自己完成所有的线程而纠缠不清。
现在你想通过单个子类运行多个请求是不行的,因为AsyncTask将服务调用的两个部分联系在一起:执行服务调用以获取响应的细节,以及如何处理响应更新UI。如果调用postFastName()方法,则在返回该响应之后执行的操作可能与您调用postLastName()有所不同。而且因为它的不同意味着你不能只为所有这些不同的调用定义一个AsyncTask。您可以通过组合或子类化基类来共享代码,但是您必须为要在服务器上执行的每个唯一操作创建子类。因此,对每次调用都要考虑Class而不是Method。
您不必使用传递给doInBackground()的参数。如果您有多种类型的参数传递给AsyncTask。在构造函数中传递它们。因为您无法重用AsyncTask实例(即每个实例不能多次调用AsyncTask.execute())。他们的生命周期必须是实例化,执行()和折腾。这意味着在构造函数中传递输入不会损害您使用AsyncTask的能力。
我编写了自己的AsyncTask版本,它分离出三个回调方法:success(),用于处理从doInBackground()返回的结果;当从doInBackground()抛出任何异常时调用handleException();和doFinally()调用,无论doInBackground()返回什么或引发异常。默认情况下,无论错误或成功如何,都会调用asyncTask onPostExecute()。它看起来像这样:
public class MyTask extends EnhancedAsyncTask<Param,Integer,MyResult> {
MyParam1 param1;
MyParam2 param2;
public MyTask( MyParam1 param1, MyParam2 param2 ) {
this.param1 = param;
this.param2 = param2;
}
protected MyResult doInBackground( Param... params ) {
// do server work here
server.send( param1, param2 );
}
protected void success( MyResult result ) {
// do Update of the UI
}
protected void handleException( Exception ex ) {
// show an error here
}
}
// Now to use this AsyncTask you would do something like this:
MyTask task = new MyTask( param1, param2 ).execute();
我经常将其作为匿名内部类来执行此操作,因此不需要传递对UI的引用,但如果不执行Anon类,则可以将它们传递给构造函数。如果活动被销毁(例如用户翻转屏幕),您必须小心不要触摸UI。
答案 1 :(得分:0)
在设计之前,有些事情看起来你做错了。
您不应该像在这里一样直接致电doInBackground
new ServerProxy()。doInBackground(“setSelectedCell”,postParameters);
相反它应该调用任何version of execute
至于设计,你可以试试这个
ServerProxy
类,但不要从AsyncTask
扩展它。只需用它来封装你的逻辑。ServerProxyAsync
,其中ServerProxy
将作为构图。现在您可以选择一个选项
公共类ServerProxy扩展了AsyncTask
此处String
可能是您要在ServerProxy
个实例上调用的方法名称,您可以使用反射。
注意:此问题可能还有其他问题,这只是问题的第一次尝试