【问题标题】:Google Analytics - NetworkOnMainThreadException on send in AsyncTaskGoogle Analytics - 在 AsyncTask 中发送 NetworkOnMainThreadException
【发布时间】:2015-03-13 22:19:49
【问题描述】:

我必须在我正在开发的应用程序中实施 Google Analytics。我正在使用 Android Studio。

我还不太确定是否应该从每个 Activity 实现发送跟踪器,或者是否在 Application class 中执行一次就足够了,但那是另一回事了。目前,Google Analytics 在Application class 中实施。它尝试连接到某些东西(尽管我设置了dryRun),但失败了,然后什么也没说,除非我导致我的应用程序崩溃。然后我在尝试调度事件时收到NetworkOnMainThreadException 错误。

它在dryRun 上尝试在哪里分派事件,导致NetworkOnMainThreadException 不少于?它不应该在dryRun 上将所有内容发送到 Logcat 吗?我应该如何处理dryRun 而不是?

一开始我试着像那样实现它,没有额外的AsyncTask 类,假设我会把所有东西都转储到Logcat,但是当我第一次得到NetworkOnMainThreadException 错误时,我实现了@ 987654334@班级。

LogCat:

01-15 13:06:21.835    1787-1800/com.example.app W/GAV4﹕ Thread[GAThread,5,main]: Service unavailable (code=1), will retry.
01-15 13:06:26.847    1787-1808/com.example.app W/GAV4﹕ Thread[Service Reconnect,5,main]: Service unavailable (code=1), using local store.
01-15 13:07:12.695    1787-1787/com.example.app E/GAV4﹕ Thread[main,5,main]: Error dispatching all events on exit, giving up: android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
        at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:926)
        at org.apache.http.impl.SocketHttpClientConnection.shutdown(SocketHttpClientConnection.java:183)
        at org.apache.http.impl.conn.DefaultClientConnection.shutdown(DefaultClientConnection.java:150)
        at org.apache.http.impl.conn.AbstractPooledConnAdapter.shutdown(AbstractPooledConnAdapter.java:169)
        at org.apache.http.impl.conn.AbstractClientConnAdapter.abortConnection(AbstractClientConnAdapter.java:378)
        at org.apache.http.impl.client.DefaultRequestDirector.abortConnection(DefaultRequestDirector.java:1031)
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:530)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:509)
        at com.google.android.gms.analytics.h.a(Unknown Source)
        at com.google.android.gms.analytics.h.a(Unknown Source)
        at com.google.android.gms.analytics.ag.dispatch(Unknown Source)
        at com.google.android.gms.analytics.w.eD(Unknown Source)
        at com.google.android.gms.analytics.w.dispatch(Unknown Source)
        at com.google.android.gms.analytics.x$b.run(Unknown Source)
        at com.google.android.gms.analytics.x.dY(Unknown Source)
        at com.google.android.gms.analytics.GoogleAnalytics.dY(Unknown Source)
        at com.google.android.gms.analytics.ExceptionReporter.uncaughtException(Unknown Source)
        at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
        at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
        at dalvik.system.NativeStart.main(Native Method)

应用类(相关部分):

public class App extends Application {

private static App context = null;

private static final String PROPERTY_ID = "UA-xxxxxxxx-1";

private GoogleAnalytics analytics;

private Tracker t;

public void onCreate() {
    super.onCreate();
    if (context == null)
        context = (App) getApplicationContext();
    try {
        analytics = GoogleAnalytics.getInstance(context);
        t = analytics.newTracker(R.xml.app_tracker);
        new SendTrackerInBg(t);
    }
    catch (Exception e) {e.printStackTrace();}


}

SendTrackerInBg:

public class SendTrackerInBg extends AsyncTask<Tracker, Void, Integer> {

    SendTrackerInBg(Tracker t)
    {
        this.execute(t);
    }

    @Override
    protected Integer doInBackground(Tracker... trackers) {
        try {
            trackers[0].send(new HitBuilders.AppViewBuilder().build());
            return 0;
        }
        catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }
}

app_tracker.xml(相关部分):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="ga_sessionTimeout">300</integer>

    <!-- Enable automatic Activity measurement -->
    <bool name="ga_autoActivityTracking">true</bool>

    <!-- The screen names that will appear in reports -->
    <screenName name="com.example.app.App">
        Application
    </screenName>
    <string name="ga_sampleFrequency">300.0</string>
    <string name="ga_trackingId">UA-xxxxxxxx-1</string>
    <bool name="ga_reportUncaughtExceptions">true</bool>
</resources>

analytics_global_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="ga_dryRun">true</bool>
    <string name="ga_logLevel">verbose</string>
</resources>

清单(相关部分):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app"
android:versionCode="00"
android:versionName="0.00" >

<uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="19" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />

<permission
    android:name="com.example.app.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />

<uses-permission android:name="com.example.app.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

<meta-data
    android:name="com.google.android.gms.analytics.globalConfigResource"
    android:resource="@xml/analytics_global_config" />

<application
    android:name=".App"
    android:allowBackup="true"
    android:hardwareAccelerated="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

UPD:感谢@Bart Hofma,我意识到我可能对我的应用程序崩溃感到困惑。当 GA 尝试调度事件时,我的应用程序不会崩溃。相反,GA 仅在我的应用程序崩溃时才尝试调度事件,否则它会保持沉默。我故意让我的应用程序崩溃,看看 GA 会说什么。我有一个自定义视频播放器,它在真实设备上运行良好,但在虚拟机上崩溃,所以当我希望我的应用崩溃时,我只需转到虚拟机上的播放器活动。

【问题讨论】:

  • 我不知道什么是dryrun,但您似乎只是在主类中建立网络连接。所以我猜你忘了从那里移动一些代码,或者错误地实现了异步任务。尽管您的问题不包括 Main 的代码,但也没有在清单中指定(删除它以提高可读性?)我认为您应该在问题中包含您的主要活动
  • @BartHofma "SDK 提供了一个 dryRun 标志,设置后会阻止任何数据发送到 Google Analytics。当您在测试或调试实现并且不想测试时,应该设置 dryRun 标志出现在您的 Google Analytics(分析)报告中的数据。” developers.google.com/analytics/devguides/collection/android/v3/… 我的 MainActivity 中没有建立任何网络连接。我什至还没有开始在那里实施谷歌分析,一旦我遇到第一个错误,我就从我的 StartActivity 中删除了所有关于 GA 的内容。 --
  • @BartHofma -- 我没有包括整个清单,因为我有 12 个活动和差不多一样多的片段,我认为这些只会使帖子混乱。但无论如何感谢您的意见。我可以添加我的 StartActivity(删除 url、令牌等),但那是 333 行不相关的代码。
  • 有人能解释一下投反对票的原因吗?
  • 你完全正确,只是遇到了同样的问题,是的,它似乎是由带有未捕获异常的空运行标志引起的 - 在我的情况下,遵循 ExceptionReporter.uncaughtException 我有我自己的布局通货膨胀例外。幸运的是,当不是试运行时,问题不会发生,因此为生产运行祈祷。不确定需要报告问题的确切位置,可能在这里:productforums.google.com/forum/#!categories/analytics/… 或这里code.google.com/p/analytics-issues/issues/list

标签: java android android-asynctask google-analytics android-studio


【解决方案1】:

您必须从线程调用谷歌分析。我在这里分享我正在使用的代码。

将此代码放在一个类中(MBGoogleAnalyticsManager.java)

 import android.content.Context;
 import com.google.android.gms.analytics.GoogleAnalytics;
 import com.google.android.gms.analytics.HitBuilders;
 import com.google.android.gms.analytics.Tracker;


public class MBGoogleAnalyticsManager  
{
    private static final String TAG = "MBGoogleAnalyticsManager";
    private static MBGoogleAnalyticsManager instance = null;
    public String PROPERTY_ID = "UA-28454545-2";

    private Context context;
    private Tracker dataTracker;

    public static MBGoogleAnalyticsManager getInstance(Context c) 
        {
            if(instance == null) 
                {
                    System.out.println("MBGoogleAnalyticsManager new instance is created");
                    instance = new MBGoogleAnalyticsManager(c);
                }
            else
                {
                    System.out.println("MBGoogleAnalyticsManager instance is already avaiable");
                }
            return instance;
        }

    private MBGoogleAnalyticsManager(Context c)     
        {
            //super(c);
            context = c;
            GoogleAnalytics analytics = GoogleAnalytics.getInstance(context);   
            dataTracker = analytics.newTracker(PROPERTY_ID);
        }




      //==============================================================================
     //========================== Send a screen view =================================
    //================================================================================
    public synchronized void sendGoogleAnalyticsSreenView(String screenName)
        {               
            dataTracker.setScreenName(screenName);    // Set screen name.
            //dataTracker.setAppName("MovieBuddy");  // We can send the application name [String](Optional)
            //dataTracker.setAppVersion("2.2");     // We can send the application version [String](Optional)
            //dataTracker.setLanguage("Eng");      // We can send the language [String](Optional)
            //dataTracker.setSessionTimeout(300); // We can set the time for the session time out [Long](Optional)

            dataTracker.send(new HitBuilders.AppViewBuilder()    
                                            //.setNewSession()   // If want to start a new session (Optional)
                                            .build());
            System.out.println("Screen: "+screenName);
        }



      //==============================================================================
     //========================== Send A Click Event Hit =============================
    //================================================================================
    public synchronized void sendGoogleAnalyticsHitEvents(String screenName,String category,String action,String label)
        {       
            dataTracker.setScreenName(screenName);
            dataTracker.send(new HitBuilders.EventBuilder()         
                                            .setCategory(category) // Set the category of the event [String]
                                            .setAction(action)    // Set the action has taken for the event [String]
                                            .setLabel(label)     // Set the label of for the event [String]
                                            .build());
            System.out.println("Hit Label: "+label);
        }



      //==============================================================================
     //========================== Send A Exception Event =============================
    //================================================================================

    public synchronized void sendGoogleAnalyticsException(String screenName,String ExceptionMethodName,String ExceptionLocation,boolean ExceptionFatal)
        {   
            dataTracker.setScreenName(screenName);
            dataTracker.send(new HitBuilders.ExceptionBuilder()                                         
                                            .setDescription(ExceptionMethodName + ":" + ExceptionLocation) // Send the exception details [String]
                                                                                                          //(Never send the e.message, as it contains personal info)
                                            .setFatal(ExceptionFatal)                                    // Send true or false if fatal exception error [boolean]
                                            .build());
        }



      //==============================================================================
     //================ Send A Social Event Interaction With target ==================
    //================================================================================
    public synchronized void sendGoogleAnalyticsSocialInteractionWithTarget(String screenName,String SocialNetworkName,String SocialAction,String SocialTarget)
        {       
            dataTracker.setScreenName(screenName);
            dataTracker.send(new HitBuilders.SocialBuilder()                 
                                            .setNetwork(SocialNetworkName)  // Set the Social Network Name [String]
                                            .setAction(SocialAction)       // Set the action [String]
                                            .setTarget(SocialTarget)      // Set the target [String](Not a mandatory field)
                                            .build());
            System.out.println("Target: "+SocialTarget);
        }




      //==============================================================================
     //============== Send A Social Event Interaction Without target =================
    //================================================================================

    public synchronized void sendGoogleAnalyticsSocialInteraction(String SocialNetworkName,String SocialAction)
        {       
            dataTracker.send(new HitBuilders.SocialBuilder()
                                            .setNetwork(SocialNetworkName)// Set the Social Network Name [String]
                                            .setAction(SocialAction)     // Set the action [String]
                                            .build());
        }
} 

现在你必须调用这个类的实例、方法并从你调用的类中提供所需的数据,如下所示:

private void sendScreenView(final String screenName)
    {   
        new Thread(new Runnable() 
            {
                @Override
                public void run() 
                    {                           
                        analyticsManager = MBGoogleAnalyticsManager.getInstance(getApplicationContext());
                        analyticsManager.sendGoogleAnalyticsSreenView(screenName);
                    }
            }).start();
    }

并调用此方法:

sendScreenView("家庭活动");

希望对您有所帮助。

【讨论】:

  • 请发布问题。如果您设置的是 GA 帐户,则最长可能需要 48 小时才能工作,并且您将在第二天获得特定日期的数据。
【解决方案2】:

我浪费了一天的时间来搜索解决方案(我有相同的线程转储行)并发布它与 Google Analytics 没有直接关系。根本原因是下一行:adView.destroy();其中 adView == null。似乎 Google Analytics 试图发送此异常并自行崩溃。 我是通过完全禁用 Google Analytics 找到的。

【讨论】:

  • 对我来说也一样,但我没有禁用 Analytics,而是在其块上使用了 try/catch。
  • 是的,我的意思是找到有问题的块,我必须禁用 Google Analytics 捕获异常。
猜你喜欢
  • 2012-11-16
  • 2015-01-01
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多