IntentService冻结了我的应用程序UI

在我的应用程序中,我使用Intentservice从服务器获取数据并将获取的数据存储到本地sqlite db。 我正在使用5个IntentService来获取和填充五个表。 每个Intent Service的数据最多可达300行。 我该怎么办?

IntentService代码:

public class SendBpRecordServer extends IntentService { DbHelper dbHelper; public static final String TAG="BP Service"; public JSONObject finalData; public SendBpRecordServer() { super("BP"); dbHelper=new DbHelper(this); Log.i("In Constructor",TAG); } @Override protected void onHandleIntent(Intent intent) { String recName=intent.getStringExtra("nameTag"); if (recName.equals("fetch")) { Log.i("Send Data","Yes"); fetchDatFromServer(); ResultReceiver resultReceiver=intent.getParcelableExtra("receiverTagBP"); Log.d("BP Reseult ",resultReceiver.toString()); Bundle bun= new Bundle(); bun.putBoolean("Process_Complete_bp",true); resultReceiver.send(2, bun); } else { Log.i("Inside Service PUT BP ","Yes"); dataCollected(); } } private void fetchDatFromServer() { Response.Listener listener=new Response.Listener() { @Override public void onResponse(JSONObject response) { Log.i("Json Array Response", response.toString()); try { Boolean responseStatusCondition=response.getBoolean("success"); if (responseStatusCondition) { JSONArray jsonArray=response.getJSONArray("response"); Log.i("Array Size is",Integer.toString(jsonArray.length())); for (int i=0;i<jsonArray.length();i++) { JSONObject childJSONObject = jsonArray.getJSONObject(i); //Set the flag bit to 1 since data is already at server long result=dbHelper.insertIntoBloodPressureDetails(childJSONObject.getInt("systolic"), childJSONObject.getInt("diastolic"), childJSONObject.getLong("timestamp"),1 ); // Log.i("Insertion result ",Long.toString(result)); } Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT")); c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.MINUTE, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); //This is midnight time in GMT long unixTimeStamp = c.getTimeInMillis(); //Convert it in to Indian time System long indianMidNightTime=unixTimeStamp-19800000; //Log.i("Now Calculates Days","doing"); dbHelper.calculateDays(dbHelper.bpTableName, dbHelper.bpCOLUMN_days, dbHelper.bpCOLUMN_timestamp, indianMidNightTime); } }catch (JSONException js) { js.printStackTrace(); } } }; Response.ErrorListener errorListener=new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { NetworkResponse response = error.networkResponse; // Handle Error if (error instanceof TimeoutError || error instanceof NoConnectionError) { error.printStackTrace(); Toast.makeText(getApplicationContext(), " this Network Error", Toast.LENGTH_SHORT).show(); } else if (error instanceof AuthFailureError) { //TODO error.printStackTrace(); Toast.makeText(getApplicationContext(), "User not authorized", Toast.LENGTH_SHORT).show(); } else if (error instanceof ServerError && response != null) { try { String res = new String(response.data, HttpHeaderParser.parseCharset(response.headers, "utf-8")); // Now you can use any deserializer to make sense of data JSONObject obj = new JSONObject(); obj.put("New Error",res); Log.i("New Server Error",obj.toString()); } catch (UnsupportedEncodingException e1) { // Couldn't properly decode data to string e1.printStackTrace(); } catch (JSONException e2) { // returned data is not JSONObject? e2.printStackTrace(); } } else if (error instanceof NetworkError) { //TODO error.printStackTrace(); Toast.makeText(getApplicationContext(), "Network Error", Toast.LENGTH_SHORT).show(); } else if (error instanceof ParseError) { //TODO error.printStackTrace(); Toast.makeText(getApplicationContext(), "Error consuming request", Toast.LENGTH_SHORT).show(); } else error.printStackTrace(); } }; String bp_url=Constants.url+"bp"; JsonObjectHeader customRequest=new JsonObjectHeader(bp_url, null, listener, errorListener); RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext()); requestQueue.add(customRequest); } private void dataCollected() { JSONArray jsonArray=new JSONArray(); ArrayList arrayList=dbHelper.fetchDataFromBp(); for (int i=0;i<arrayList.size();i++) { Graph graph=new Graph(); graph=arrayList.get(i); try { JSONObject jsonObject=new JSONObject(); jsonObject.put("systolic",graph.getHeight()); jsonObject.put("diastolic",graph.getWeight()); jsonObject.put("timestamp",graph.getTime()); jsonArray.put(jsonObject); }catch (JSONException js) { js.printStackTrace(); } } finalData=new JSONObject(); try { finalData.put("bp",jsonArray); }catch (JSONException js) { js.printStackTrace(); } sendDatatoServer(); } private void sendDatatoServer() { Response.Listener listener=new Response.Listener() { @Override public void onResponse(JSONObject response) { try { // Parsing json object response // response will be a json object //Toast.makeText(getApplicationContext(),response.toString(),Toast.LENGTH_LONG).show(); Boolean responseStatusCondition = response.getBoolean("success"); Log.i("Response BP",responseStatusCondition.toString()); if (responseStatusCondition) dbHelper.setTheFlagBpTable(); else Log.i("Something Went Wrong"," On Server"); } catch (JSONException k) { Log.i("On Response",k.getMessage()); k.printStackTrace(); } } }; Response.ErrorListener errorListener=new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // Handle Error if (error instanceof TimeoutError || error instanceof NoConnectionError) { error.printStackTrace(); Toast.makeText(getApplicationContext(), " this Network Error", Toast.LENGTH_SHORT).show(); } else if (error instanceof AuthFailureError) { //TODO error.printStackTrace(); Toast.makeText(getApplicationContext(), "User not authorized", Toast.LENGTH_SHORT).show(); } else if (error instanceof ServerError) { //TODO error.printStackTrace(); Toast.makeText(getApplicationContext(), "Server error", Toast.LENGTH_SHORT).show(); } else if (error instanceof NetworkError) { //TODO error.printStackTrace(); Toast.makeText(getApplicationContext(), "Network Error", Toast.LENGTH_SHORT).show(); } else if (error instanceof ParseError) { //TODO error.printStackTrace(); Toast.makeText(getApplicationContext(), "Error consuming request", Toast.LENGTH_SHORT).show(); } else error.printStackTrace(); } }; Log.i("Bp Final Data",finalData.toString()); JsonObjectHeader customRequest=new JsonObjectHeader(Request.Method.PUT, Constants.url+"bp", finalData, listener, errorListener); RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext()); requestQueue.add(customRequest); } } 

调用intentservice的代码:

 Log.i("Fetch BP Data ", SendBpRecordServer.TAG); resultReceiverBP=new MyResultReceiver(new Handler()); resultReceiverBP.setReceiver(this); Log.i("Bp resultreceiver ",resultReceiverBP.toString()); Intent intent2=new Intent(this,SendBpRecordServer.class); intent2.putExtra("nameTag","fetch"); intent2.putExtra("receiverTagBP",resultReceiverBP); startService(intent2); 

并在完成任务时向我发送代码

在onReceiveResult中..结果代码通过调用intentservice发送,当计数进入5时,然后发出主要活动(虽然这个技巧不起作用,即启动mainactivity而不完成分配给intentservice的任务)。

 @Override public void onReceiveResult(int resultCode, Bundle resultData) { // TODO Auto-generated method stub Log.d("Diabetes","received result from Service= "+resultData.getString("ServiceTag")); // Log.d("BMI ","received result from Service= "+resultData.getString("ServiceTag")); /* if (progressDialog.isShowing()) { progressDialog.dismiss(); }*/ Log.i("Get Values ",Integer.toString(Constants.getValues)); if (resultCode==0 && resultData.getBoolean("Process_Complete")) Constants.getValues++; if (resultCode==1 && resultData.getBoolean("Process_Complete_bmi")) Constants.getValues++; if (resultCode==2 && resultData.getBoolean("Process_Complete_bp")) Constants.getValues++; if (resultCode==3 && resultData.getBoolean("Process_Complete_med_stats")) Constants.getValues++; if (resultCode==4 && resultData.getBoolean("Process_Complete_one")) Constants.getValues++; if (Constants.getValues==5) { Constants.getValues=0; if (progressDialog.isShowing()) { progressDialog.dismiss(); } startActivity(new Intent(this,MainActivity.class)); finish(); } } 

您是否完全确定IntentService是UI冻结的根本原因? Intent服务专门设计用于在工作线程中运行,以便从主(UI)线程卸载处理,其中一个主要原因是帮助防止 UI冻结。

也许尝试在UI级别开始调试工作。 特别是,当你启动它时,它为IntentService提供了ResultReceiver ,你在该接收器实例中的onReceiveResult回调方法中做了什么?

除此之外,对于您遇到冻结的活动,请检查您正在进行的操作。 从主线程上的数据库加载大量数据(即不使用Loader或类似的东西将处理卸载到工作线程)是UI冻结的常见原因,至少在我迄今为止的经验中。

更新

我想我已经解决了问题所在。 有两个主要问题,都源于你如何使用Volley。 向Volley队列添加请求时,它将异步执行。 这意味着queue方法立即返回。 在您的意图服务代码中,这意味着服务立即继续告诉ResultReceiver它已经完成处理,而实际上它所做的全部是对请求进行排队。 所有五个意图服务都将执行此操作,这意味着MainActivity将很快进入。 这是第一个问题。

第二个问题解释了您遇到的冻结问题。 虽然Volley在工作线程上执行请求,但它会将解析后的响应返回给主线程上的请求 – 请参阅此处的文档。 这意味着您在意图服务中执行的所有响应处理(将数据放入数据库等)实际上发生在主(UI)线程上。 这解释了冻结。

您可能想要做的是切换到使用Volley的RequestFuture 。 这基本上允许您阻塞直到请求完成,从而将异步请求转换为同步请求。 为此,请创建适当类型的未来(在您的情况下为JSONObject ),并将其设置为请求的侦听器和错误侦听器。 然后,像现在一样对请求进行排队,然后立即调用将来的get方法。 此方法将阻止,直到响应处理完毕。 在意图服务中执行此操作是可以的,因为它在工作线程上运行,而不是在UI线程上运行。

如果请求成功,您将获得返回的数据,并且您可以执行当前在Response.Listener实现中的所有逻辑。 如果发生错误(即请求因某种原因而失败),请求将来将抛出一个exception,您可以处理该exception以采取任何适当的操作。

使用请求期货是一种使用侦听器的完全不同的方法,您可能需要更改代码以使其工作,但它应该解决您所看到的问题。

希望有所帮助,并且我真诚地道歉,因为我们没有及早发现这个bug。