我对Android编程比较陌生,但我确实来自Java背景,为企业应用程序构建后端内容。现在,我正在开发一个Android项目,我想从服务器中检索一个java.util.List of Restaurants。
目前,为了实现这些任务,我使用一个带有新Runnable的简单Thread,因为该线程立即在Thread-pool中,然后我可以简单地加入Thread,并等到它收到来自服务器的回复并且然后发回去。这很方便,而且工作得很好。
但是,我不能对Threads做两件事,检查客户端的Internet连接并显示进度条。据我理解和阅读,这两件事都可以通过AsyncTask来实现。
但这是关键点,我不希望AsyncTask在不久的将来执行然后返回结果,因为使用我当前的Thread模型,我可以简单地加入Thread并放松。
现在,我的问题是,在AsyncTask中是可能的,我并不是说在1000毫秒后使用get方法。我的意思是等待它。我该如何做到这一点?有了这个,我想知道如何检查INternet,如果成功,那么只提出请求。
这是我在项目中使用的Async方法之一,接下来是我在项目中使用的简单Thread模型。
private class LoginUserViaRest extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... params) {
final EditText userEmail = (EditText) findViewById(R.id.usernameText);
final EditText userPassword = (EditText) findViewById(R.id.PasswordField);
rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
StaticRestTemplate.jsessionid = rest.execute(StaticRestTemplate.baseURL+"j_spring_security_check", HttpMethod.POST,
new RequestCallback() {
@Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getBody().write(("j_username=" + userEmail.getText().toString() + "&j_password=" + userPassword.getText().toString()).getBytes());
}
}, new ResponseExtractor<String>() {
@Override
public String extractData(ClientHttpResponse response) throws IOException {
List<String> cookies = response.getHeaders().get("Cookie");
if (cookies == null) {
cookies = response.getHeaders().get("Set-Cookie");
}
String cookie = cookies.get(cookies.size() - 1);
int start = cookie.indexOf('=');
int end = cookie.indexOf(';');
return cookie.substring(start + 1, end);
}
});
return null;
}
@Override
protected void onPostExecute(String aVoid) {
super.onPostExecute(aVoid);
}
}
检索图像的线程:
@Override
public List<RestImage> getImagesForMenuCard(final int menuCardId) {
final RestTemplate restTemplate = StaticRestTemplate.getRest();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", "JSESSIONID=" + StaticRestTemplate.jsessionid);
requestHeaders.setAccept(Collections.singletonList(new MediaType("application", "json")));
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
menuCardImageEntity = restTemplate.exchange(menucardImageList + menuCardId, HttpMethod.GET, requestEntity, RestImage[].class);
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
RestImage[] restImages = menuCardImageEntity.getBody();
List<RestImage> restImageList = new ArrayList<>();
Collections.addAll(restImageList, restImages);
return restImageList;
}
我发现Thread模型很简单,因为我知道它更好。我真的不明白创建一个类来发出网络请求的要求。 我对AsyncTask的理解是否被打破,或者这是它应该是这样的方式。
为大量文本道歉,我想我会简明扼要地解释一下我的情况。非常感谢。
答案 0 :(得分:2)
如果你调用join(),你的线程正在等待另一个线程死掉。由于您调用连接的线程是Main或UI Thread,这意味着您要阻止UI,这是您应该避免的。现在 - 我真的很讨厌AsyncTask,但它是执行(可能)长时间运行任务的Android标准方式。您可以查看IntentService(但您必须管理服务和UI之间的通信),或者您可以查看RxJava和RxAndroid(这是我最喜欢的框架)。
关于检查连接,您需要ConnectivityManager类,当然需要上下文。
答案 1 :(得分:1)
没有要求AsyncTask
特别用于任何事情。您可以使用任何您喜欢的Java并发类/技术/框架。
AsyncTask
的好处是它为您提供了一个很好的抽象,以保证在某些线程上执行某些代码(doInBackground()
在后台线程上执行; onPreExecute()
,onPostExecute()
,并且主线程上有onProgressUpdate()
,所以如果你想根据AsyncTask
的进度/完成情况更新用户界面,这很容易做到。一般来说,我推荐AsyncTask
用于可能对UI产生直接影响的相对较短的操作,例如在后台模糊位图,然后将其设置为ImageView
重要的一点是,你永远不应该阻止主(UI)线程。这意味着在该线程上调用join()
总是一个坏主意。您需要设计代码,以便在异步操作完成时通知您 - 通常这涉及回调接口或其他一些可观察的模式。可以这样想:只因为你在等待&#34;对于结果并不意味着必须阻止线程,您可能必须确保用户无法与UI的某些部分进行交互。
关于这个主题有一些好书,我建议搜索它们。
答案 2 :(得分:0)
不要在主线程中使用join()
,因为如果您正在等待的线程陷入循环或者没有返回(从其run方法返回),您将获得ANR
至于你的问题,AsyncTask类和Java中的其他并发方法没有区别。 AsyncTask的作用是抽象背景中的操作,一种在后台发出操作通知并发布后台操作结果的方法。
我自己更喜欢使用Thread类,并使用接口回调我的操作状态。考虑以下内容:
public class BackgroundOperationWorker implements Runnable{
private Thread thread;
private IOperationListener listener;
Handler handler;
public BackgroundOperationWorker(Handler mainThreadHandler,IOperationListener listener)
{
this.handler = mainThreadHandler;
this.listener = listener;
}
public void doIt(){
thread = new Thread(this);
thread.start();
}
@Override
public void run(){
/**
do what you have to do in the thread
**/
if(success){
handler.post(new Runnable(){
listener.operationSuccess();
});
}else{
handler.post(new Runnable(){
listener.operationFailed();
});
}
}
}
要小心,如果侦听器在您的活动类中实现,在轮换等配置更改时,接口实例将变为无效,您必须在活动的onConfigurationChanged(Bundle bundle)
方法中再次设置该实例。 / p>
编辑: 编辑上面的示例代码使其更简单。
考虑以下代码:
public class MyClass implements IOperationListener{
public BackgroundOperationWorker worker;
public MyClass(Context context){
this.worker = new BackgroundOperationWorker(new Handler(context.getMainLooper()),this/*as an instance of IOperationListener*/);
this.worker.doIt();
}
@Override
public void onOperationSuccess(){
//notify the user that the operation is successful
}
@Override
public void onOperationFailed(){
//notify the user that the operation has failed
}
}
这个MyClass就是一个例子。这可以是您实施&#34; IOperationListener&#34;。
的活动