0

我是 Android 开发的新手,遇到了一个奇怪的问题:我需要构建一个应用程序来查看我的所有通话、消息和移动互联网流量,以跟踪消费情况。我为电话和消息设置了一个观察者,直到现在一切都完美无缺。我做了一个类来检索关于我的互联网流量的数据(不是观察者),我需要定期安排这个类,所以我这样做了:我在清单中注册了一个接收器,接收器类如下:

public class ServiceStarter extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("ServiceStarter.onReceive", "DetenctionService non attivo, lo lancio...");
        context.startService(new Intent(context, DetectionSevice.class));
    }
}

现在导致问题的类DetectionService:

public class DetectionSevice extends Service {
    @SuppressWarnings("unused")
    private static SQLiteDatabase dbInstance;

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

    @Override
    public void onCreate() {        
        super.onCreate();
        ContentResolver resolver = this.getApplicationContext().getContentResolver();
        TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        dbInstance = HabbleDB.getDBInstance(getApplicationContext());
        // The calls observer
        resolver.registerContentObserver(android.provider.CallLog.Calls.CONTENT_URI, true, new CallLogObserver(getContentResolver(), tm, getApplicationContext()));
        Log.i("DetectionService.onCreate", "Observer chiamate attivato");
        // The messages observer
        resolver.registerContentObserver(MessageLogObserver.uriConversation, true, new MessageLogObserver(resolver, tm, getApplicationContext()));
        Log.i("DetectionService.onCreate", "Observer messaggi attivato");
        //data intent for scheduling
        PendingIntent pi;
        AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        long nextDate;
        Intent saveData = new Intent(this, DataSaver.class);
        pi = PendingIntent.getService(this, 1234567, saveData, PendingIntent.FLAG_CANCEL_CURRENT);
        nextDate = System.currentTimeMillis() + DataSaver.DELAY;
        am.setRepeating(AlarmManager.RTC_WAKEUP, nextDate, DataSaver.DELAY, pi);
        Log.i("DetectionService.onCreate", "Scheduler per la raccolta dati attivato");
        SharedPreferenceManager.setLongPreference(this, SharedPreferenceManager.NEXT_DATA_SAVE, nextDate);
        //Sender data intent for scheduling
        Intent intent = new Intent(this, SelectAndSend.class);  
        pi = PendingIntent.getService(this, 1234578, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        nextDate = System.currentTimeMillis()+SelectAndSend.DELAY;
        am.setRepeating(AlarmManager.RTC_WAKEUP, nextDate, SelectAndSend.DELAY, pi);
        Log.i("DetectionService.onCreate", "Scheduler per l'invio dati registrato");
        SharedPreferenceManager.setLongPreference(this, SharedPreferenceManager.NEXT_SCHEDULE, nextDate);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return Service.START_STICKY;
    }
}

最后应该由调度程序启动的类:

public class DataSaver extends IntentService {
    private static final boolean tsSupported = (TrafficStats.getTotalRxBytes() == TrafficStats.UNSUPPORTED) ? false : true;
    private static final Format FORMATTER = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private TelephonyManager manager;
    private Context context = getApplicationContext();
    private long totalApps, total3g;
    private SparseArray<String> apps = new SparseArray<String>();
    private PowerManager.WakeLock wl;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    public static final int DELAY = 1 * 60 * 1000;

    public DataSaver() {
        super("DataSaverService");
        setIntentRedelivery(true);
    }

    @SuppressWarnings("deprecation")
    @Override
    public void onCreate() {
        super.onCreate();
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "DataSaverService");
        wl.acquire();
        initializeMinDataID();
        Log.i("DataSaver", "DataSaver created");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        run();
        long nextDate = System.currentTimeMillis() + DataSaver.DELAY;
        SharedPreferenceManager.setLongPreference(this, SharedPreferenceManager.NEXT_DATA_SAVE, nextDate);
        wl.release();
    }

    public void run() {
        mHandler.post(new Runnable() {
            public void run() {
                int i, uid;
                long base3g, baseApps;
                //Recupero gli UID solo delle app che effettivamente hanno generato traffico
                File dir = new File("/proc/uid_stat/");
                String[] children = dir.list();
                if (children != null) {
                    PackageManager pm = context.getPackageManager();
                    for (i = 0; i < children.length; i++) {
                        uid = Integer.parseInt(children[i]);
                        if ((uid >= 0 && uid < 2000) || (uid >= 10000)) {
                            apps.put(uid, pm.getNameForUid(uid));
                        }
                    }
                }
                baseApps = SharedPreferenceManager.getLongPreference(context, SharedPreferenceManager.LAST_APPS_DATA);
                base3g = SharedPreferenceManager.getLongPreference(context, SharedPreferenceManager.LAST_3G_DATA);
                totalApps = 0;
                total3g = 0;
                //Se TrafficStats è supportato
                if(tsSupported) {
                    total3g += TrafficStats.getMobileRxBytes() + TrafficStats.getMobileTxBytes();
                    if(total3g < base3g) {
                        Log.e("DataSaver.run", "total3g è minore di base3g!");
                        SharedPreferenceManager.setLongPreference(context, SharedPreferenceManager.LAST_3G_DATA, total3g);
                        return;
                    }
                    if(apps.size() > 0) {
                        for(i = 0; i < apps.size(); i++) {
                            totalApps += TrafficStats.getUidRxBytes(apps.keyAt(i)) + TrafficStats.getUidTxBytes(apps.keyAt(i));
                        }
                    }
                    if(totalApps < baseApps) {
                        Log.e("DataLogObserver.saveDataInformation", "totalApps è minore di baseApps!");
                        SharedPreferenceManager.setLongPreference(context, SharedPreferenceManager.LAST_APPS_DATA, totalApps);
                        return;
                    }
                } else {//Se TrafficStats non è supportato
                    Toast toast = Toast.makeText(context, "Impossibile recuperare alcuni dati. Device non supportato.", Toast.LENGTH_SHORT);
                    toast.show();
                    Log.w("DataSaver.initializeMinDataID", "Il device non supporta TrafficStats!");
                    return;
                }
                Date savedTime = new Date();
                DataBean bean = new DataBean();
                String mcc = manager.getNetworkOperator().substring(0, 3);
                String mnc = manager.getNetworkOperator().substring(3);
                AppDataBean appBean;
                bean.serial = manager.getSubscriberId();
                bean.mcc = mcc;
                bean.mnc = mnc;
                bean.total3gAmount = total3g - base3g;
                bean.from = FORMATTER.format(savedTime);
                if(apps.size() > 0) {
                    for(i = 0; i < apps.size(); i++) {
                        appBean = new AppDataBean();
                        appBean.uid = apps.keyAt(i);
                        appBean.name = apps.valueAt(i);
                        appBean.appAmount = TrafficStats.getUidRxBytes(appBean.uid) + TrafficStats.getUidTxBytes(appBean.uid);
                        appBean.from = FORMATTER.format(savedTime);
                        if(!HabbleDB.insertAppData(appBean)) Log.e("DataLogObserver.saveDataInformation", "Errore nell'inserimento dei dati per l'applicazione " + apps.valueAt(i));
                    }
                }
                if(HabbleDB.insertData(bean)) //se l'inserimento è andato a buon fine, aggiorno anche LAST_3G_DATA
                    SharedPreferenceManager.setLongPreference(context, SharedPreferenceManager.LAST_3G_DATA, total3g);
                else Log.e("DataLogObserver.saveDataInformation", "Errore nell'inserimento dei dati 3g");
            }
        });
    }

    private void initializeMinDataID() {
        totalApps = 0;
        total3g = 0;
        //Se TrafficStats è supportato
        if(tsSupported) {
            if(apps.size() > 0) {
                for(int i = 0; i < apps.size(); i++) {
                    totalApps += TrafficStats.getUidRxBytes(apps.keyAt(i)) + TrafficStats.getUidTxBytes(apps.keyAt(i));
                }
            }
            total3g += TrafficStats.getMobileRxBytes() + TrafficStats.getMobileTxBytes();
        } else {//Se TrafficStats non è supportato
            Toast toast = Toast.makeText(context, "Impossibile recuperare alcuni dati. Device non supportato.", Toast.LENGTH_SHORT);
            toast.show();
            Log.w("DataSaver.initializeMinDataID", "Il device non supporta TrafficStats!");
            return;
        }
        long min = SharedPreferenceManager.getLongPreference(context, SharedPreferenceManager.LAST_3G_DATA);
        if(min == 0 || min > total3g) SharedPreferenceManager.setLongPreference(context, SharedPreferenceManager.LAST_3G_DATA, total3g);
        min = SharedPreferenceManager.getLongPreference(context, SharedPreferenceManager.LAST_APPS_DATA);
        if(min == 0 || min > totalApps) SharedPreferenceManager.setLongPreference(context, SharedPreferenceManager.LAST_APPS_DATA, totalApps);
    }
}

当我启动应用程序时,两个观察者工作正常,但似乎只安排了数据发送器类 (SelectAndSend),DataSaver 类不会从应用程序启动开始记录任何内容,并且似乎它在应用程序中不存在.

有人可以帮我吗?

PS:对不起我的英语不好,我希望清楚。

[编辑 2013-05-27]:我尝试以这种方式修改 DetectionService.onCreate():

        ...
        PendingIntent pi, pi2;
        AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        AlarmManager am2 = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        long nextDate;

        ComponentName cn = new ComponentName(this, DataSaver.class);
        Intent saveData = new Intent().setClass(this, DataSaver.class).setComponent(cn);

        pi = PendingIntent.getService(this, 1234567, saveData, PendingIntent.FLAG_UPDATE_CURRENT);
        nextDate = System.currentTimeMillis() + DataSaver.DELAY;
        am.setInexactRepeating(AlarmManager.RTC_WAKEUP, nextDate, DataSaver.DELAY, pi);
        Log.i("DetectionService.onCreate", "Scheduler per la raccolta dati attivato");
        SharedPreferenceManager.setLongPreference(this, SharedPreferenceManager.NEXT_DATA_SAVE, nextDate);
        //aggiungo l'intent per l'invio dei dati all'alarm manager
        Intent intent = new Intent(this, SelectAndSend.class);  
        pi2 = PendingIntent.getService(this, 1234578, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        nextDate = System.currentTimeMillis() + SelectAndSend.DELAY;
        am2.setRepeating(AlarmManager.RTC_WAKEUP, nextDate, SelectAndSend.DELAY, pi2);
        Log.i("DetectionService.onCreate", "Scheduler per l'invio dati registrato");
        SharedPreferenceManager.setLongPreference(this, SharedPreferenceManager.NEXT_SCHEDULE, nextDate);

如您所见,我在 Intent 中强制使用 ComponentName 对象和指定的类,但我还没有响应。我真的需要帮助,我要疯了!!!

4

1 回答 1

0

我解决了将所有代码放在唯一开始的代码中。我添加了一个计数器,每 5 分钟运行一次课程。

顺便说一句,如果有人可以/愿意回答,我会很高兴。

谢谢

于 2013-05-28T07:47:27.553 回答