写了一个应用mainactivity启动服务,在service中启动socket服务,socket捕获异常在service中弹出dialog,但就是不行。
每次都弹出这个错误,但改主题也没用还是弹出这个错误,哪位给看一下
FATAL EXCEPTION: Thread-4
Process: com.example.msslapp, PID: 22716
java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
android 使用 service弹出dialog
mainactivity是
public class MainActivity extends AppCompatActivity {
private final int SERVER_PORT = 26666;//端口号
private final String SERVER_IP = "192.168.1.101";//连接IP
TcpConnectThread tcpthread;
TextView tv1;
EditText et1,et2,et3,et4;
Button btn1,btn2,btn3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1 =(TextView) findViewById(R.id.tv1);
et1 =(EditText) findViewById(R.id.et1);
btn1=(Button) findViewById(R.id.btn1);
et2 =(EditText) findViewById(R.id.et2);
et3 =(EditText) findViewById(R.id.et3);
et4 =(EditText) findViewById(R.id.et4);
btn2=(Button) findViewById(R.id.btn2);
btn3=(Button) findViewById(R.id.btn3);
Intent regIntent = new Intent(this, SocketService.class);
regIntent.putExtra("IP", SERVER_IP);
regIntent.putExtra("PORT",SERVER_PORT);
startService(regIntent);
// tcpthread = new TcpConnectThread(SERVER_IP,SERVER_PORT,getApplicationContext());
// tcpthread.start();
//发送消息模式为test的消息
btn1.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
String str=et1.getText().toString();
TCPsend ts=new TCPsend(tcpthread.Client_ssl,"test",str);
new Thread(ts).start();
}
});
//发送消息模式为key的消息
btn2.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
String key= et2.getText().toString();
String data= et3.getText().toString();
String context =et4.getText().toString();
TCPsend ts=new TCPsend(SocketService.Client_ssl,key,data,context);
new Thread(ts).start();
}
});
btn3.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
EventBus.getDefault().post(new MyEvent("123456"));
}
});
/*
if(EventBus.getDefault().isRegistered(this)){
System.out.println("已经注册");
}
else if(!EventBus.getDefault().isRegistered(this)){
System.out.println("注册失败");
}*/
EventBus.getDefault().register(this);
}
@Override
public void onDestroy() {
// TCPsend ts=new TCPsend(tcpthread.Client_ssl,"type","Quit");
// new Thread(ts).start();
super.onDestroy();
MainActivity.this.stopService(new
Intent(MainActivity.this,
SocketService.class));
EventBus.getDefault().unregister(this); //取消注册
}
//接收eventbus消息
@Subscribe(threadMode = ThreadMode.MAIN)
public void EventbusMain(MyEvent te) {
tv1.setText(te.getdata());
}
}
service为
public class SocketService extends Service {
private static final String CLIENT_KET_PASSWORD = "changeit";//私钥密码
private static final String CLIENT_TRUST_PASSWORD = "changeit";//信任证书密码
private static final String CLIENT_AGREEMENT = "SSL";//使用协议
private static final String CLIENT_KEY_MANAGER = "X509";//密钥管理器
private static final String CLIENT_TRUST_MANAGER = "X509";//
private static final String CLIENT_KEY_KEYSTORE = "BKS";//密库,这里用的是BouncyCastle密库
private static final String CLIENT_TRUST_KEYSTORE = "BKS";//
/*连接线程*/
private Thread connectThread;
private Timer timer = new Timer();
//private OutputStream outputStream;
private SocketBinder sockerBinder = new SocketBinder();
private String ip;
private int port;
private TimerTask task;
static SSLSocket Client_ssl;
/*默认重连*/
private boolean isReConnect = true;
private Handler handler;
@Override
public IBinder onBind(Intent intent) {
return sockerBinder;
}
public class SocketBinder extends Binder {
/*返回SocketService 在需要的地方可以通过ServiceConnection获取到SocketService */
public SocketService getService() {
return SocketService.this;
}
}
@Override
public void onCreate() {
handler = new Handler(Looper.getMainLooper());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/*拿到传递过来的ip和端口号*/
ip = intent.getStringExtra("IP");
port =intent.getIntExtra("PORT",0) ;
/*初始化socket*/
initSocket();
return super.onStartCommand(intent, flags, startId);
}
/*初始化socket*/
private void initSocket() {
if (Client_ssl == null && connectThread == null) {
connectThread = new Thread(new Runnable() {
@Override
public void run() {
try {
final SSLContext sslContext = SSLContext.getInstance(CLIENT_AGREEMENT);
//取得KeyManagerFactory和TrustManagerFactory的X509密钥管理器实例
KeyManagerFactory keyManager = KeyManagerFactory.getInstance(CLIENT_KEY_MANAGER);
TrustManagerFactory trustManager = TrustManagerFactory.getInstance(CLIENT_TRUST_MANAGER);
//取得BKS密库实例
KeyStore kks = KeyStore.getInstance(CLIENT_KEY_KEYSTORE);
KeyStore tks = KeyStore.getInstance(CLIENT_TRUST_KEYSTORE);
//加客户端载证书和私钥,通过读取资源文件的方式读取密钥和信任证书
kks.load(getBaseContext().getAssets().open("client.bks"), CLIENT_KET_PASSWORD.toCharArray());
tks.load(getBaseContext().getAssets().open("client.bks"), CLIENT_TRUST_PASSWORD.toCharArray());
//初始化密钥管理器
keyManager.init(kks, CLIENT_KET_PASSWORD.toCharArray());
trustManager.init(tks);
//初始化SSLContext
sslContext.init(keyManager.getKeyManagers(), trustManager.getTrustManagers(), null);
Client_ssl = (SSLSocket) sslContext.getSocketFactory().createSocket(ip, port);
System.out.println("正在连接");
/*连接成功的话 发送心跳包*/
if (Client_ssl.isConnected()) {
/*因为Toast是要运行在主线程的 这里是子线程 所以需要到主线程哪里去显示toast*/
toastMsg("socket已连接");
TcpConnectThread tcpthread = new TcpConnectThread(Client_ssl,getApplicationContext());
tcpthread.start();
/*发送心跳数据*/
sendBeatData();
}
} catch (IOException e) {
e.printStackTrace();
if (e instanceof SocketTimeoutException) {
toastMsg("连接超时");
releaseSocket();
} else if (e instanceof NoRouteToHostException) {
toastMsg("该地址不存在,请检查");
stopSelf();
} else if (e instanceof ConnectException) {
toastMsg("连接异常或被拒绝,请检查");
releaseSocket();
//stopSelf();
}
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
});
/*启动连接线程*/
connectThread.start();
}
}
/*定时发送数据*/
private void sendBeatData() {
if (timer == null) {
timer = new Timer();
}
if (task == null) {
task = new TimerTask() {
@Override
public void run() {
try {
Message msg=new Message();
msg.putmsgmap("type","Beat");
MyObjectOutputStream moos;
moos =new MyObjectOutputStream(Client_ssl.getOutputStream());
moos.writeObject(msg);
moos.flush();
} catch (Exception e) {
/*发送失败说明socket断开了或者出现了其他错误*/
//toastMsg("连接断开,正在重连");
/*重连*/
releaseSocket();
e.printStackTrace();
}
}
};
}
timer.schedule(task, 0, 2000);
}
/*释放资源*/
private void releaseSocket() {
if (task != null) {
task.cancel();
task = null;
}
if (timer != null) {
timer.purge();
timer.cancel();
timer = null;
}
if (Client_ssl != null) {
try {
Client_ssl.close();
} catch (IOException e) {
}
Client_ssl = null;
}
if (connectThread != null) {
connectThread = null;
}
/*重新初始化socket*/
if (isReConnect) {
showDialog();
//initSocket();
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("SocketService", "onDestroy");
isReConnect = false;
releaseSocket();
}
/*因为Toast是要运行在主线程的 所以需要到主线程哪里去显示toast*/
private void toastMsg(final String msg) {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
});
}
private void showDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("连接已经断开,是否重新连接");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
initSocket();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
isReConnect = false;
}
});
AlertDialog alertDialog = builder.create();
//alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
alertDialog.getWindow().setType((WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY));
}else {
alertDialog.getWindow().setType((WindowManager.LayoutParams.TYPE_SYSTEM_ALERT));
}
alertDialog.setCanceledOnTouchOutside(true);
alertDialog.show();
new Thread(){
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
alertDialog.show();
}
});
};
}.start();
}
}
在服务中调用方法
private void showDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("连接已经断开,是否重新连接");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
initSocket();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
isReConnect = false;
}
});
AlertDialog alertDialog = builder.create();
//alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
alertDialog.getWindow().setType((WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY));
}else {
alertDialog.getWindow().setType((WindowManager.LayoutParams.TYPE_SYSTEM_ALERT));
}
alertDialog.setCanceledOnTouchOutside(true);
alertDialog.show();
new Thread(){
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
alertDialog.show();
}
});
};
}.start();
}
权限也加了
name="android.permission.SYSTEM_OVERLAY_WINDOW"/>
name="android.permission.SYSTEM_ALERT_WINDOW" />
name="android.permission.INTERNET"/>
在Android中,Service不能直接弹出对话框,因为它不具有用户界面。如果您试图使用showDialog方法,则会出现错误。
解决方法如下:
启动一个Activity:您可以启动一个Activity,并在其中显示对话框。
使用Notification:您可以使用Notification,以在通知栏中显示消息。
使用BroadcastReceiver:您可以使用BroadcastReceiver,以在接收到广播时显示对话框。
望采纳。。
android 中,service 是不能直接使用 dialog,因为初始化 dialog 的参数 context 需要用到 Activity,你现在用的 context 是 service,所以会报错闪退。
解决方案:
方案一:使用 WindowManager 去添加 Layout 做一个悬浮窗版的 dialog。
方案二:在 service 里面启动一个 DialogActivity
方案三:在 service 里面启动一个全透明的 Activity,然后在这个全透明的 activity 里面弹出 Dialog。
望采纳,如果您需要代码,可先采纳,然后联系我,我可给你把这三个方案的代码写给你。
斟酌后再考虑,望采纳哦😅
只能从活动或片段调用该方法。Android 中的服务在后台运行,无法访问 UI,因此您无法直接显示来自服务的对话框。showDialog
若要显示来自服务的对话框,需要创建一个通知来启动显示该对话框的活动。下面是一个示例:
创建显示对话框的活动。可以通过调用 in 方法来执行此操作。AlertDialog.BuilderonCreate
在您的服务中,创建一个通知,用于启动在步骤 1 中创建的活动。用于创建在单击通知时启动活动的 Intent。PendingIntent
```java
Intent intent = new Intent(this, DialogActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "channel_id")
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("Service Notification")
.setContentText("Click to show dialog")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(0, builder.build());
3.确保请求文件中的权限。FOREGROUND_SERVICEAndroidManifest.xml
```java
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
这个错误如果单独用activity或许可以解决,目前android创建的默认这个不行,不兼容,所以会报这个错误,可以采用异步调用的方式,也可以直接再创一个activity兼容这个dialog,最后设置成透明背景就是一样的。
不知道你这个问题是否已经解决, 如果还没有解决的话:service不可以弹出dialog,如果想要弹出,可以有以下方案
1)透明activity,里面有dialog进行展示,dialog的取消、确定与activity的生命周期关联
2)用phonewindow或者window
3)一个像素的activity,然后可以进行任意的操作
service里有个handler,放handler里去执行,如果你的toast可以正常显示,dialog也可以呀。
dialog.getWindow().setType((WindowManager.LayoutParams.TYPE_SYSTEM_ALERT));
可以让对话框始终显示在其他应用程序的window之上,也就是说这个dialog始终处于最上层,对用户始终可见,
也就是说用户按了home之后dialog还在。这样做需要加上权限"android.permission.SYSTEM_ALERT_WINDOW",但是某些手机对底层进行了修改(小米,魅族,乐视之类),系统会默认会拒绝该权限。
解决:
通过将type设定为TYPE_TOAST, 就可以绕过检查。
通过将type设定为TYPE_TOAST, 就可以绕过检查。
如果需要后台进行建议换个方案吧,不如搞个悬浮窗来解决不行的话就回到软件打开个activity在进行不然的话用不了showdialog方法的
该回答引用ChatGPT
请参考下面的解决方案,如果有帮助,还请点击 “采纳” 感谢支持!
解决方案如下:
在清单文件中,为MainActivity活动指定一个AppCompat主题,如下所示:
<activity
android:name=".MainActivity"
android:theme="@style/AppTheme">
...
</activity>
2、创建一个style.xml文件并创建一个AppCompat主题:
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
...
</style>
</resources>
3、在Service中使用Context.getSystemService(Context.ALERT_SERVICE)获取WindowManager,并使用它创建一个Dialog:
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AppTheme));
builder.setTitle("Title")
.setMessage("Message")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// handle the click event
}
});
AlertDialog dialog = builder.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
dialog.show();