Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/182.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android:在活动上下文之外使用WebView_Android_Android Activity_Android Webview_Web Scraping_Intentservice - Fatal编程技术网

Android:在活动上下文之外使用WebView

Android:在活动上下文之外使用WebView,android,android-activity,android-webview,web-scraping,intentservice,Android,Android Activity,Android Webview,Web Scraping,Intentservice,我试图通过一个后台服务来实现网页抓取,该服务定期抓取一个网站,而用户的手机上没有显示视图 因为我必须在加载的页面上调用一些javascript,所以我不能使用任何HttpGet等 因此,我必须使用只能在UI线程上运行的WebView实例 任何使用网络视图启动活动的尝试都会导致进入手机前台的视图(根据Android的活动设计) 任何在活动上下文之外使用WebView的尝试都会导致错误,指出您无法在非UI线程上使用WebView LI>由于各种复杂性原因,我不能考虑使用诸如RHNO之类的库来减少

我试图通过一个后台服务来实现网页抓取,该服务定期抓取一个网站,而用户的手机上没有显示视图

  • 因为我必须在加载的页面上调用一些javascript,所以我不能使用任何HttpGet等
  • 因此,我必须使用只能在UI线程上运行的WebView实例
  • 任何使用网络视图启动活动的尝试都会导致进入手机前台的视图(根据Android的活动设计)
  • 任何在活动上下文之外使用WebView的尝试都会导致错误,指出您无法在非UI线程上使用WebView
  • <> LI>由于各种复杂性原因,我不能考虑使用诸如RHNO之类的库来减少UI的Web擦除。

有没有办法解决这个问题?

您可以从服务中显示Web视图。下面的代码创建了一个您的服务可以访问的窗口。窗口不可见,因为大小为0乘0

public class ServiceWithWebView extends Service {

    @Override
    public void onCreate() {
        super.onCreate();

        WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.TOP | Gravity.LEFT;
        params.x = 0;
        params.y = 0;
        params.width = 0;
        params.height = 0;

        LinearLayout view = new LinearLayout(this);
        view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));

        WebView wv = new WebView(this);
        wv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
        view.addView(wv);
        wv.loadUrl("http://google.com");

        windowManager.addView(view, params);
    }
}

此外,这还需要android.permission.SYSTEM\u ALERT\u窗口的
权限。

您可以使用此权限隐藏活动

         <activity android:name="MyActivity"
          android:label="@string/app_name"
          android:theme="@android:style/Theme.NoDisplay">

这样做将阻止应用程序显示任何活动。
然后你可以在活动中完成你的工作。

如果我错了,请纠正我,但这个问题的正确答案是,当用户在手机上做其他事情时,不可能在后台使用WebView而不通过活动中断用户

我应用了Randy和Code_瑜珈的建议:使用一个带有“Theme.NoDisplay”的活动来启动一个带有WebView的后台服务来做一些工作。但是,即使看不到任何视图,在启动服务的那一秒切换到该活动会中断用户(例如,暂停正在玩的正在运行的游戏)


这对我的应用程序来说简直是灾难性的消息,所以我仍然希望有人能给我一种方法,让我使用一个不需要活动(或可以实现同样功能的网络视图的替代品)的网络视图。

网络视图不能存在于活动或片段之外,因为它是一个UI。 但是,这意味着只需要一个活动来创建WebView,而不需要处理它的所有请求

如果您在主活动中创建了不可见的WebView,并且可以从静态上下文访问它,那么您应该能够从任何位置在后台的视图中执行任务,因为我相信WebView的所有IO都是异步完成的


为了消除这种全球访问的障碍,您可以随时启动一个引用WebView的服务来完成您需要的工作。

或者替代WebView来完成同样的工作我知道已经一年半了,但我现在面临着同样的问题。我最终通过在Android应用程序中运行的节点引擎中运行Javascript代码解决了这个问题。它叫。你可以看看。另外,看看这个不使用WebView运行Javascript的例子。我真的很想知道您最终使用了什么?

为什么不创建一个后端服务来为您执行抓取操作

然后您只需从RESTful Web服务轮询结果,甚至使用消息传递中间件(例如ZeroMQ)


如果它适合您的使用情况,可能会更优雅:让抓取服务通过GCM发送您的应用推送消息:)

解决方案是这样的,但有Looper.getMainLooper():


在@JonasCz的帮助下:

我使用了以下代码来解决这个问题:

Handler handler = new Handler(Looper.getMainLooper());
try
{
    handler.post(
        new Runnable()
        {
            @Override
            public void run()
            {
                ProcessRequest(); // Where this method runs the code you're needing
            }
        }
    );
} catch (Exception e)
{
    e.printStackTrace();
}

我不确定这是否是解决给定问题的灵丹妙药。 根据@Pierre接受的答案(我觉得正确)

当 用户在手机上做其他事情时不会打断用户 通过一项活动

因此,我认为必须进行一些架构/流程/策略更改才能解决这个问题

建议的解决方案#1:不要从服务器获取推送通知,而是运行后台作业,然后运行一些JS代码或WebView。相反,每当用户启动应用程序时,都应该查询后端服务器,以了解是否需要执行任何刮取操作。并且在后端输入的基础上,android客户端可以运行JS代码或WebView并将结果传回服务器

我还没有尝试过这个解决方案。但我希望这是可行的


这也将解决意见中所述的以下问题:


这是因为后端将被检测为来自同一IP的机器人抓取,并被阻止(除了在不同页面上进行大量抓取所需的后端资源)


数据可能在一段时间内不可用(直到某个用户为您刮取数据)。但是,使用此策略,我们当然可以为最终用户提供更好的用户体验。

不过,您仍然在ACTIVITY类onCreate方法中启动此服务。我无法在活动中执行代码,因为用户可以看到活动。在未继承Activity部分的类中创建WebView的新实例将导致运行时异常。我不确定是否理解您评论的第一部分。是的,您必须找到一种启动服务的方法,但这可能是一项简单地启动然后完成的活动。就WebView而言,我绝对知道这会起作用。此“onCreate()”方法来自服务本身。大约一周前我自己做过,从未经历过运行时异常。我猜您试图使用“onStartCommand()”函数,该函数可能会从其他线程调用。如果我在“活动”中启动该服务,则用户至少会在一小部分时间内看到某个屏幕,不是吗?它需要隐形。我已从IntentServ成功启动了您的带有WebView示例的服务
Handler handler = new Handler(Looper.getMainLooper());
try
{
    handler.post(
        new Runnable()
        {
            @Override
            public void run()
            {
                ProcessRequest(); // Where this method runs the code you're needing
            }
        }
    );
} catch (Exception e)
{
    e.printStackTrace();
}