针对如何在Android中使用IntentService同时下载多个文件?和android多个application这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展Android8.0以后使
针对如何在Android中使用IntentService同时下载多个文件?和android多个application这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展Android 8.0 以后使用后台 Service 服务 JobIntentService 的使用、Android IntentService的使用和源码分析、Android IntentService详解及使用实例、Android Oreo JobIntentService继续在Android 7及以下版本的后台运行,并且经常在Android 8及以上版本中崩溃等相关知识,希望可以帮助到你。
本文目录一览:- 如何在Android中使用IntentService同时下载多个文件?(android多个application)
- Android 8.0 以后使用后台 Service 服务 JobIntentService 的使用
- Android IntentService的使用和源码分析
- Android IntentService详解及使用实例
- Android Oreo JobIntentService继续在Android 7及以下版本的后台运行,并且经常在Android 8及以上版本中崩溃
如何在Android中使用IntentService同时下载多个文件?(android多个application)
我想创建一个与此服务类似的服务(从Here引用),以在Android中异步下载多个文件。
public static class DownloadingService extends IntentService {public static String PROGRESS_UPDATE_ACTION = DownloadingService.class .getName() + ".newDownloadTask";private ExecutorService mExec;private CompletionService<NoResultType> mEcs;private LocalBroadcastManager mBroadcastManager;private List<DownloadTask> mTasks;public DownloadingService() { super("DownloadingService"); mExec = Executors.newFixedThreadPool( 3 ); // The reason to use multiple thread is to download files asynchronously. mEcs = new ExecutorCompletionService<NoResultType>(mExec);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId);}@Overrideprotected void onHandleIntent(Intent intent) { while(true) { if( cursor <= totalDownloadQueue.size() -1) { //totalDownloadQueue is a static ArrayList which contains numerous DownloadTask mEcs.submit(totalDownloadQueue.get(cursor)); cursor++; // The variable cursor is also a static int variable. } }// continuously observing the totalDownloadQueue. If any download item is added. Then the thread are dispatched to handle that. mExec.shutdown();}
用户可以选择listview
不同片段中的下载项目。我的策略是,随着用户选择项目并按下下载按钮,这些项目将被传递到DownloadTask
其中,负责下载文件。然后将下载任务添加到中totalDownloadQueue
。
这里有一些问题:
- 我知道
intentservice
是由某些已定义的操作触发的。但是我想要创建一个后台服务,监视totalDownloadQueue
,如果downloadtask
有新消息可用,那么将调用一些线程来操作任务。
如果我对这个定制商品这样做有什么副作用intentservice
?
我应该使用什么替代类?请提供sample code
说明,谢谢。
据我所知,线程的初始化仅被调用一次。如果我在应用程序的开头启动服务,并且在用户终止应用程序时应该杀死线程。(我的意思是当他
swipe out
打开窗口时。)用户退出应用程序后线程是否存在?如果这种方法仍然不能解决有关异步下载文件的问题?我应该采取什么其他策略?请提供一些示例代码或参考,以便我对其进行修改。
我已经花了7天时间来处理复杂的要求,请帮忙!
答案1
小编典典在Android中异步下载多个文件。
而且我认为您想同时下载。
我想你误用了intentservice
。intentservice
有一个looper
和一个handler
,每个start调用都会为处理程序创建一条消息。所有邮件都在中排队,looperqueue
并且一次发送一次。
您应该使用常规服务,而不要使用,intentservice
因为您一次要同时下载而不是一次。扩展服务类,并在onCreate
方法中可以创建多个线程,每个线程可以从中获取消息onStartCommand
。我不想复制并粘贴该文档示例,因为我认为最好再次阅读所有文档。如果您阅读它,则可以完全理解如何创建同时处理多个任务的服务,尽管该示例中仅创建了一个线程。
http://developer.android.com/guide/components/services.html
我想要创建一个监视totalDownloadQueue的后台服务
我认为你不需要那个。仅当您创建downloadtask
呼叫服务时,您的信息message
就会传递到服务类,您可以在该类中通过创建blockingqueue
来处理消息threads
。
用户退出应用程序后,线程是否存在?
是的,也许不是。它取决于该过程,如果该过程存在则是,但是如果该过程已被破坏则否。再次阅读lifecycle
进程,以了解哪些进程被android杀死或保留。
http://developer.android.com/guide/components/processes-and-
threads.html
如果这种方法仍然不能解决有关异步下载文件的问题?我应该采取什么其他策略?请提供一些示例代码或参考,以便我对其进行修改。
您可以使用,downloadmanager
但会顺序下载。
http://developer.android.com/reference/android/app/DownloadManager.html
http://blog.vogella.com/2011/06/14/android-downloadmanager-
example/
Android 8.0 以后使用后台 Service 服务 JobIntentService 的使用
由于Android8.0以后不能使用后台服务,使用Service需要使用ContextCompat.startForegroundService启动前台服务,而且通知栏有Notification显示该Service正在运行,这可能会带来不好的用户体验。
如果还是希望使用服务在后台默默工作,通过使用服务开启子进程等等,可以使用JobIntentService。下面的具体的代码:
public class TestService extends JobIntentService {
private static final int JOB_ID = 1000;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, TestService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
// TODO:
}
}
<service
android:name=".service.TestService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" //重要1
/>
<uses-permission android:name="android.permission.WAKE_LOCK"/> //重要2
//@Override
//public IBinder onBind(@NonNull Intent intent) { //重要3,大坑,不能重写onBind方法,重写的话要返回super.onBind(),否则onHandleWork不会回调。
// return null;
//}
//重要4,重写onStartCommand方法时要返回super.onStartCommand()
Intent intent = new Intent(MainActivity.this,TestService.class);
intent.putExtra("key","value");
TestService.enqueueWork(MainActivity.this,intent);
Android IntentService的使用和源码分析
引言
Service服务是Android四大组件之一,在Android中有着举足重轻的作用。Service服务是工作的UI线程中,当你的应用需要下载一个文件或者播放音乐等长期处于后台工作而有没有UI界面的时候,你肯定要用到Service+Thread来实现。因此你需要自己在Service服务里面实现一个Thread工作线程来下载文件或者播放音乐。然而你每次都需要自己去写一个Service+Thread来处理长期处于后台而没有UI界面的任务,这样显得很麻烦,没必要每次都去构建一个Service+Thread框架处理长期处于后台的任务。Google工程师给我们构建了一个方便开发者使用的这么一个框架---IntentService。
IntentService简介
IntentService是一个基础类,用于处理Intent类型的异步任务请求。当客户端调用android.content.Context#startService(Intent)发送请求时,Service服务被启动,且在其内部构建一个工作线程来处理Intent请求。当工作线程执行结束,Service服务会自动停止。IntentService是一个抽象类,用户必须实现一个子类去继承它,且必须实现IntentService里面的抽象方法onHandleIntent来处理异步任务请求。
IntentServic示例
Client代码
public class ClientActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//客户端同时发送两个任务到IntentService服务端执行
public void send(View view) {
Intent intent = new Intent(this, DownLoadService.class);
intent.putExtra("key", 1);
intent.putExtra("value", "the first task1");
startService(intent);
Intent intent1 = new Intent(this, DownLoadService.class);
intent1.putExtra("key", 2);
intent1.putExtra("value", "the second task2");
startService(intent1);
}
}
模拟两个异步任务同时请求,通过Intent实例携带数据启动Service服务。
Service客户端
public class DownLoadService extends IntentService {
public static final String TAG = "DownLoadService";
//重写默认的构造方法
public DownLoadService() {
super("DownLoadService");
}
//在后台线程执行
@Override
protected void onHandleIntent(Intent intent) {
int key = intent.getIntExtra("key", 0);
String value = intent.getStringExtra("value");
switch (key) {
case 1:
//模拟耗时任务1
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case 2:
//模拟耗时任务1
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
default:
break;
}
Log.e(TAG, "\nthe current time is: " + System.currentTimeMillis()/1000
+ "\nthe Thread id is " + Thread.currentThread().getId()
+ "\nthe current task is " + value);
}
}
DownLoadService子类继承IntentService类,然后实现onHandleIntent抽象方法进行处理Intent请求的异步任务。在服务端DownLoadService类中,我们并没有创建Thread线程去执行异步耗时任务请求。所有的异步耗时任务都是在onHandleIntent抽象方法中实现了。言外之意是IntentService类内部已经帮开发者搭建好了一个异步任务处理器,用户只需实现其中的onHandleIntent抽象方法去处理异步任务即可,从而让开发者更加简单方便的使用IntentService处理后台异步任务请求。那么IntentService内部是怎么搭建异步任务处理器的呢?我们不妨查看源码来窥探个究竟。
IntentService源码分析
IntentService构造方法
/**
* Creates an IntentService. Invoked by your subclass''s constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
分析:该构造方法需在子类中调用,用于创建一个IntentService对象。参数name用于定义工作线程的名称,仅仅用于调式作用。我们知道Service服务的生命周期是从onCreate方法开始的。那么就来看看IntentService#onCreate方法吧。
IntentService#onCreate方法
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
分析:该方法首先利用HandlerThread类创建了一个循环的工作线程thread,然后将工作线程中的Looper对象作为参数来创建ServiceHandler消息执行者。由另一篇博客Android HandlerThread 源码分析可知,HandlerThread+Handler构建成了一个带有消息循环机制的异步任务处理机制。因此开发者就可以将异步任务封装成消息的形式发送到工作线程中去执行了。Service服务生命周期第二步执行IntentService#onStartCommand方法。
IntentService#onStartCommand方法
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
分析:在IntentService子类中你无需重写该方法。然后你需要重写onHandlerIntent方法,系统会在IntentService接受一个请求开始调用该方法。我们看到在该方法中仅仅是调用了onStart方法而已,跟踪代码:
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
分析:该方法中通过mServiceHandler获得一个消息对象msg,然后将startId作为该消息的消息码,将异步任务请求intent作为消息内容封装成一个消息msg发送到mServiceHandler消息执行者中去处理,那么我们来看看mServiceHandler的实现吧!
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
分析:实现也比较简单,ServiceHandler是IntentService的内部类,在重写消息处理方法handlerMessage里面调用了onHandlerIntent抽象方法去处理异步任务intent的请求,当异步任务请求结束之后,调用stopSelf方法自动结束IntentService服务。看过博客Android HandlerThread 源码分析的人都应该知道,此处handleMessage方法是在工作线程中调用的,因此我们子类重写的onHandlerIntent也是在工作线程中实现的。我们来看看onHandlerIntent方法:
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
*/
protected abstract void onHandleIntent(Intent intent);
分析:该方法用于处理intent异步任务请求,在工作线程中调用该方法。每一个时刻只能处理一个intent请求,当同时又多个intent请求时,也就是客户端同时多次调用Content#startService方法启动同一个服务时,其他的intent请求会暂时被挂起,直到前面的intent异步任务请求处理完成才会处理下一个intent请求。直到所有的intent请求结束之后,IntentService服务会调用stopSelf停止当前服务。也就是当intent异步任务处理结束之后,对应的IntentService服务会自动销毁,进而调用IntentService#onDestroy方法:
@Override
public void onDestroy() {
mServiceLooper.quit();
}
该方法中调用HandlerThread工作线程中Looper对象的quit方法让当前工作线程HandlerThread退出当前Looper循环,进而结束线程。进而结束当前IntentService服务。到此,整个IntentService服务结束,现在可以用一张流程图来描述整个过程如下:
IntentService总结
- 子类需继承IntentService并且实现里面的onHandlerIntent抽象方法来处理intent类型的任务请求。
- 子类需要重写默认的构造方法,且在构造方法中调用父类带参数的构造方法。
- IntentService类内部利用HandlerThread+Handler构建了一个带有消息循环处理机制的后台工作线程,客户端只需调用Content#startService(Intent)将Intent任务请求放入后台工作队列中,且客户端无需关注服务是否结束,非常适合一次性的后台任务。比如浏览器下载文件,退出当前浏览器之后,下载任务依然存在后台,直到下载文件结束,服务自动销毁。
- 只要当前IntentService服务没有被销毁,客户端就可以同时投放多个Intent异步任务请求,IntentService服务端这边是顺序执行当前后台工作队列中的Intent请求的,也就是每一时刻只能执行一个Intent请求,直到该Intent处理结束才处理下一个Intent。因为IntentService类内部利用HandlerThread+Handler构建的是一个单线程来处理异步任务。
【转载请注明出处:http://www.cnblogs.com/feidu/p/8074268.html 废墟的树】
扫码关注微信公众号“Android知识传播”,不定时传播常用Android基础知识。
Android IntentService详解及使用实例
Android IntentService详解
一、IntentService简介
IntentService是Service的子类,比普通的Service增加了额外的功能。先看Service本身存在两个问题:
- Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中;
- Service也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务;
二、IntentService特征
- 会创建独立的worker线程来处理所有的Intent请求;
- 会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
- 所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
- 为Service的onBind()提供默认实现,返回null;
- 为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;
三、使用步骤(详情参考Service项目)
继承IntentService类,并重写onHandleIntent()方法即可;
MainActivity.Java文件
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void startService(View source) { // 创建所需要启动的Service的Intent Intent intent = new Intent(this,MyService.class); startService(intent); } public void startIntentService(View source) { // 创建需要启动的IntentService的Intent Intent intent = new Intent(this,MyIntentService.class); startService(intent); } }
MyIntentService.java文件
public class MyIntentService extends IntentService { public MyIntentService() { super("MyIntentService"); } @Override protected void onHandleIntent(Intent intent) { // IntentService会使用单独的线程来执行该方法的代码 // 该方法内执行耗时任务,比如下载文件,此处只是让线程等待20秒 long endTime = System.currentTimeMillis() + 20 * 1000; System.out.println("onStart"); while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (InterruptedException e) { e.printstacktrace(); } } } System.out.println("----耗时任务执行完成---"); } }
MyService.java文件
public class MyService extends Service { @Override public IBinder onBind(Intent arg0) { return null; } @Override public int onStartCommand(Intent intent,int flags,int startId) { // 该方法内执行耗时任务可能导致ANR(Application Not Responding)异常 long endTime = System.currentTimeMillis() + 20 * 1000; System.out.println("onStart"); while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (InterruptedException e) { e.printstacktrace(); } } } System.out.println("----耗时任务执行完成---"); return START_STICKY; } }
运行上述代码,启动MyIntentService的会使用单独的worker线程,因此不会阻塞前台的UI线程;而MyService会。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
Android Oreo JobIntentService继续在Android 7及以下版本的后台运行,并且经常在Android 8及以上版本中崩溃
Android 8&以上:
在Android 8及更高版本中连续发生崩溃.这里有一张票提到了同样的问题https://issuetracker.google.com/issues/63622293,我添加了一些极客建议的临时解决方案.
Android 7&下面:
一旦工作完成,JobIntentService就像Intent Service一样不会停止.
我在服务中实现了JobIntentService,只要用户执行某些操作就会触发该服务.
码
public class SampleJobIntentService extends FixedJobIntentService { public static void postData(Context context,String data) { Intent intent = new Intent(context,SampleJobIntentService.class); intent.setAction(INITIAL_ACTION); intent.putExtra(SAMPLE_ID,data); SampleJobIntentService.enqueueWork(context,intent); } public static void enqueueWork(Context context,Intent work) { SampleJobIntentService.enqueueWork(context,SampleJobIntentService.class,JOB_ID,work); @Override protected void onHandleWork(@NonNull Intent intent) { if (intent != null) { SampleRequest sampleRequest = requests.get(intent.getAction()); if (sampleRequest != null) { try { // perform some networking operations } catch (Exception ex) { Log.d("Error for intent "); } Log.i("send action "); } else Log.e("action not found for "); } } }
为了避免JobIntentService崩溃,我从https://issuetracker.google.com/issues/63622293获取了一些参考资料
public abstract class FixedJobIntentService extends JobIntentService { @Override GenericWorkItem dequeueWork() { try { return new FixedGenericWorkItem(super.dequeueWork()); } catch (SecurityException ignored) { doStopCurrentWork(); } return null; } private class FixedGenericWorkItem implements GenericWorkItem { final GenericWorkItem mGenericWorkItem; FixedGenericWorkItem(GenericWorkItem genericWorkItem) { mGenericWorkItem = genericWorkItem; } @Override public Intent getIntent() { if (mGenericWorkItem != null) { return mGenericWorkItem.getIntent(); } return null; } @Override public void complete() { try { if (mGenericWorkItem != null) { mGenericWorkItem.complete(); } } catch (IllegalArgumentException ignored) { doStopCurrentWork(); } } } }
解决方法
Well…,Its a lot big theory…!! It would not be able to put it all here. I will try my best which will make some your concepts clear.
我已经失去了2年阅读谷歌文档的完整年份…哪些是无用的…没有适当的文档,没有适合其开发人员的示例代码.. !!所以我在堆栈溢出的每个帖子中提到这一点,因为它有助于节省其他人的时间.. !!
它看起来你是一个优秀的程序员;只需要对您发布的问题提供一些提示:
提示-1:
YOU :- I have recently replaced all my service to foreground services and
JobIntentService
前台服务:
如果你需要所有的时间运行过程;什么都不会结束……一旦开始它就会在服务中使用它从其OnStartCommand返回START_STICKY.再次不建议使用,好像你想不惜一切代价实现它…那么你将不得不使用setongoing的通知(true)哪个最终用户无法刷掉你的通知,它将保留在那里永远….
使用前台服务:
接收器也有限制;在Oreo之上,您不能通过在清单中声明它并仅通过创建接收器来使用所有接收器和意图操作…我建议只使用BootComplete权限并使用单个接收器接收boot_completed意图并调用服务在O之下并调用O之上的前台服务.现在从该前台服务中为所有人实现运行时接收器并在Ondestroy方法中取消注册它.我从来没有找到实现运行时接收器的官方示例代码,最后我已经成功实施了几个月的艰苦工作…是的,这不是一个聪明的工作,因为谷歌
何时使用前台服务:
只有你想实现广播接收器….如果你不想实现任何广播接收器;远离…….
提示-2:
YOU :- I have recently replaced all my service to foreground services and
JobIntentService
**服务质量:**
只做一个非常微小的工作……然后退出……它必须由StopSelf()退出……再次,如果多次调用服务可能会导致数据丢失……同样的服务线程可以运行更多不止一次…再次,如果你想要一项服务做很多工作……使用START_STICKY ……但是不建议再次推荐我已经建议,何时在提示1中使用它.
** Intentservice的质量如下:**
执行相对较长时间运行的任务并且它只具有串行执行属性如果您反复调用同一个intentService,则所有调用将保留在队列中,并在逐个完成后逐个执行.如上所述,这不是服务中的情况.它自己结束……没有必要由开发人员结束.. !!
**独特的品质:**
一旦他们崩溃,android可以阻止他们将来调用,而不会通知你,因为它崩溃的应用程序.需要使用try-catch-exception处理它们以避免崩溃.再次……如果您在服务中实现线程,那么try-catch-exception将不会使您的应用程序崩溃…
**那么地狱&如何实施呢:**
使用FireBaseJobScedular: –
>易于使用
>使用简单的JobService
>可以运行更长或更短的时间任务……即使是所有的时间运行任务
>甚至非标准公司支持,如vivo,mi,oppo,one 3,…这需要库存 – android会对其进行更改,并提供FunTouchO,ColorOs,OxygenO等名称
>只需将电池设置更改为“不优化此应用”
>是谷歌正式支持它并建议使用它
>它创建GooglePlyService的实例并在其中运行.显然,非标准公司也不会限制谷歌应用程序执行其任务.
>在Oreo上工作..,即使我已经在Android P上测试过它,并且在Android版本5.0下作为AlarmManager任务工作.
>我仍然建议使用16以上的minsdk,目标sdk 26,好像万一你要将你的应用程序上传到谷歌播放它现在是强制性的,那个消息会听到你的消息.并编译sdk 26.
>只需将您的JobService绑定在清单中,并使用receive_boot_complete的单行权限
>只需安排它……它将在每个制造商的市场上的每个设备上启动……即使是冷启动和热启动
>它最大限度地减少了很多代码,你可以专注于实际的任务.
>任务完成后,您可以返回false以指示任务已完成,它将结束JobService.
为什么我建议,因为我是一个UNKNown公司的首席技术官,并且经历过许多类型的Android手机制造商的前台服务引起的问题……不是Apple和ios所以我们必须经历它.自18年以来一直是开发人员,我今天大部分都在编码…在所有开发项目中,我的开发策略仅由我来考虑.
Correct me … too… As you have not mentioned
what your tasks
andproject
is related to… and what you exactly wants to be done in aforeground service and intent-service
… Let me kNow…,It would be my pleasure to help you. It is a general theoretical answer rather than what you wants…. But for giving you actual answer i will need exact your project scope..
今天关于如何在Android中使用IntentService同时下载多个文件?和android多个application的讲解已经结束,谢谢您的阅读,如果想了解更多关于Android 8.0 以后使用后台 Service 服务 JobIntentService 的使用、Android IntentService的使用和源码分析、Android IntentService详解及使用实例、Android Oreo JobIntentService继续在Android 7及以下版本的后台运行,并且经常在Android 8及以上版本中崩溃的相关知识,请在本站搜索。
本文标签: