2

I'm designing my first Android app.

This app consist in several Runnable that do some stuff. Initially I made this Runnable to be execute by a Thread (a Thread for each Runnable). Each Runnable is also Observable, so it can notify changes to Activity. User click on a start button, one or more Runnable starts, them do their job notifying gui during execution and then stops. All works fine.

First question: Is that approach the right one? In order to answer this question please keep reading.

I need two other things in my app:

  1. to be sure that execution of my jobs doesn't stops, even if user goes away from my app to do something else;
  2. to plan the execution of my Runnable that has to start and execute in background. Example: user decides that wants a "job" to be execute everyday at 16:00.

I've seen that I can do that with an AlarmManager and Service.

Second question: I need a Service that can manage several Runnable asynchronously, so when AlarmManager starts I ask this Service to do the requested job; I'll also modify the first part of application: instead of Thread I'll use this Service, so I can be sure that execution doesn't stop. What kind of Service I need? IntentService can do this job? It's right to proceed in this way? There is a better solution?

Can you give me some example of how I can implement all that?

I hope that I explained clearly my situation, otherwise I'll try to do it better.

Regards

4

1 回答 1

0

第一个问题:这种方法正确吗?

不,您应该实现并运行您Runnable的 s in Threads in a Service

IntentService如果您不需要Service同时处理多个请求,那么An将是您的最佳选择。如果您启动 aService它会继续在后台运行,即使Activity启动它会进入后台或停止。

一个Runnables 可以发送一个广播,指示需要更新 UI。Activity应该注册一个来BroadcastReceiver收听广播消息并相应地更新 UI。

您可以使用 anAlarmManager来安排您所指示的作业的执行。一种方法是安排AlarmManager发送广播以由您接收,该广播IntentService 通过运行适当的作业对其进行操作。

这是一个结合所有这些的示例:

这里是IntentService

public class MyIntentService extends IntentService {
    public static final String ACTION_START_JOB = "com.mycompany.myapplication.START_JOB";
    public static final String ACTION_UPDATE_UI = "com.mycompany.myapplication.UPDATE_UI";

    private final IBinder mBinder = new MyBinder();

    // You can have as many Runnables as you want.
    Runnable run = new Runnable() {
        @Override
        public void run() {
            // Code to run in this Runnable.
            // If the code needs to notify an Activity
            // for a UI update, it will send a broadcast.
            Intent intent = new Intent(ACTION_UPDATE_UI);
            sendBroadcast(intent);
        }
    };

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    public void onCreate() {
        // You need to register your BroadcastReceiver to listen
        // to broadcasts made by the AlarmManager.
        // The BroadcastReceiver will fire up your jobs when these
        // broadcasts are received.
        IntentFilter filter = new IntentFilter(ACTION_START_JOB);
        registerReceiver(jobBroadcastReceiver, filter);
    }

    @Override
    public void onDestroy() {
        // You should unregister the BroadcastReceiver when
        // the Service is destroyed because it's not needed
        // any more.
        unregisterReceiver(jobBroadcastReceiver);
    }

    /**
     * This method is called every time you start this service from your
     * Activity. You can Spawn as many threads with Runnables as you want here.
     * Keep in mind that your system have limited resources though.
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        Intent intentFireUp = new Intent();
        intentFireUp.setAction(ACTION_START_JOB);
        PendingIntent pendingIntentFireUpRecording = PendingIntent
                .getBroadcast(MyIntentService.this, 0, intentFireUp, 0);

        AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

        Calendar cal = Calendar.getInstance();

        int year = 2013, month = 5, day = 10, hourOfDay = 7, minute = 13, second = 0;

        cal.set(year, month, day, hourOfDay, minute, second);
        long startTime = cal.getTimeInMillis() + 5 * 60 * 1000; // starts 5
                                                                // minutes from
                                                                // now
        long intervalMillis = 24 * 60 * 60 * 1000; // Repeat interval is 24
                                                    // hours (in milliseconds)

        // This alarm will send a broadcast with the ACTION_START_JOB action
        // daily
        // starting at the given date above.
        alarm.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalMillis,
                pendingIntentFireUpRecording);

        // Here we spawn one Thread with a Runnable.
        // You can spawn as many threads as you want.
        // Don't overload your system though.
        new Thread(run).run();
    }

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

    // Depending on your implementation, you may need to bind
    // to this Service to run one of its methods or access
    // some of its fields. In that case, you will need a Binder
    // like this one.
    public class MyBinder extends Binder {
        MyIntentService getService() {
            return MyIntentService.this;
        }
    }

    // Spawns a Thread with Runnable run when a broadcast message is received.
    // You may need different BroadcastReceivers that fire up different jobs.
    BroadcastReceiver jobBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            new Thread(run).run();
        }
    };

}

这是Activity

public class MyActivity extends Activity {
    Service mService;
    boolean mBound = false;
    ToggleButton mButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (ToggleButton) findViewById(R.id.recordStartStop);

        mButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (mButton.isChecked()) {
                    Intent intent = new Intent(MyActivity.this,
                            MyIntentService.class);
                    startService(intent);
                }
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter filter = new IntentFilter(MyIntentService.ACTION_UPDATE_UI);
        registerReceiver(uiUpdateBroadcastReceiver, filter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(uiUpdateBroadcastReceiver);
    }

    BroadcastReceiver uiUpdateBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // Here goes the code to update your User Interface
        }
    };

    ServiceConnection myServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
            mBound = false;
        }

        // If you need
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MyIntentService mService = ((MyBinder) service).getService();
            mBound = true;
        }
    };
}

并且不要忘记Service在文件中添加定义AndroidManifest.xml

<manifest ... >
  ...
  <application ... >
      <service android:name=".MyIntentService" />
      ...
  </application>
</manifest>
于 2013-03-27T03:59:38.643 回答