Android:实时获取数据而不是使用异步任务
我对Android编程相对陌生,但我确实来自Java背景,为企业应用程序构建后端工具。现在,我正在开发一个Android项目,在该项目中,我想从服务器中检索餐馆的java.util.List。Android:实时获取数据而不是使用异步任务
目前,为了实现这些任务,我使用了一个简单的线程和一个新的Runnable,因为线程立即在线程池中,然后我可以简单地加入线程,并等待它从服务器收到回复然后发回。非常方便,这是工作良好。
但是,有两件事情我不能使用线程来检查客户端的Internet连接并显示一个进度条。据我了解和阅读,这两个东西可以通过AsyncTask来实现。
但是,这里是关键点,我不希望AsyncTask在不久的将来执行,然后返回结果,因为使用当前的Thread模型,我可以简单地加入Thread并放松。
现在,我的问题是,在AsyncTask中是可能的,我不是说在1000毫秒后使用get方法。我的意思是真的在等待它。我如何实现这一目标?就此,我想知道如何检查INternet,如果成功,那么只能提出请求。
这是我在项目中的异步方法之一,然后下一个是我在项目中使用的简单线程模型。
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;
}
我找到线程模型很容易,因为我更好地了解它。我真的不明白需要创建一个类来发出网络请求。 我对AsyncTask的理解是否被破坏,或者这是它应该是的方式。对于大量文字的道歉,我想简明扼要地解释我的情况。非常感谢。
如果你调用join(),你的线程正在等待另一个线程死掉。由于您称为连接的线程是主线程或用户线程线程,这意味着您将阻止用户界面,这是您应该避免的。现在 - 我真的很讨厌AsyncTask,但它是执行(可能)长时间运行任务的Android标准方式。你可以看看IntentService(但你必须管理服务和UI之间的通信),或者你可以看看RxJava和RxAndroid(这是我最喜欢的框架)。
关于检查连接,你需要ConnectivityManager类,当然这需要一个上下文。
RxJava和RxAndroid看起来很有前途,而且相当方便,而与AsyncTask混杂在一起。在我接受你的答案之前的最后一件事,你能帮我翻译我在主要Post中的登录代码到RxAndroid代码。我正在设置服务器返回的JSESSIONID的值。 –
这是一个有点棘手的代码与登录,这就是为什么。非常感谢。 :-) –
好的。在[Retrofit](http://square.github.io/retrofit/)中获得战利品,这样你就可以忘记所有与http相关的东西。图书馆可以为您提供每个网络请求的Observable
没有特别要求使用AsyncTask
。您可以使用您喜欢的任何Java并发类/技术/框架。
的AsyncTask
的好处是它给你一个很好的抽象为保证某些线程(doInBackground()
在后台线程; onPreExecute()
,onPostExecute()
和onProgressUpdate()
在主线程上)执行某些代码,所以如果你想更新基于AsyncTask
的进度/完成的UI,这很容易实现。通常我建议AsyncTask
用于可能对用户界面有直接影响的相对较短的操作,例如在背景中模糊一个位图,然后将其设置为内容ImageView
重要的是要避免阻塞主(UI)线程。这意味着在该线程上调用join()
总是一个坏主意。您需要设计代码,以便在异步操作完成时通知您,这通常包括回调接口或其他可观察模式。这样想:仅仅因为你“等待”结果并不意味着线程必须被阻止,你可能必须确保用户不能与UI的某个部分进行交互。
关于这个问题有一些很好的书,我建议你去搜索一下。这里
这是正确的答案。永远不要使用连接的线程导致你阻塞UI线程。 Android 101说永远不会妨碍用户的体验,如果你必须使用微调,并使用AsyncTasks ......节省你很多时间和精力 –
永远不要使用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)
方法重新设置实例。
编辑: 编辑上面的示例代码,使其更加简单。
考虑下面的代码:
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的就是一个例子。这可以是您执行“IOperationListener”的活动。
你如何从上面的类调用方法,你在哪里得到答复?你有没有使用上述类的代码?非常感谢!!! –
@WeareBorg我编辑的答案更清晰。 MyClass使用BackgroundWorker类。 BackgroundWorker类的doIt方法初始化后台线程并启动它。由于BackgroundWorker实现了Runnable,因此我将BackgroundWorker实例传递给后台线程。线程启动后,BackgroundWorker的run方法将从线程中调用。 –
不幸的是,Android不支持Java8,否则我只会在线程中添加Lambda表达式来创建一个更紧凑的版本。 –
使用AsyncTask被称为无痛线程,以下是Android开发人员有关AsyncTask与线程:[无痛线程](http://android-developers.blogspot.com/2009/05/painless-threading.html)和另一个很好的阅读在这里:[处理器VS AsyncTask与线程](http://stackoverflow.com/a/9800870/593709) –
@AdilSoomro:我没有长时间运行的任务,既不频繁的UI更新...你给的链接只是指以表明有人冻结视图。不相关,因为我想在进行网络请求时显示进度条。 –