我想在服务中创建一个具有3个线程的固定池的执行程序。
这3个线程将根据我的SQLite DB上的数据做一些工作。
有没有办法告诉线程“调用”服务上的某个方法,告诉他“线程已经完成,你现在可以从数据库中提取数据并启动一个新线程”
这样我可以操纵数据库,下一个线程也会相应地行动。
我所要做的就是用我在数据库上的所有数据填充队列,这样就不会对数据库中的更改做出反应,因为我已经提取了所有数据
编辑:一些代码以便更好地理解
public class MediaDownloadService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
executor = new ThreadPoolExecutor(2,3,3000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
//initiale start of new threads (first run)
}
public void startNewThread(){
if(helper.requestsExists()){
Map<Integer,String> requestMap = helper.getRequestsToExcute(0);
Set<Integer> keySet = requestMap.keySet();
Iterator<Integer> iterator = keySet.iterator();
executor.submit(new MyThread(file, getApplicationContext(), iteratorNext), 1);
}else{
executor.shutdown();
this.stopSelf();
}
}
和线程本人:
public class MyThread implements Runnable {
private File _file;
private Context context;
private DBHelper helper;
private int requestId;
public MyThread(File file, Context context, int requestId) {
this._file = file;
this.context = context;
this.requestId = requestId;
}
@Override
public void run() {
// Thread work here
helper.deleteRequest(requestId);// remove from db to prevent infinite loop
// THIS IS THE QUESTION
MediaDownloadService.startNewThread();// ??? can it be done
} catch (IOException e) {
Log.e("Callable try", post.toString());
}
}
当然我不希望它是静态的,还有其他方法吗?
答案 0 :(得分:0)
我认为您在此处有一些误解:Executor.submit()
不接受Thread
,而是Runnable
。它会将Runnable
放入队列中,并且可能(在一段时间后)分配一个线程来执行该runnable指定的操作。存在整个执行程序,因此您不必自己进行线程创建,管理和任务调度。
ThreadPoolExecutor
因此已经实现了您尝试实现的排队功能。因此,一个解决方案是在执行器进入时简单地将所有任务提交给执行程序。执行程序将对它们进行排队并将它们安排到可用的线程。
另请注意,AsyncTask.execureOnExecutor()
还允许您在主线程上运行onPostExecute()
。
请将MyThread
和startNewThread()
重命名为其他内容。前者不是一个线程,而只是一个任务,后者只向执行者提交工作。
答案 1 :(得分:0)
经过一番研究后,我设法找到了解决方案:
首先,我学会了如何通过这里绑定服务与IBinder: here
所以我的服务现在看起来像这样:
public class MediaDownloadService extends Service {
private DBHelper helper;
private ExecutorService executor;
private final IBinder sharonsBinder = new MyLocalBinder();
File file;
@Override
public IBinder onBind(Intent intent) {
return sharonsBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
helper = new DBHelper(getApplicationContext());
executor = new ThreadPoolExecutor(2,3,3000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
Log.e("requestsExists", helper.requestsExists() + "");
if(helper.requestsExists()){
// map of the index of the request and the string of the absolute path of the request
Map<Integer,String> requestMap = helper.getRequestsToExcute(3);
Set<Integer> keySet = requestMap.keySet();
Iterator<Integer> iterator = keySet.iterator();
Log.e("MAP",requestMap.toString());
//checks if the DB requests exists
if(!requestMap.isEmpty()){
//execute them and delete the DB entry
while(iterator.hasNext()){
int iteratorNext = iterator.next();
Log.e("ITREATOR", iteratorNext + "");
file = new File(requestMap.get(iteratorNext));
Log.e("file", file.toString());
Log.e("thread Opened", "Thread"+iteratorNext);
executor.submit(new MyTask(file, getApplicationContext(), iteratorNext), 1);
helper.requestTaken(iteratorNext);
}
}
}
return START_STICKY;
}
public void startNewTask(){
if(helper.requestsExists()){
Map<Integer,String> requestMap = helper.getRequestsToExcute(1);
Set<Integer> keySet = requestMap.keySet();
Iterator<Integer> iterator = keySet.iterator();
while(iterator.hasNext()){
int iteratorNext = iterator.next();
file = new File(requestMap.get(iteratorNext));
Log.e("file", file.toString());
Log.e("thread Opened", "Thread"+iteratorNext);
executor.submit(new MyTask(file, getApplicationContext(), iteratorNext), 1);
helper.requestTaken(iteratorNext);
}
}else{
executor.shutdown();
this.stopSelf();
}
}
public class MyLocalBinder extends Binder{
MediaDownloadService getService(){
return MediaDownloadService.this;
}
}
现在我将我的任务绑定到服务,以便能够像这样调用startNewTask()方法:
public class MyTask implements Runnable {
private File _file;
private Context context;
private DBHelper helper;
private int requestId;
private MediaDownloadService sharonsService;
boolean isBound = false;
public MyTask(File file, Context context, int requestId) {
this._file = file;
this.context = context;
this.requestId = requestId;
}
@Override
public void run() {
Intent intent = new Intent(context,MediaDownloadService.class);
context.bindService(intent,sharonsConnection,Context.BIND_AUTO_CREATE);
// some work here
sharonsService.startNewTask();
} catch (IOException e) {
Log.e("Callable try", post.toString());
}
}
private ServiceConnection sharonsConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
MyLocalBinder binder = (MyLocalBinder) service;
sharonsService = binder.getService();
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
isBound = false;
}
};
工作正常,线程仅在任务完成时打开
希望它能帮助有同样问题的人。