Я хочу начать новый поток в моей собственной службе, которая запускается из операции. В этой теме я хочу обновлять данные в базе данных каждые 3 секунды. Я создал базу данных и инициализировал ее в моем методе onStartCommand (). Где мне реализовать свою тему и как?

Я пробовал это, но это не сработало, приложение, к сожалению, будет закрыто. Без вызова этого метода все работает фин.

Я создаю этот метод, который я вызвал в своем onStartCommand

private void startThreadUpdatingDatabase(){
    Log.d("Database", "startThreadUpdatingDatabase(was called)");
    new Thread(new Runnable() { 
        public void run(){
            //do stuff
        }
    }).start();
}
1
d4rty 3 Дек 2014 в 01:47
Прочитайте чертову трассировку стека, если ваше приложение вылетает! А какой смысл тебе в треде нужен на самом деле?
 – 
Marcin Orlowski
3 Дек 2014 в 01:52
Нет необходимости в потоке для такой «недолгой» операции, вы пробовали обработчик?
 – 
pskink
3 Дек 2014 в 01:55
Пожалуйста, добавьте к вашему вопросу трассировку стека из logcat. Потоки прекрасно работают в Сервисах, и они действительно не заботятся друг о друге. Выполнение операций с базой данных — это не то, что вы должны делать в основном потоке, поэтому есть смысл делать это в потоке. Вы можете рассмотреть IntentService, который является службой, которая запускает для вас поток. Они не совсем хороши для 3-секундных повторяющихся задач, но работают.
 – 
zapl
3 Дек 2014 в 01:57
Не будьте такими суровыми людьми. Прочтите это руководство: developer.android.com/guide/components/…
 – 
Toguard
3 Дек 2014 в 01:58
Я новичок в разработке извините. В этом сервисе я добавляю прослушиватель для получения данных из машины. Это работает. В этих слушателях я вычисляю некоторую информацию из живых данных. И я ищу способ записать эту информацию в свою базу данных. Так что я могу прочитать эту рассчитанную информацию из действий.
 – 
d4rty
3 Дек 2014 в 01:59

2 ответа

Лучший ответ

Если вы хотите запустить повторяющуюся задачу, вы можете попробовать разные подходы:

1) Будильник
2) Хендлер
3) TimerTask (наименее любимый)

Будильник :

private AlarmManager mAlarmManager;
private static final long ALARM_INTERVAL = 3 * 60 * 1000;

private void issueAlarm() {
    if(mAlarmManager == null)
        mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Calendar calendar = Calendar.getInstance(Locale.US);
    calendar.add(Calendar.MILLISECOND, (int) ALARM_INTERVAL);
    Intent intent = new Intent(this, AlarmBroadcastReceiver.class);
    alarmIntent = PendingIntent.getBroadcast(this, ALARM_REQUEST_CODE, intent, 0);
    mAlarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), ALARM_INTERVAL, alarmIntent);
}

Создайте свой AlarmReceiver:

public class AlarmBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //Do DB Stuff here
    }

}

И не забудьте прописать в манифесте:

<receiver
    android:name=".AlarmBroadcastReceiver"
    android:exported="false" />

Обработчик :

@Override
public void onCreate() {
    // Start up the thread running the service.  Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block.  We also make it
    // background priority so CPU-intensive work will not disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
        Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

И поставьте свою опубликованную задачу в очередь

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //As danny117 pointed out, multiple clients starting the service
    //Can trigger this.
    mServiceHandler.removeCallbacks(yourRunnable);
    mServiceHandler.post(yourRunnable);
    return super.onStartCommand(intent, flags, startId);
}

Runnable должен выглядеть так:

private Runnable yourRunnable = new Runnable() {
        @Override
        public void run(){
        //DB work here
        if(mServiceHandler != null)
            mServiceHandler.postDelayed(this, ALARM_INTERVAL);
        }
}

Также убирайте после остановки обслуживания:

@Override
public void onDestroy() {
    super.onDestroy();
    mServiceHandler.removeCallbacks(yourRunnable);
    mServiceLooper.quit();
}

Таймер :

Создайте свой таймер:

private Timer myTimer = new Timer();

Создайте повторяющуюся задачу таймера:

private void scheduleTask() {
    myTimer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            //Do DB stuff here
        }
    }, 0, ALARM_INTERVAL);
}

Рекомендации:
Планирование повторяющихся сигналов тревоги
Создание службы

2
Toguard 3 Дек 2014 в 22:24
1
В приведенном выше коде вы можете получить несколько запусков, потому что onStartCommand может вызываться более одного раза. Решение для этого предостережения — handler.removeCallback(youRunnable), затем handler.post(youRunnable).
 – 
danny117
3 Дек 2014 в 06:01
Хорошее наблюдение, только что внес изменения.
 – 
Toguard
3 Дек 2014 в 22:25

Чтобы повторить с задержкой, вы создаете runnable, который вызывает postDelayed обработчика, чтобы перезапустить его по истечении заданного периода времени.

//change the notificationSmallIcon (titlebar) so it flashes every few seconds
private static Runnable iconWarnRunnable = new Runnable() {
    @Override
    public void run() {
        if (isWarningRunning) {
            long dely;
            if (notificationSmallIcon == R.drawable.ic_launcher2) {
                notificationSmallIcon = R.drawable.ic_launcher2x;
                dely = iconWarnDelay1;
            } else {
                notificationSmallIcon = R.drawable.ic_launcher2;
                dely = iconWarnDelay2;
            }
            notifyHandler.postDelayed(this, dely);
            myShowNotification();
        } else {
            //just in nick of time
            notificationSmallIcon = R.drawable.ic_launcher2;
        }
    }
};

final HandlerThread myThread = new HandlerThread("myHandlerThread");
private static long iconWarnDelay1;
private static long iconWarnDelay2;


@Override
public void onCreate() {
    iconWarnDelay1 = 2500;
    iconWarnDelay2 = 500;
    myThread.start();
    myThread.setPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
    notifyHandler = new Handler(myThread.getLooper());

... там, где вы запускаете runnable, очень важно, чтобы при запуске вы сначала удалили, чтобы у вас всегда был только один запуск.

isWarningRunning = true;
notifyHandler.removeCallbacks(iconWarnRunnable);
notifyHandler.postDelayed(iconWarnRunnable, iconWarnDelay1);

... где-нибудь остановите работающий

isWarningRunning = false;
notifyHandler.removeCallbacks(iconWarnRunnable);
0
danny117 3 Дек 2014 в 05:49