我想为我的控制台应用程序安全退出,该应用程序将使用单声道在linux上运行,但我找不到一个解决方案来检测是否发送了一个信号,或者用户按下了ctrl + c。
在Windows上有内核函数SetConsoleCtrlHandler来完成这项工作,但这对单声道不起作用。
如何在我的控制台应用程序上获得关闭事件以安全退出?
答案 0 :(得分:11)
你需要使用Mono.UnixSignal
,Jonathan Pryor发布了一个很好的样本:http://www.jprl.com/Blog/archive/development/mono/2008/Feb-08.html
在Mono页面上还有一个较短的示例:FAQ / Technical / Operating System Questions / Signal Handling:
// Catch SIGINT and SIGUSR1
UnixSignal[] signals = new UnixSignal [] {
new UnixSignal (Mono.Unix.Native.Signum.SIGINT),
new UnixSignal (Mono.Unix.Native.Signum.SIGUSR1),
};
Thread signal_thread = new Thread (delegate () {
while (true) {
// Wait for a signal to be delivered
int index = UnixSignal.WaitAny (signals, -1);
Mono.Unix.Native.Signum signal = signals [index].Signum;
// Notify the main thread that a signal was received,
// you can use things like:
// Application.Invoke () for Gtk#
// Control.Invoke on Windows.Forms
// Write to a pipe created with UnixPipes for server apps.
// Use an AutoResetEvent
// For example, this works with Gtk#
Application.Invoke (delegate () { ReceivedSignal (signal); });
}});
答案 1 :(得分:10)
作为提供unix和windows实现的示例,请参见下文。请注意,使用Visual Studio时仍可以包含Mono.Posix dll。
我也添加了SIGTERM信号,因为当停止/重新启动你的app作为服务时,unix中的systemd会触发这个信号。
公开退出事件的界面
public class MainActivity extends Activity {
private ImageView image;
private Button uploadButton;
private Bitmap bitmap;
private Button selectImageButton;
// number of images to select
private static final int PICK_IMAGE = 1;
/**
* called when the activity is first created
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// find the views
image = (ImageView) findViewById(R.id.uploadImage);
uploadButton = (Button) findViewById(R.id.uploadButton);
// on click select an image
selectImageButton = (Button) findViewById(R.id.selectImageButton);
selectImageButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
selectImageFromGallery();
}
});
// when uploadButton is clicked
uploadButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new ImageUploadTask().execute();
}
});
}
/**
* Opens dialog picker, so the user can select image from the gallery. The
* result is returned in the method <code>onActivityResult()</code>
*/
public void selectImageFromGallery() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"),
PICK_IMAGE);
}
/**
* Retrives the result returned from selecting image, by invoking the method
* <code>selectImageFromGallery()</code>
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE && resultCode == RESULT_OK
&& null != data) {
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
Log.i("picturePath", "picturePath: " + picturePath);
cursor.close();
decodeFile(picturePath);
}
}
/**
* The method decodes the image file to avoid out of memory issues. Sets the
* selected image in to the ImageView.
*
* @param filePath
*/
public void decodeFile(String filePath) {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 1024;
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
bitmap = BitmapFactory.decodeFile(filePath, o2);
image.setImageBitmap(bitmap);
}
/**
* The class connects with server and uploads the photo
*
*
*/
class ImageUploadTask extends AsyncTask<Void, Void, String> {
private String webAddressToPost = "URL";
// private ProgressDialog dialog;
private ProgressDialog dialog = new ProgressDialog(MainActivity.this);
@Override
protected void onPreExecute() {
dialog.setMessage("Uploading...");
dialog.show();
}
@Override
protected String doInBackground(Void... params) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.JPEG, 100, bos);
byte[] data = bos.toByteArray();
String file = Base64.encodeToString(data, 0);
ArrayList<NameValuePair> postData;
postData = new ArrayList<NameValuePair>();
JSONObject parentData = new JSONObject();
JSONObject childData = new JSONObject();
try {
childData.put("fileContent", file);
childData.put("fileName", "droid.jpeg");
childData.put("fileType", "I");
System.out.println(childData);
parentData.put("mobile", childData);
System.out.println(parentData);
postData.add(new BasicNameValuePair("mobile", childData
.toString()));
InputStream is = null;
String jsonResponse = "";
JSONObject jObj = null;
} catch (JSONException e) {
e.printStackTrace();
}
postData.add(new BasicNameValuePair("mobile", childData.toString()));
InputStream is = null;
String jsonResponse = "";
JSONObject jObj = null;
try {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(webAddressToPost);
/*
* MultipartEntity entity = new MultipartEntity(
* HttpMultipartMode.BROWSER_COMPATIBLE);
*
* entity.addPart("uploaded", new StringBody(file));
*
* entity.addPart("someOtherStringToSend", new StringBody(
* "your string here"));
*/
httpPost.setHeader("Content-Type",
"application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(parentData.toString()));
// httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
System.out.println(httpResponse);
BufferedReader reader = new BufferedReader(
new InputStreamReader(httpResponse.getEntity()
.getContent(), "UTF-8"));
String sResponse = reader.readLine();
Log.i("sResponse", "sResponse: " + sResponse);
return sResponse;
} catch (Exception e) {
// something went wrong. connection with the server error
}
return null;
}
@Override
protected void onPostExecute(String result) {
dialog.dismiss();
Toast.makeText(getApplicationContext(), "file uploaded",
Toast.LENGTH_LONG).show();
}
}
Unix实现
public interface IExitSignal
{
event EventHandler Exit;
}
Windows实施
public class UnixExitSignal : IExitSignal
{
public event EventHandler Exit;
UnixSignal[] signals = new UnixSignal[]{
new UnixSignal(Mono.Unix.Native.Signum.SIGTERM),
new UnixSignal(Mono.Unix.Native.Signum.SIGINT),
new UnixSignal(Mono.Unix.Native.Signum.SIGUSR1)
};
public UnixExitSignal()
{
Task.Factory.StartNew(() =>
{
// blocking call to wait for any kill signal
int index = UnixSignal.WaitAny(signals, -1);
if (Exit != null)
{
Exit(null, EventArgs.Empty);
}
});
}
}