Android:实时获取数据而不是使用Async-Task

时间:2015-09-04 14:15:04

标签: java android multithreading asynchronous android-asynctask

我对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的理解是否被打破,或者这是它应该是这样的方式。

为大量文本道歉,我想我会简明扼要地解释一下我的情况。非常感谢。

3 个答案:

答案 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的某些部分进行交互。

关于这个主题有一些好书,我建议搜索它们。

编辑这里有一个:http://shop.oreilly.com/product/0636920029397.do

答案 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;。

的活动