【问题标题】:Android service thread making web request is blocking UI发出 Web 请求的 Android 服务线程阻塞了 UI
【发布时间】:2012-01-03 16:56:17
【问题描述】:

首先我将解释当前的情况。 我在 2 个服务中有 2 个不同的线程(从 USB 端口服务读取并生成 Web 请求服务)。我在我的活动的 onCreate 中启动它们,例如:

serialServiceIntent = new Intent(NDKSerialActivity.this, SerialService.class);
startService(serialServiceIntent);
webServiceIntent = new Intent(NDKSerialActivity.this, RecordWebService.class);
startService(webServiceIntent);

串行服务没有任何问题,但在 RecordWebService 中,当我发出请求时,我的 gui 会停止,直到响应到来。

代码是这样的:

public class RecordWebService extends Service
{
public static final String SERVER_ADDRESS = "http://192.168.1.100:8080/MobilHM/rest";
private static final String TAG = RecordWebService.class.getSimpleName();
private RecordWebThread recordWebThread;

@Override
public void onStart(Intent intent, int startId)
{
    super.onStart(intent, startId);
    recordWebThread = new RecordWebThread(true);
    recordWebThread.start();
}

@Override
public void onDestroy()
{
    super.onDestroy();
    Log.i(TAG, "RecordWebService Destroyed");
}

@Override
public IBinder onBind(Intent intent)
{
    return null;
}
}

public class RecordWebThread extends Thread
{
private static final String TAG = RecordWebThread.class.getSimpleName();
public boolean always;


public RecordWebThread(boolean always)
{
    this.always = always;
}

@Override
public void run()
{
    PatientRecord patientRecord = new PatientRecord();
    while (always)
    {
        RestClient restClient = new RestClient(RecordWebService.SERVER_ADDRESS + "/hello");
        try
        {
            restClient.execute(RequestMethod.GET);
        }
        catch (Exception e1)
        {
            Log.e(TAG, "", e1);
        }
        Log.i(TAG, "Server Response Code:->" + restClient.getResponseCode());
        Log.i(TAG, "Server Response:->" + restClient.getResponse());
        try
        {
            sleep(4 * 1000);
        }
        catch (InterruptedException e)
        {
            Log.e(TAG, "Web service interrupted", e);
        }
    }
}
}

我还尝试删除睡眠部分并使用计时器和计时器任务使线程运行,例如:

public void sendRecord()
{
    scanTask = new TimerTask()
    {
        public void run()
        {
            handler.post(new Runnable()
            {
                public void run()
                {
                    RestClient restClient = new RestClient(RecordWebService.SERVER_ADDRESS + "/hello");
                    try
                    {
                        restClient.execute(RequestMethod.GET);
                    }
                    catch (Exception e1)
                    {
                        Log.e(TAG, "", e1);
                    }
                    Log.i(TAG, "Server Response Code:->" + restClient.getResponseCode());
                    Log.i(TAG, "Server Response:->" + restClient.getResponse());
                }
            });
        }
    };
    t.schedule(scanTask, 1000, 4000);
}

但运气不好,我的 gui 在涉及 restClient.execute 时挂起。

可以找到RestClient.java@http://www.giantflyingsaucer.com/blog/?p=1462

如何让我的请求不阻塞我的 gui 线程?

编辑:

public void sendRecord()
{
    scanTask = new TimerTask()
    {
        public void run()
        {
            RestClient restClient = new RestClient(RecordWebService.SERVER_ADDRESS + "/hello");
            try
            {
                restClient.execute(RequestMethod.GET);
            }
            catch (Exception e1)
            {
                Log.e(TAG, "", e1);
            }
            Log.i(TAG, "Server Response Code:->" + restClient.getResponseCode());
            Log.i(TAG, "Server Response:->" + restClient.getResponse());
        }
    };
    t.schedule(scanTask, 1000, 4000);
}

如果没有处理程序,我会在我的活动的 onCreate 中调用它,但 ui 仍然挂起。

【问题讨论】:

    标签: android multithreading user-interface web block


    【解决方案1】:

    或者您可以使用 IntentService 来为您处理线程问题。

    这是一个示例类:

    public class MyService extends IntentService {
    
        public MyService() {
            super("MyService");
        }
    
        public MyService(String name) {
            super(name);        
        }
    
        @Override
        protected void onHandleIntent(Intent arg0) {
    
                    //Do what you want
            }
    }
    

    然后你只需调用:

    Intent intent = new Intent(getApplicationContext(),MyService.class);
    startService(intent);
    

    编辑:

    要每 4 秒重复一次相同的事情,您应该这样做:

     PendingIntent serviceIntent= PendingIntent.getService(context,
                    0, new Intent(context, MyService.class), 0);
    
       long firstTime = SystemClock.elapsedRealtime();
       AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    
       long intervalInSec = 4;
    
       am.setRepeating(AlarmManager.ELAPSED_REALTIME, firstTime, intervalInSec*1000, serviceIntent)
    

    ;

    【讨论】:

    • 谢谢斯弗拉蒂尼。我的工作应该以 4 秒的间隔重复。我应该用计时器还是什么来调用 startService?
    • 我编辑了答案,以便您可以看到使用 AlarmManager 的示例
    • 非常感谢。正如你所说,我刚刚编辑了代码。尽管您的解决方案很有价值,但 ui 仍然悬而未决。我认为它可能更多地与 .execute(request) 相关,而不是服务、计时器等。我正在寻找像 actionscript 中的异步 http 请求。
    • 请按原样发布您的完整代码。您不需要在 handleIntent 中创建新线程。这一切都在另一个线程中完成。
    • 看起来阻塞部分是json。我正在使用 flexjson 将我的 PatientRecord 对象序列化为 json,但在 android 中它正在杀死我的应用程序。我现在正在使用 Kryo,它非常完美。感谢您的关注。它适用于两种方式,包括我的第一个实现和您的实现。
    【解决方案2】:

    在您的代码(2d 版本)中,接下来会发生:您创建线程,并要求 UI 线程进行一些网络交互。只需在执行请求时排除handler.post(...)。稍后您可以将其用于简单的可运行对象,以使用请求结果更新您的 UI。

    【讨论】:

    • 如果我理解正确,您可以在帖子中查看编辑。如果不是,请纠正我。
    猜你喜欢
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    相关资源
    最近更新 更多