【问题标题】:httpclient sleeps while executinghttpclient 在执行时休眠
【发布时间】:2013-01-23 07:38:34
【问题描述】:

我正在开发长时间运行的应用程序,我的应用程序定期使用DefaultHttpClient(我也尝试过使用AndroidHttpClient)。我不知道,但工作一段时间后,不知何故httpClient.execute 睡着了。从字面上看,当我唤醒(解锁或连接到 PC)时,我的设备 httpClient 立即继续工作(如果我设置超时或仅返回执行响应,则会引发异常)。我搜索并尝试了类似的案例和非工作。对于唤醒和 wifilocks,我只是在执行前获取 wifi 锁和唤醒锁,并在得到响应后释放它。没有任何效果,我也不知道。

我工作的设备是 Galaxy S3(v4.0+) 和 Ace(v2.3.6)

提前致谢。

这是卡住的 MyTask,它卡在 response = new MyClient(ctx).client.execute(post);MyClient 是一个包装器,用于处理 https 和证书的事情。

public abstract class GenericTask extends AsyncTask<Object, Object, Document> {


public final static String TAG = "GenericTask";
private WakeLock wakeLock;
private WifiLock wifiLock;
protected HttpPost post;
public String taskId;
public Context ctx;
Object parameter;

public GenericTask(Context ctx, Object parameter) {
    this.parameter = parameter;
    this.ctx = ctx;
    post = null;
    initLock(ctx);
    lock();
}
private void lock() {
    try {
        wakeLock.acquire();
        wifiLock.acquire();
        Log.d(TAG,"LockAcquired");
    } catch (Exception e) {
        Log.e("WlanSilencer", "Error getting Lock: " + e.getMessage());
    }
}

private void unlock() {
    Log.e(TAG,"unlock");
    if (wakeLock.isHeld())
        wakeLock.release();
    if (wifiLock.isHeld())
        wifiLock.release();
    Log.d(TAG,"LockReleased");
}

private void initLock(Context context) {
    wifiLock = ((WifiManager) context
            .getSystemService(Context.WIFI_SERVICE)).createWifiLock(
            WifiManager.WIFI_MODE_FULL_HIGH_PERF, "GenericTaskWifiLock");
    wakeLock = ((PowerManager) context
            .getSystemService(Context.POWER_SERVICE)).newWakeLock(
            PowerManager.FULL_WAKE_LOCK, "GenericTaskWakeLock");
    Log.d(TAG,"LockInitiated");
}

public boolean cancelTask(boolean bln) {
    if(post!=null)
        post.abort();
    return super.cancel(bln);
}

public void execute(){
    if(Build.VERSION.SDK_INT >= 11){
        startNew();
    }else{
        startOld();
    }
}
private void startOld() {
    super.execute();

}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void startNew(){
    executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR );
}
@Override
protected void onPostExecute(Document doc) {
    unlock();
    if(doc==null){
        Log.e("GenericTask: " +getClass(),"onPostExecute doc=null");
    }
    Log.e(TAG,"onPostExecute");
        TaskManager.getInstance().returnFromTaskSuccess(doc, getClass(), taskId, parameter);

}

@Override
protected Document doInBackground(Object... params) {
    Log.e(TAG,"doInBackground");
    try {
        return call();
    } catch (InvalidKeyException e) {
        OtherUtils.printStackTrace(e);
    } catch (NoSuchPaddingException e) {
        OtherUtils.printStackTrace(e);
    } catch (InvalidAlgorithmParameterException e) {
        OtherUtils.printStackTrace(e);
    } catch (IllegalStateException e) {
        OtherUtils.printStackTrace(e);
    } catch (NoSuchAlgorithmException e) {
        OtherUtils.printStackTrace(e);
    } catch (IOException e) {
        OtherUtils.printStackTrace(e);
    } catch (TransformerException e) {
        OtherUtils.printStackTrace(e);
    } catch (ParserConfigurationException e) {
        OtherUtils.printStackTrace(e);
    }
    return null;
}
protected abstract String getUrl();

protected abstract Document getRequest();

public int initialSleep() {
    return 0;
}

public String getTaskId() {
    return taskId;
}

public void setTaskId(String taskId) {
    this.taskId = taskId;
}

protected Document call() throws IOException, TransformerException, ParserConfigurationException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalStateException, NoSuchAlgorithmException{


Document doc = getRequest();
    String url = getUrl();
    Document responseXml = null;
    try {

        post = HttpUtils.postXml(doc, url, null);

        HttpResponse response;
        HttpParams httpParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, 16000);
        HttpConnectionParams.setSoTimeout(httpParams, 20000);
        post.setParams(httpParams);
        response = new MyClient(ctx).client.execute(post);
        HttpEntity resEntity = response.getEntity();
        responseXml = XmlUtils.entityToXml(resEntity, null);
        resEntity.consumeContent();
        return responseXml;
    } catch (TransformerException e) {
        throw e;
    } catch (IOException e) {
        throw e;
} 


}
}

HttpUtils:

public class HttpUtils {
public static HttpPost postXml(Document doc, String url, WrapperAsByteArrayOutputStream baos) throws IOException, TransformerConfigurationException, TransformerException
{
    StringWriter xmlAsWriter = new StringWriter();
    StreamResult result = new StreamResult(xmlAsWriter);
    TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc), result);
    HttpPost post = new HttpPost(url);
    InputStreamEntity req;
    if ( baos == null ) {
        req = new InputStreamEntity(new ByteArrayInputStream(xmlAsWriter.toString().getBytes()), -1);
    }
    else {
        req = new InputStreamEntity(new WrappedInputStream(new ByteArrayInputStream(xmlAsWriter.toString().getBytes()), baos), -1);
    }
    req.setChunked(true);
    post.setEntity(req);
    return post;
}

我的客户:

公共类 MyClient 扩展 DefaultHttpClient { 公共 HttpClient 客户端;

public MyClient(Context ccc) {
    super();
    KeyStore localTrustStore = null;
    try {
        localTrustStore = KeyStore.getInstance("BKS");
    } catch (KeyStoreException e) {
        e.printStackTrace();
    }
    InputStream in = ccc.getResources().openRawResource(
            R.raw.localcert);
    try {
        localTrustStore.load(in, "local_trust_password".toCharArray());
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("http", PlainSocketFactory
            .getSocketFactory(), 80));
    SSLSocketFactory sslSocketFactory = null;
    try {
        sslSocketFactory = new SSLSocketFactory(localTrustStore);
    } catch (KeyManagementException e) {
        e.printStackTrace();
    } catch (UnrecoverableKeyException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    }
    schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
    HttpParams params = new BasicHttpParams();
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params,
            schemeRegistry);

    this.client = new DefaultHttpClient(cm, params);
}

AlarmReciever 的 onrecieve

public void onReceive(Context context, Intent intent) {
    try {
        TaskManager.getInstance().sendBatteryStatus();
         }
    } catch (Exception e) {
        Toast.makeText(
                context,
                "There was an error somewhere, but we still received an alarm",
                Toast.LENGTH_SHORT).show();
        e.printStackTrace();

    }

returnfromtask success 只是检查 id 的线程安全,处理文档并设置新的警报,如下所示:

 Calendar cal = Calendar.getInstance();
    cal.add(Calendar.SECOND, 30);
    Intent intent = new Intent(ctx, AlarmReceiver.class);

    PendingIntent sender = PendingIntent.getBroadcast(ctx, 2131225, intent,
            PendingIntent.FLAG_CANCEL_CURRENT);

    AlarmManager am = (AlarmManager) ctx
            .getSystemService(Context.ALARM_SERVICE);
    am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);

sendBatteryStatus 收集一些要发送的信息,并将其传递给扩展 GenericTask 的任务,它通常执行 new MyAsyncTask(..bla bla).execute();

【问题讨论】:

  • 你从哪里调用http客户端?一个活动? AsyncTask?其他后台线程?还有什么?
  • 在服务中创建的 AsyncTask 中调用它。
  • 这似乎不是您的问题,但症状听起来完全就像您不关闭 HttpEntity 时会发生的情况:stackoverflow.com/a/14088063

标签: android timeout httpclient wakelock


【解决方案1】:

一旦您释放唤醒锁,CPU 就可以进入睡眠状态,这很可能就是发生的情况。您多次使用HttpClient 执行操作,但在某个时间点,在释放唤醒锁后,CPU 进入休眠状态。

由于您想定期执行代码,您应该使用此处记录的AlarmManager 服务:http://developer.android.com/reference/android/app/AlarmManager.html。即使手机处于睡眠状态,警报管理器服务也处于活动状态。您可以通过AlarmManager.set*() 方法之一安排PendingIntent 来使用它。警报管理器将在接收器onReceive() 方法期间保持唤醒锁,但您很可能需要获取 WiFi 锁。

【讨论】:

  • 我在后台服务中同时获取了 wifilock(FULL_MODE) 和 wakelock(PARTIAL_AWAKE)锁定自己(是的,它以某种方式释放,他们说这是因为电源按钮)。但即使它没有工作,我只是在我的异步任务(负责单个帖子)开始时获得了 FULL_WAKE_LOCK 和 WIFI_MODE_FULL_HIGH_PERF 并在 onPostExecute 中释放它。过了一段时间(几个小时后),我的设备仍然可能卡在同一位置。您的关心。
  • 我的应用程序定期发送这些帖子,我也在使用alarmanager。睡眠事情不会发生在我的单个帖子之间,它恰好发生在 httpClient.execute(post)
  • 对不起,我以为你没有使用AlarmManager,因为你提到了唤醒锁但没有提到 AM。你所描述的很奇怪。您可以发布您的服务、ssyncTask、接收器和 UI 的实际代码吗?如果它是您的应用程序的一个最小片段仍然存在这个问题,那就太好了,即所谓的 SSCCE:sscce.org 没有这个,它只是在猜测......
  • 当我发布问题时,我没有使用警报管理器。我正在准备某种 sscce。
  • 好的。要尝试它,我需要:HttpUtils.postXml() 的来源,MyClient.client 是如何创建的,最后 - 您的 GenericTasks 是如何通过 AlarmManager 创建的。其余的对我没有兴趣,我可以嘲笑它。
猜你喜欢
  • 2018-08-21
  • 2016-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
相关资源
最近更新 更多