安卓在Service中弹出Dialog
来源:互联网 发布:淘宝客服幽默常用语 编辑:程序博客网 时间:2024/05/21 19:05
这是前几天在面试的时候被问到的一个问题,首先当时本人并没有仔细研究过这个问题,答得一塌糊涂,所以下来就仔细研究了一下:
先给出结论:
API 18 及以下可以使用将Dialog设置为 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT ,来解决这个问题;API 19 以上就不行了,我的实现方式是将一个Activity的THEME设置为Theme.AppCompat.Dialog.Alert,曲线救国。效果如下:
一、API 18 的实现方式:
- 添加权限 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
- 直接贴出 Activity 和 Service 部分代码
MainActivity
public class MainActivity extends Activity { @BindView(R.id.start_service) Button startService; @BindView(R.id.stop_service) Button stopService; @BindView(R.id.bind_service) Button bindService; @BindView(R.id.unbind_service) Button unbindService; private Intent intent; private MyService.MyBinder myBinder; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { myBinder = (MyService.MyBinder) iBinder; myBinder.startDownload(); } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); intent = new Intent(this, MyService.class); } @OnClick({R.id.start_service, R.id.stop_service, R.id.bind_service, R.id.unbind_service}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.start_service: startService(intent); break; case R.id.stop_service: stopService(intent); break; case R.id.bind_service: bindService(intent, connection, BIND_AUTO_CREATE); break; case R.id.unbind_service: unbindService(connection); break; } }}上面的startDownload() 方法执行的时 showDialog(),名字咩改,见谅
MyService
public class MyService extends Service { private static final String TAG = "MyService"; private MyBinder binder = new MyBinder(); private Handler handler = new Handler(); @Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate executed"); Log.e(TAG, "MyService thread is " + Thread.currentThread().getId()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand executed"); showDialog(); return super.onStartCommand(intent, flags, startId); } @Override public boolean onUnbind(Intent intent) { Log.d(TAG, "onUnBind executed"); return super.onUnbind(intent); } @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind executed"); return binder; } @Override public void onDestroy() { Log.d(TAG, "onDestroy executed"); super.onDestroy(); } public class MyBinder extends Binder { public void startDownload() { showDialog(); Log.d(TAG, "requestNet"); } } private void showDialog() {// 注释1此处需要注意(详见下文)//AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AppTheme)); builder.setTitle("提示"); //设置标题 builder.setMessage("是否确认退出?"); //设置内容 builder.setIcon(R.mipmap.ic_launcher);//设置图标,图片id即可 builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { //设置确定按钮 @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); //关闭dialog Toast.makeText(MyService.this, "确认" + which, Toast.LENGTH_SHORT).show(); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { //设置取消按钮 @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); Toast.makeText(MyService.this, "取消" + which, Toast.LENGTH_SHORT).show(); } }); builder.setNeutralButton("忽略", new DialogInterface.OnClickListener() {//设置忽略按钮 @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); Toast.makeText(MyService.this, "忽略" + which, Toast.LENGTH_SHORT).show(); } }); //参数都设置完成了,创建并显示出来 final AlertDialog dialog = builder.create();// 注释2 把该dialog类型设置为系统的弹窗 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); dialog.show();// 注释3 并不需要使用多线程 + handler// new Thread(new Runnable() {// @Override// public void run() {// handler.post(new Runnable() {// @Override// public void run() {// Toast.makeText(MyService.this, "dialog.show()", Toast.LENGTH_SHORT).show();// dialog.show();// }// });// }// }).start(); }}注释1:此处如果直接写成注释中的代码,报出如下错误,提示需要给Activity设置一个Theme,Google了一下,网上有很多这样的错误,但是跟笔者的情况都不一样,
笔者按照提示给MainActivity加了Theme,发现并没有卵用,后来给Dialog添加了Theme才有效。笔者此处并没有想通为什么必须添加这个Theme,希望有大牛解答。
08-10 05:51:34.187 29397-29397/chang.xiaobing.servicedialogtest E/AndroidRuntime: FATAL EXCEPTION: mainjava.lang.RuntimeException: Unable to start service chang.xiaobing.servicedialogtest.service.MyService@536d1ff0 with Intent {cmp=chang.xiaobing.servicedialogtest/.service.MyService }: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2507)at android.app.ActivityThread.access$1900(ActivityThread.java:130)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1292)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:137)at android.app.ActivityThread.main(ActivityThread.java:4745)at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)at dalvik.system.NativeStart.main(Native Method)Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.at android.support.v7.app.AppCompatDelegateImplV9.createSubDecor(AppCompatDelegateImplV9.java:356)at android.support.v7.app.AppCompatDelegateImplV9.ensureSubDecor(AppCompatDelegateImplV9.java:325)at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:286)at android.support.v7.app.AppCompatDialog.setContentView(AppCompatDialog.java:83)at android.support.v7.app.AlertController.installContent(AlertController.java:225)at android.support.v7.app.AlertDialog.onCreate(AlertDialog.java:257)at android.app.Dialog.dispatchOnCreate(Dialog.java:351)at android.app.Dialog.show(Dialog.java:256)at chang.xiaobing.servicedialogtest.service.MyService.showDialog(MyService.java:108)at chang.xiaobing.servicedialogtest.service.MyService.onStartCommand(MyService.java:41)at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2490)at android.app.ActivityThread.access$1900(ActivityThread.java:130) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1292) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4745) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method)
注释2:此处除了可以设置为 TYPE_SYSTEM_ALERT,还可以设置为 TYPE_TOAST,只不过设置为 TYPE_TOAST 之后不会响应点击事件,而且关不掉。
注释3:笔者在网上查资料时发现很多文章中写到在Service中 show Dialog 和 show Toast 时需要使用多线程+handler,经测试并不需要(见上面注释3的代码部分)
(布局文件会在下方给出)
下面是曲线救国方案:
思路:直接弹出一个Dialog样式的Activity,不多说直接上代码
1.在values/styles.xml中添加一个style(根据需求自定义)
<style name="dialogstyle"> <!--设置dialog的背景--> <item name="android:windowBackground">@android:color/transparent</item> <!--设置Dialog的windowFrame框为无--> <item name="android:windowFrame">@null</item> <!--设置无标题--> <item name="android:windowNoTitle">true</item> <!--是否浮现在activity之上--> <item name="android:windowIsFloating">true</item> <!--是否半透明--> <item name="android:windowIsTranslucent">true</item> <!--设置窗口内容不覆盖--> <item name="android:windowContentOverlay">@null</item> <!--设置动画,在这里使用让它继承系统的Animation.Dialog--> <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> <!--背景是否模糊显示--> <item name="android:backgroundDimEnabled">true</item> </style>2. 在清单文件中添加一个DialogActivity,并且为其设置样式
<activity android:name=".DialogActivity" android:theme="@style/dialogstyle"></activity>3. 将showDialog() 方法给成下面的:
private void showDialog() { Intent intent = new Intent(this, DialogActivity.class);// 此处必须设置flag intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); }
4. 然后可以自定义布局,处理点击事件,效果如下(写的并不是很美观,可根据需求自定义)源码在这里
文章就到这里,希望能对你有所帮助,笔者才疏学浅,不足之处请各位大牛不吝赐教!
阅读全文
0 0
- 安卓在Service中弹出Dialog
- 如何在service中弹出dialog
- 如何在service中弹出dialog
- android在Service中弹出Dialog对话框
- 如何在service中弹出dialog
- 如何在service中弹出dialog
- 在Service中弹出Toast和Dialog
- 如何在service中弹出dialog
- 如何在service中弹出dialog
- 如何在service中弹出dialog
- 如何在service中弹出dialog
- 如何在service中弹出dialog
- Android在Service中弹出对话框(Dialog)
- Android在Service中弹出Dialog
- 在Service中弹出一个Dialog
- 在Service或者BroadCastReceiver中弹出dialog
- 在Service中弹出Toast和Dialog
- Service中弹出Dialog Toast
- JMS ActiveMQ入门
- Samba服务安装与配置
- iwebshop 简介
- React+webpack 的开发环境配置步骤(三)
- IO流--File类的使用
- 安卓在Service中弹出Dialog
- Cesium 转换成gltf格式
- A
- (1)概述
- 通过Hive及其Udf函数进行Nginx日志分析
- Python基础教程学习笔记第二章:列表和元组
- Qt自带命令的发布+vs+opencv应用程序的发布
- redis 安装与配置
- html网页嵌入flv视频