【问题标题】:call AsyncTask from Broadcast receiver android从广播接收器android调用AsyncTask
【发布时间】:2014-02-13 02:05:46
【问题描述】:

所以目前我有一个 AsyncTask 类,当我单击一个按钮时,它运行并将数据 POST 到我的服务器(效果很好)。

我现在要做的是处理用户未连接到互联网时发生的事情。所以我设置了这些类来在互联网连接时通知应用程序,以便数据可以自动发送到服务器。

AsyncTask 类(内部类)

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

    ProgressDialog dialog = new ProgressDialog(getActivity());
    final AlertDialog finishedDialog = new AlertDialog.Builder(getActivity())
    .setCancelable(false)
    .setPositiveButton(android.R.string.ok, null)
    .create();



    @Override
    protected String doInBackground(String... urls) {
        onProgressUpdate("Uploading Data...");
        return POST(urls[0]);
    }

    @Override
    protected void onPreExecute() {
        this.dialog.show();
        finishedDialog.setOnShowListener(new DialogInterface.OnShowListener(){

            @Override
            public void onShow(DialogInterface dialog) {
                Button b = finishedDialog.getButton(AlertDialog.BUTTON_POSITIVE);
                b.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // navigate to match summary.....
                    finishedDialog.dismiss();
                }

            });
            }

        });
    }

    protected void onProgressUpdate(String msg) {
        dialog.setMessage(msg);

    }

    // onPostExecute displays the results of the AsyncTask.
    @Override
    protected void onPostExecute(String result) {
        if (result != ""){

            finishedDialog.setTitle("Upload Complete!");
            finishedDialog.setMessage("Data Sent Successfully");
            finishedDialog.show();
            dialog.dismiss();
            editor.clear();
            editor.commit();
            //Toast.makeText(getActivity().getBaseContext(), result, Toast.LENGTH_LONG).show();
        }else
        {
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                public void run() {
                    finishedDialog.setTitle("Upload Failed!");
                    finishedDialog.setMessage("Data Will Automatically Be Uploaded When Internet Connection Is Available");
                    finishedDialog.show();
                    dialog.dismiss();
                }}, 1000);

            setFlag(true);
        }
   }

}


public static boolean getFlag() {
    return flag;
}

public void setFlag(boolean flag) {
    this.flag = flag;
}


public String POST(String url){
    InputStream inputStream = null;
    String result = "";
    try {

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

        // 2. make POST request to the given URL
        HttpPost httpPost = new HttpPost(url);


        if(adapter.updateNeeded()){
            JSONObject main = new JSONObject(exmaplePrefs.getString("jsonString", "cant find json"));
            JSONObject dbUpdates = new JSONObject(exmaplePrefs.getString("ChangesJSON", "cant find Changejson"));
            main.put("Team_Updates", dbUpdates);
            json = main.toString();
        }else{
             json = exmaplePrefs.getString("jsonString", "cant find json");
             // String json = "{\"twitter\":\"test\",\"country\":\"test\",\"name\":\"test\"}";
        }




        // 5. set json to StringEntity
        StringEntity se = new StringEntity(json);
        se.setContentType("application/json;charset=UTF-8");

        // 6. set httpPost Entity
        httpPost.setEntity(se);

        // 7. Set some headers to inform server about the type of the content   
       // httpPost.setHeader("Accept", "application/json");
       // httpPost.setHeader("Content-type", "application/json");
       // httpPost.setHeader("json", json);


        // 8. Execute POST request to the given URL

        HttpResponse httpResponse = httpclient.execute(httpPost);

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

        String status = httpResponse.getStatusLine().toString();
        // 10. convert inputstream to string
        if (!status.equals("HTTP/1.1 500 Internal Server Error")){
            if(inputStream != null){
                result = convertInputStreamToString(inputStream);   
            }
            else{
                result = "Did not work!";
            }
        }else{
            System.out.println("500 Error");

        }



    } catch (Exception e) {
        Log.d("InputStream", e.getLocalizedMessage());
        System.out.println("eerroorr "+e);
    }

    // 11. return result
    System.out.println(result);
    return result;

}

private static 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;

}
}

NetworkUtil 类

  public class NetworkUtil {

public static int TYPE_WIFI = 1;
public static int TYPE_MOBILE = 2;
public static int TYPE_NOT_CONNECTED = 0;


public static int getConnectivityStatus(Context context) {
    ConnectivityManager cm = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    if (null != activeNetwork) {
        if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
            return TYPE_WIFI;

        if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
            return TYPE_MOBILE;
    }
    return TYPE_NOT_CONNECTED;
}

public static String getConnectivityStatusString(Context context) {
    int conn = NetworkUtil.getConnectivityStatus(context);
    String status = null;
    if (conn == NetworkUtil.TYPE_WIFI) {
        status = "Wifi enabled";
    } else if (conn == NetworkUtil.TYPE_MOBILE) {
        status = "Mobile data enabled";
    } else if (conn == NetworkUtil.TYPE_NOT_CONNECTED) {
        status = "Not connected to Internet";
    }
    return status;
}
}

BroadcastReceiver 类

public class NetworkChangeReceiver extends BroadcastReceiver {


@Override
public void onReceive(final Context context, final Intent intent) {
     intent.getExtras();
    String status = NetworkUtil.getConnectivityStatusString(context);

    Toast.makeText(context, status, Toast.LENGTH_LONG).show();

    if(MatchFragment.getFlag()){
        //send data
    }
}
}

所以在 BroadcastReceiver 类中,当应用程序尝试发送数据但没有互联网时,我检查设置为 true 的标志(AsyncTask 类中的 onPostExecute)。

所以想要做的是一些如何调用 POST 方法。我必须创建一个新的异步任务类吗?我在这里有点难过。

谢谢

【问题讨论】:

    标签: java android android-asynctask broadcastreceiver


    【解决方案1】:

    BroadcastReceiver 中使用AsyncTask 是一种不好的 做法。

    您应该使用Service,因为Android OS 可能会杀死您的进程,或者onReceive() 可能会在asyncTask 返回结果之前运行完成,因此无法保证您会得到预期的结果。

    【讨论】:

    • 同意,我正要这么说。
    • 好的,我能举个例子说明如何针对我的问题实施服务吗?
    • @QuokMoon,谢谢,为了清楚起见,我应该创建一个服务类,它将数据发布到服务器并在互联网可用时从广播接收器调用服务?这可能吗?
    • 这是不正确的,Android 文档没有说明使用 BroadcastReceivers 中的 AsyncTask 是一种不好的做法,事实上,它说这是一个有效的建议方案。
    【解决方案2】:

    您不应该在广播接收器中使用 AsyncTask,因为系统可以在从 onReceive 方法返回后终止您的进程(如果没有任何活动的服务或活动)。 Proof link

    官方文档recommendsIntentService 用于此类情况(请参阅有关广​​播接收器的段落)。

    【讨论】:

    • 这是不正确的,Android 文档说调用 goAsync 和使用 AsyncTasks 是一种有效且建议的方案。
    【解决方案3】:

    其他答案不正确according to Google's documentation。广播接收器开发人员指南明确指出,如果您首先调用 goAsync() 并将状态报告给 AsyncTask 中的挂起结果,则可以使用 BroadcastReceivers 中的 AsyncTasks

    因此,您不应从广播接收器启动长时间运行的后台线程。在 onReceive() 之后,系统可以随时终止进程以回收内存,并在此过程中终止进程中运行的衍生线程。 为避免这种情况,您应该调用 goAsync()(如果您想要更多时间在后台线程中处理广播) 或使用 JobScheduler 从接收器调度 JobService,以便系统知道该过程继续执行主动工作。

    稍后它会澄清您实际获得了多少时间:

    在接收者的 onReceive() 方法中调用 goAsync() 并传递 BroadcastReceiver.PendingResult 到后台线程。这保持 从 onReceive() 返回后激活的广播。然而,即使 使用这种方法,系统希望您完成广播 非常快(不到 10 秒)。它确实允许您将工作转移到 另一个线程以避免主线程出现故障。

    public class MyBroadcastReceiver extends BroadcastReceiver {
        private static final String TAG = "MyBroadcastReceiver";
    
        @Override
        public void onReceive(final Context context, final Intent intent) {
            final PendingResult pendingResult = goAsync();
            AsyncTask<String, Integer, String> asyncTask = new AsyncTask<String, Integer, String>() {
                @Override
                protected String doInBackground(String... params) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("Action: " + intent.getAction() + "\n");
                    sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
                    Log.d(TAG, log);
                    // Must call finish() so the BroadcastReceiver can be recycled.
                    pendingResult.finish();
                    return data;
                }
            };
            asyncTask.execute();
        }
    }
    

    【讨论】:

    • Google 在这方面的示例太糟糕了。 data 未定义,整个异步任务签名无法解释,最好:如果您收到来自 LocalBroadcastManager 的意图,goAsync 有时可能会导致异步后台执行崩溃。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多