Thread 在服务中启动线程创建
Thread to initiate thread creation in a service
我想在服务中创建一个带有 3 个线程的固定池的执行器。
这 3 个线程将根据我的 SQLite 数据库中的数据做一些工作。
有没有办法告诉线程"call"服务上的一些方法会告诉他,"a thread is done, you can now pull the data from the DB and start a new thread"
这样我就可以操作数据库,下一个线程将相应地进行操作。
我所要做的就是用我数据库中的所有数据填充队列,这样它就不会对数据库中的更改做出反应,因为我已经提取了所有数据
编辑:一些代码可以更好地理解
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());
}
}
我当然不希望它是静态的,还有其他方法吗?
我认为您在这里有一些误解:Executor.submit()
不接受 Thread
,而是接受 Runnable
。它会将 Runnable
放入队列中,并可能(在一段时间后)分配一个线程来执行该可运行对象指定的操作。整个执行器的存在,让你不必自己做线程的创建、管理和任务调度。
ThreadPoolExecutor
因此已经实现了您正在尝试实现的排队功能。因此,一种解决方案是在所有任务进入时将所有任务简单地提交给执行器。执行器将它们排队并将它们调度到可用线程。
还要注意 AsyncTask.execureOnExecutor()
这也让你有可能在主线程上有 onPostExecute()
运行。
请将 MyThread
和 startNewThread()
重命名为其他名称。前者不是线程,只是任务,后者只是向执行者提交工作。
经过一番研究,我设法找到了解决方案:
首先我通过这里学习了如何使用IBinder绑定服务:
https://www.youtube.com/watch?v=0c4jRCm353c
所以我的服务现在看起来像这样:
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;
}
};
工作正常,只有在任务完成时才打开线程
希望对遇到同样问题的人有所帮助。
我想在服务中创建一个带有 3 个线程的固定池的执行器。
这 3 个线程将根据我的 SQLite 数据库中的数据做一些工作。
有没有办法告诉线程"call"服务上的一些方法会告诉他,"a thread is done, you can now pull the data from the DB and start a new thread"
这样我就可以操作数据库,下一个线程将相应地进行操作。
我所要做的就是用我数据库中的所有数据填充队列,这样它就不会对数据库中的更改做出反应,因为我已经提取了所有数据
编辑:一些代码可以更好地理解
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());
}
}
我当然不希望它是静态的,还有其他方法吗?
我认为您在这里有一些误解:Executor.submit()
不接受 Thread
,而是接受 Runnable
。它会将 Runnable
放入队列中,并可能(在一段时间后)分配一个线程来执行该可运行对象指定的操作。整个执行器的存在,让你不必自己做线程的创建、管理和任务调度。
ThreadPoolExecutor
因此已经实现了您正在尝试实现的排队功能。因此,一种解决方案是在所有任务进入时将所有任务简单地提交给执行器。执行器将它们排队并将它们调度到可用线程。
还要注意 AsyncTask.execureOnExecutor()
这也让你有可能在主线程上有 onPostExecute()
运行。
请将 MyThread
和 startNewThread()
重命名为其他名称。前者不是线程,只是任务,后者只是向执行者提交工作。
经过一番研究,我设法找到了解决方案:
首先我通过这里学习了如何使用IBinder绑定服务: https://www.youtube.com/watch?v=0c4jRCm353c
所以我的服务现在看起来像这样:
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;
}
};
工作正常,只有在任务完成时才打开线程
希望对遇到同样问题的人有所帮助。