异步任务未在更新 Android 小部件上完成

asynctask not completeing onUpdate Android Widget

大家早上好, 试图让小部件上的 onclick 事件起作用,问题是后台异步任务在设置挂起意图的 onUpdate 函数之前没有完成。我对android有点熟悉,但肯定还在学习阶段。我在实际 activity 中进行的测试运行良好且正确,观察日志何时进入绝对是一个时间问题。任何帮助将不胜感激!!

public class SingleClickWanIP extends AppWidgetProvider {
private static final String TAG = "waninfo";

private String myURL;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    // There may be multiple widgets active, so update all of them
    Log.d(TAG,"started update: " + myURL);
    WifiManager wifiManager = (WifiManager)  context.getSystemService(WIFI_SERVICE);
    WifiInfo wifiInfo = wifiManager.getConnectionInfo();
    String ssid = wifiInfo.getSSID();
    String homessid = "\"MyRouterName\"";

    if (ssid.equalsIgnoreCase(homessid)){
        myURL = "192.168.1.106";
    }
    Log.d(TAG,"finished ssd check: " + myURL);
    String newURL = "http://"+myURL+":120";
    Uri uri = Uri.parse(newURL);
    Intent intent = new Intent(Intent.ACTION_VIEW, uri);

    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.single_click_wan_ip);
    Log.d(TAG,"finished intent and remote views: " + myURL);
    views.setOnClickPendingIntent(R.id.ibOrange, pendingIntent);
    Log.d(TAG,"finished on click pending: " + myURL);

    final int N = appWidgetIds.length;
    for (int i = 0; i < N; i++) {
        updateAppWidget(context, appWidgetManager, appWidgetIds[i]);
    }
    Log.d(TAG,"finished onUpdate: " + myURL);
}



@Override
public void onEnabled(Context context) {
    ProcessURL process = new ProcessURL();
    process.execute("https://www.dropbox.com/link to get external ip value/wanip.txt?raw=1");
    Log.d(TAG,"started process: " + myURL);

}

private class ProcessURL extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... params) {
        Log.d(TAG,"started background");
        return GET(params[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        myURL = result;
        Log.d(TAG,"finished and set myURL variable: " + myURL);
    }



    private  String GET(String url){
        InputStream inputStream = null;
        String result = "";
        try {

            // create HttpClient
            HttpClient httpclient = new DefaultHttpClient();

            // make GET request to the given URL
            HttpResponse httpResponse = httpclient.execute(new HttpGet(url));

            // receive response as inputStream
            inputStream = httpResponse.getEntity().getContent();

            // convert inputstream to string
            if(inputStream != null)
                result = convertInputStreamToString(inputStream);
            else
                result = "Did not work!";

        } catch (Exception e) {
            Log.d(TAG, e.getLocalizedMessage());
        }

        return result;
    }

    private String convertInputStreamToString(InputStream inputStream) throws IOException {
        BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream));
        String line = "";
        String result = "";
        while((line = bufferedReader.readLine()) != null)
            result += line;

        inputStream.close();
        return result;

    }
}

一点背景,我很便宜,不想为 no-ip 或类似的东西付费。但我想与朋友和家人分享我的服务器访问权限,而不必告诉他们 "yeah, just type in xx.xx.xx.xxx:120 to get there"。所以服务器将外部 ip 写入我的 dropbox 文件,我有一个来自 dropbox 的共享 link,我在这个应用程序中使用它来获取值,然后打开我的服务器站点。中提琴


编辑

...明白了!我摸索着发现 post 关于小部件自发切换的奇怪行为,它修复了 spontaneous widget。然后单击将不起作用,因为我必须使用 if 将代码包装在 onupdate 中,因为它不会创建一个未决的 uri 意图并将 null 作为 url 地址。所以...将挂起的 onclick 意图复制到 onpost 执行过程,现在我是地毯上的一个错误。

感谢您的指导,非常感谢!

onpost执行的内容:

            WifiManager wifiManager = (WifiManager) gContext.getSystemService(WIFI_SERVICE);
            WifiInfo wifiInfo = wifiManager.getConnectionInfo();
            String ssid = wifiInfo.getSSID();
            String homessid = "\"MyRouterName\"";

            if (ssid.equalsIgnoreCase(homessid)) {
                result = "192.168.1.106";
            }
            Log.d(TAG, "finished ssd check: " + result);
            myURL = "http://" + result + ":8080";

            Uri uri = Uri.parse(myURL);
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);

            PendingIntent pendingIntent = PendingIntent.getActivity(gContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
            RemoteViews views = new RemoteViews(gContext.getPackageName(), R.layout.single_click_wan_ip);
            Log.d(TAG, "finished intent and remote views: " + myURL);
            views.setOnClickPendingIntent(R.id.ibOrange, pendingIntent);
            Log.d(TAG, "finished on click pending: " + myURL);

            ComponentName thisWidget = new ComponentName(gContext, SingleClickWanIP.class);
            gappWidgetManager.updateAppWidget(thisWidget, views);

            Log.d(TAG,"finished and set myURL variable: " + myURL);

我会请求在异步任务的 onPostExecute 上更新小部件,因为那时您拥有 URL 并且您现在可以正确设置挂起的意图。

使用带有操作 AppWidgetManager.ACTION_APPWIDGET_UPDATE 的意图来请求小部件更新。

在您的情况下,从 IntentService 更新小部件比从您的应用程序小部件提供商启动的 AsyncTask 更新小部件要安全得多。

onEnabledonUpdate 应该在(最多)10 秒内完成。

我强烈建议您使用以下代码:

SingleClickWanIP.java

public class SingleClickWanIP extends AppWidgetProvider
{
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    {
        context.startService(new Intent(context, ProcessURL.class));
    }

    @Override
    public void onEnabled(Context context)
    {
        context.startService(new Intent(context, ProcessURL.class));
    }
}

ProcessURL.java

public class ProcessURL extends IntentService
{
    private static final String TAG = "waninfo";
    private String myURL;

    public ProcessURL()
    {
        super("ProcessURL__service");
        setIntentRedelivery(true);
    }

    @Override
    protected void onHandleIntent(Intent intent__)
    {
        myURL = GET("https://www.dropbox.com/link to get external ip value/wanip.txt?raw=1");
        Log.d(TAG,"finished and set myURL variable: " + myURL);

        WifiManager wifiManager = (WifiManager)  getSystemService(Context.WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        String ssid = wifiInfo.getSSID();
        String homessid = "\"MyRouterName\"";

        if (ssid.equalsIgnoreCase(homessid))
        {
            myURL = "192.168.1.106";
        }
        Log.d(TAG,"finished ssd check: " + myURL);
        myURL = "http://"+myURL+":120";
        Uri uri = Uri.parse(myURL);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        RemoteViews views = new RemoteViews(getPackageName(), R.layout.single_click_wan_ip);
        Log.d(TAG,"finished intent and remote views: " + myURL);
        views.setOnClickPendingIntent(R.id.ibOrange, pendingIntent);
        Log.d(TAG,"finished on click pending: " + myURL);


        // Update all widgets

        AppWidgetManager manager = AppWidgetManager.getInstance(this);
        if(null != manager)
        {
            Log.d(TAG,"Updating all widgets...");
            manager.updateAppWidget(new ComponentName(this,SingleClickWanIP.class), views);
            Log.d(TAG,"finished and set myURL variable: " + myURL);
        }
    }

    private  String GET(String url)
    {
        InputStream inputStream = null;
        String result = "";
        try
        {
            // create HttpClient
            HttpClient httpclient = new DefaultHttpClient();

            // make GET request to the given URL
            HttpResponse httpResponse = httpclient.execute(new HttpGet(url));

            // receive response as inputStream
            inputStream = httpResponse.getEntity().getContent();

            // convert inputstream to string
            if(inputStream != null)
                result = convertInputStreamToString(inputStream);
            else
                result = "Did not work!";
        }
        catch (Exception e)
        {
            Log.d(TAG, e.getLocalizedMessage());
        }
        return result;
    }

    private String convertInputStreamToString(InputStream inputStream) throws IOException
    {
        BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream));
        String line = "";
        String result = "";
        while((line = bufferedReader.readLine()) != null)
            result += line;

        inputStream.close();
        return result;
    }
}

并在 AndroidManifest.xml 文件的 <application /> 标记中添加以下行:

<service android:name="[ADD-THE-PATH-TO-ProcessURL.java-HERE].ProcessURL" android:enabled="true" android:exported="false" />