I am using Android camera2 to create a custom camera. The cameraDevice.close() method is slow and it makes UI freeze for 1 sec. I put it in another thread and it seems to work just fine. I want to know if this will cause some serious problem and whether there is another way to achieve this. Here is my closeCamera method:
private void closeCamera() {
boolean release = false;
try {
mCameraOpenCloseLock.acquire();
release = true;
} catch (InterruptedException e) {
release = false;
}
try {
preparing = true;
if (mCaptureSession != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mCaptureSession.isReprocessable()
|| validCameraSession) {
mCaptureSession.close();
}
mCaptureSession = null;
validCameraSession = false;
}
} catch (IllegalStateException e) {
mCaptureSession = null;
} catch (Exception e) {
mCaptureSession = null;
}
try {
new Thread(new Runnable() {
#Override
public void run() {
if (mCameraDevice != null) {
if (openCamera) {
mCameraDevice.close();
mCameraDevice = null;
}
}
}
}).start();
} catch (IllegalStateException e) {
Log.e(TAG, "closeCamera: mCaptureSession - ", e);
} catch (Exception e) {
Log.e(TAG, "closeCamera: mCaptureSession - ", e);
}
if (release) {
if (mCameraOpenCloseLock != null) {
int lock = mCameraOpenCloseLock.availablePermits();
if (lock > 1) mCameraOpenCloseLock.release(lock - 1);
else if (lock == 0) mCameraOpenCloseLock.release();
}
}
}
I think it may cause crash when mCameraDevice has not been closed but user open camera again. But it is rare case, and I am thinking of putting another check before open camera again. I don't want my UI to freeze 1 sec for it to close, is there any other way I can achieve that except putting it in seperate thread?
As Alex Cohn mentions, the recommended practice is to do all camera-related work on a separate thread from the UI.
It also takes a long time to open the camera, or create a capture session, relatively speaking, so doing those operations not on the UI thread is also a good idea.
That said, as long as you're not losing track of your own app state (so that you don't try to use a camera device you've already closed by accident, for example), there's no reason you can't mix calls to the camera device or capture session from multiple threads. The classes themselves are thread-safe.
As far as I know, such freeze with cameraDevice.close() happens on some unfortunate devices, and sometimes is cured by performing a normal system upgrade.
But this is a little consolation if this happens to you, on your device. Actually, you are kind of lucky that you can prepare a fix for that. The end-users of your app will benefit from your misfortune.
Your code looks OK, if it delivers desired improvements for you. As I explained, it may be hard to reproduce this problem on another device.
I would rather put all closeCamera() logic on the same background thread. If you provided a Handler to openCamera(), as in the official example,
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
then I would suggest posting all closeCamera() sequence to this mBackgroundHandler.
Related
This thread I have written has three try catches. The first is a try with resources to set up an ObjectOutputStream. The second recieves information from another on whether authentication has succeeded or failed. On success it should establish a map utilised in communication and on failure the thread is returned from. Likewise if an Interrupt or IOException occurs in this phase, the thread is returned from. Only in the eventuality of successful authentication as far as I can see should the second try catch be reached. This second block is responsible for handling packets it receives util the session ends either through interrupt or a packet requesting it. My problem is that on ending a session I am required to replace the aforementioned ConcurrenHashMap record pertaining to this thread with an empty Optional. this should occur in both previously outlined shutdown mechanisms. However the line responsible for this in the InterruptedException catch block says the map may not have been initialised despite the fact that it should be impossible to reach that block without its initialisation.
public void run(){
boolean quit = false;
Packet packet;
int cid, nid;
ConcurrentMap<Integer, Optional<BlockingQueue<Packet>>> channelMap;
try (ObjectOutputStream output = new ObjectOutputStream(new
BufferedOutputStream(sslSocket.getOutputStream()))) {
try {
packet = channel.take();
if (packet.getType() == AUTH_SUCCESS) {
cid = ((AuthSuccessPacket) packet).getCid();
nid = ((AuthSuccessPacket) packet).getNid();
channelMap = networkMap.get(nid);
channelMap.replace(cid, Optional.of(channel));
output.writeObject(packet);
} else {
output.writeObject(packet);
return;
}
}catch (IOException | InterruptedException e){
return;
}
while (!quit && !interrupted()) {
try {
packet = channel.take();
switch (packet.getType()) {
case ACK:
case MESSAGE:
case REQUEST_USER:
case RELAY_SHUTDOWN:
output.writeObject(packet);
break;
case END_SESSION:
if (packet.getSource() == cid) {
output.writeObject(packet);
channelMap.replace(cid, Optional.empty());
quit = true;
}
break;
}
}catch (IOException e){}
}
}catch (InterruptedException e){
channelMap.replace(cid, Optional.empty());
} catch (IOException e){}
}
What am I missing? Thanks.
I am not sure what the cause was but I moved the Interrupt to a separate catch of the second inner block and it no longer raised the exception.
I have implemented the Azure - Offline Sync based on the documentation / Sample provided by Microsoft Sample in my Xamarin Forms Application.
In the sample / documentation provided, they are using the default Service Handler.
// Simple error/conflict handling. A real application would handle the various errors like network conditions,server conflicts and others via the IMobileServiceSyncHandler.
Since I need to implement a retry logic for 3 times if the Pull / Push fails. As per the documentation I have created a custom Service Handler(IMobileServiceSyncHandler).
Please find my code logic here.
public class CustomSyncHandler : IMobileServiceSyncHandler
{
public async Task<JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation)
{
MobileServiceInvalidOperationException error = null;
Func<Task<JObject>> tryExecuteAsync = operation.ExecuteAsync;
int retryCount = 3;
for (int i = 0; i < retryCount; i++)
{
try
{
error = null;
var result = await tryExecuteAsync();
return result;
}
catch (MobileServiceConflictException e)
{
error = e;
}
catch (MobileServicePreconditionFailedException e)
{
error = e;
}
catch (MobileServiceInvalidOperationException e)
{
error = e;
}
catch (Exception e)
{
throw e;
}
if (error != null)
{
if(retryCount <=3) continue;
else
{
//Need to implement
//Update failed, reverting to server's copy.
}
}
}
return null;
}
public Task OnPushCompleteAsync(MobileServicePushCompletionResult result)
{
return Task.FromResult(0);
}
}
But I am not sure how to handle / revert server copy in case all the 3 retry failed.
In the TODO sample they where reverting it based on the
MobileServicePushFailedException. But which is available when we implement IMobileServiceSyncHandler.
More over if we include custom IMobileServiceSyncHandler it wont execute the code after PushAsync / PullAsync. Even the try catch wont fire in case any exception.
try
{
await this.client.SyncContext.PushAsync();
await this.todoTable.PullAsync(
//The first parameter is a query name that is used internally by the client SDK to implement incremental sync.
//Use a different query name for each unique query in your program
"allTodoItems",
this.todoTable.CreateQuery());
}
catch (MobileServicePushFailedException exc)
{
if (exc.PushResult != null)
{
syncErrors = exc.PushResult.Errors;
}
}
// Simple error/conflict handling. A real application would handle the various errors like network conditions,
// server conflicts and others via the IMobileServiceSyncHandler.
if (syncErrors != null)
{
foreach (var error in syncErrors)
{
if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
{
//Update failed, reverting to server's copy.
await error.CancelAndUpdateItemAsync(error.Result);
}
else
{
// Discard local change.
await error.CancelAndDiscardItemAsync();
}
Debug.WriteLine(#"Error executing sync operation. Item: {0} ({1}). Operation discarded.", error.TableName, error.Item["id"]);
}
}
}
Note
In my application I am only trying to achieve retry for 3 time in case any server error. I am not looking for to resolve conflicts. Thant is the reason I haven't added the code for the same.
If someone came across similar issues and resolved it please help.
Stez.
You say you aren't trying to resolve conflicts, but you need to resolve them one way or another (without telling the user what's going on, perhaps) by accepting the server version of the object or updating the client operation. Otherwise it will just keep telling you about the same conflict each time it retries the operation.
You need to have a subclass of the Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncHandler class, which overrides OnPushCompleteAsync() in order to handle conflicts and other errors. Let's call the class SyncHandler:
public class SyncHandler : MobileServiceSyncHandler
{
public override async Task OnPushCompleteAsync(MobileServicePushCompletionResult result)
{
foreach (var error in result.Errors)
{
await ResolveConflictAsync(error);
}
await base.OnPushCompleteAsync(result);
}
private static async Task ResolveConflictAsync(MobileServiceTableOperationError error)
{
Debug.WriteLine($"Resolve Conflict for Item: {error.Item} vs serverItem: {error.Result}");
var serverItem = error.Result;
var localItem = error.Item;
if (Equals(serverItem, localItem))
{
// Items are the same, so ignore the conflict
await error.CancelAndUpdateItemAsync(serverItem);
}
else // check server item and local item or the error for criteria you care about
{
// Cancels the table operation and discards the local instance of the item.
await error.CancelAndDiscardItemAsync();
}
}
}
Include an instance of this SyncHandler() when you initialize your MobileServiceClient:
await MobileServiceClient.SyncContext.InitializeAsync(store, new SyncHandler()).ConfigureAwait(false);
Read up on the MobileServiceTableOperationError to see other conflicts you can handle as well as its methods to allow resolving them.
The exception carries with it a copy of the server version. In my implementation of IMobileServiceSyncHandler I therefore just return error.Value and this seems to work.
A more extensive example of this kind of logic can be found in this MSDN blog.
The same author has another example where he shows how you can resolve the conflict in favour of the server copy or the client copy, here.
Well, it actually works pretty well on my android studio simulator but when I try to run it on my phone it just crashes.
I just want to send a number to the server and get a response with the data that I need to that number. so this is my code which do that:
thread = new Thread() {
#Override
public void run() {
//server stuff
try {
//Connecting
if(!userClass.equals("")) {
Log.i(debugString, "Attempting to connect to server");
socket = new Socket(hostname, portnumber);
Log.i(debugString, "Connection established!");
BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(socket.getOutputStream())));
bw.write("" + userClass);
bw.newLine();
bw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
input = br.readLine();
}
} catch (IOException e) {
Log.e(debugString, e.getMessage());
} finally {
threadComplete = true;
}
}
};
thread.start();
while(!threadComplete)
continue;
then I just use this thread whenever I want to get the updated info for my request like that:
String getUserClass = userClass;
if(!getUserClass.equals(""))
{
threadComplete = false;
userClass = getUserClass;
thread.start();
while (!threadComplete)
continue;
changes.setText(input);
}
else Toast.makeText(this, "Error, choose your class", Toast.LENGTH_SHORT).show();
BTW, in the end of every thread (on the emulator because on my phone it crashes) I get a message:
Skipped 91 frames! The application may be doing too much work on its main thread.
and I have another problem, I also use IntentService to run my app service on the background, and obviously I don't want it to run constantly forever, so I made a loop which contains at the end of each loop a wait() command, but the problem is that when I set the time to wait for longer than 3000 milliseconds or so, the service crashes.
my code for the background service:
synchronized (this) {
int count = 0;
while (count<4) {
try {
wait(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (notifications && !userClass.equals("")) {
new Thread() {
#Override
public void run() {
//server stuff
try {
//Connecting
if (!userClass.equals("")) {
Log.i("debug", "Attempting to connect to server");
socket = new Socket(hostname, portnumber);
Log.i("debug", "Connection established!");
BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(socket.getOutputStream())));
bw.write("" + userClass);
bw.newLine();
bw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
input = br.readLine();
}
} catch (IOException e) {
Log.e("debug", e.getMessage());
} finally {
complete = true;
}
}
}.start();
while (!complete)
continue;
Toast.makeText(this, "" + input, Toast.LENGTH_SHORT).show();
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.chanka)
.setContentTitle("ביטול שיעורים: ")
.setContentText(input);
mNotifyMgr.notify(mNotificationId, mBuilder.build());
mNotificationId++;
Toast.makeText(this, "" + input, Toast.LENGTH_SHORT).show();
count++;
}
}
}
This following piece of code is the culprit -
while (!threadComplete)
continue;
You are kind of putting the main thread on a long loop. Android does not allow that. The general construct in these kind of use cases is this -
Step 1 - Show a progress dialog to the user indicating that you are
doing something important and user needs to wait till that is
complete. Show some meaningful text in the progress dialog which makes
sense to the user.
Step 2 - Start a async connection to the server. There are lot of
options in Android to do this. But for your purpose AsyncTask might
be useful. Connect to your server, fetch and parse data in the
doInBackground method of AsyncTask and once the task is complete,
let onPostExecute publish the same to the Main thread.
Step 3 - Once you get back the result from the Async task, you may
dismiss the progress dialog and continue with whatever you were doing.
Please note that the main thread should not be blocked at any time. This is the event handling thread of the app and handles all events (User initiated or system initiated). If the thread is blocked, you get the kind of error you are seeing now. Specifically in your case, Android system is not able to do some draw operations because of the while loop.
Create a new Asynctask and run the socket establisment codes inside it :)
socket = new Socket(hostname, portnumber);
I'm developing an Android application which is checking handoff performance. It should be playing sound/notification during call (when handoff has performed), but only audible for me. I know that it's impossible to play sound for both sides, but my case is different. Sometimes during call we can hear incoming sms notification or something like that. So it can be done.
I have created testing infinite loop which is playing sound during call, but it's not working. Sound is playing only after call. There is some piece of my code below:
private PhoneStateListener callListener = new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber) {
try {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
System.out.println("Polaczenie przychodzace");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
System.out.println("Polaczenie wychodzace");
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
while(true)
{
r.play();
}
case TelephonyManager.CALL_STATE_IDLE:
break;
default:
}
} catch (Exception e) {
}
}
};
What should I change?
I'm experiencing an issue managing threads on .Net 4.0 C#, and my knowledge of threads is not sufficient to solve it, so I've post it here expecting that somebody could give me some piece of advise please.
The scenario is the following:
We have a Windows service on C# framework 4.0 that (1)connects via socket to a server to get a .PCM file, (2)then convert it to a .WAV file, (3)send it via Email - SMTP and finally (4)notify the initial server that it was successfully sent.
The server where the service had been installed has 8 processors and 8 GB or RAM.
To allow multiprocessing I've built the service with 4 threads, each one of them performs each task I mentioned previously.
On the code, I have classes and methods for each task, so I create threads and invoke methods as follows:
Thread eachThread = new Thread(object.PerformTask);
Inside each method I'm having a While that checks if the connection of the socket is alive and continue fetching data or processing data depending on their porpuse.
while (_socket.Connected){
//perform task
}
The problem is that as more services are being installed (the same windows service is replicated and pointed between two endpoints on the server to get the files via socket) the CPU consumption increases dramatically, each service continues running and processing files but there is a moment were the CPU consumption is too high that the server just collapse.
The question is: what would you suggest me to handle this scenario, I mean in general terms what could be a good approach of handling this highly demanded processing tasks to avoid the server to collapse in CPU consumption?
Thanks.
PS.: If anybody needs more details on the scenario, please let me know.
Edit 1
With CPU collapse I mean that the server gets too slow that we have to restart it.
Edit 2
Here I post some part of the code so you can get an idea of how it's programmed:
while(true){
//starting the service
try
{
IPEndPoint endPoint = conn.SettingConnection();
string id = _objProp.Parametros.IdApp;
using (socket = conn.Connect(endPoint))
{
while (!socket.Connected)
{
_log.SetLog("INFO", "Conectando socket...");
socket = conn.Connect(endPoint);
//if the connection failed, wait 5 seconds for a new try.
if (!socket.Connected)
{
Thread.Sleep(5000);
}
}
proInThread = new Thread(proIn.ThreadRun);
conInThread = new Thread(conIn.ThreadRun);
conOutThread = new Thread(conOut.ThreadRun);
proInThread.Start();
conInThread.Start();
conOutThread.Start();
proInThread.Join();
conInThread.Join();
conOutThread.Join();
}
}
}
Edit 3
Thread 1
while (_socket.Connected)
{
try
{
var conn = new AppConection(ref _objPropiedades);
try
{
string message = conn.ReceiveMessage(_socket);
lock (((ICollection)_queue).SyncRoot)
{
_queue.Enqueue(message);
_syncEvents.NewItemEvent.Set();
_syncEvents.NewResetEvent.Set();
}
lock (((ICollection)_total_rec).SyncRoot)
{
_total_rec.Add("1");
}
}
catch (SocketException ex)
{
//log exception
}
catch (IndexOutOfRangeException ex)
{
//log exception
}
catch (Exception ex)
{
//log exception
}
//message received
}
catch (Exception ex)
{
//logging error
}
}
//release ANY instance that could be using memory
_socket.Dispose();
log = null;
Thread 2
while (_socket.Connected)
{
try{
_syncEvents.NewItemEventOut.WaitOne();
if (_socket.Connected)
{
lock (((ICollection)_queue).SyncRoot)
{
total_queue = _queue.Count();
}
int i = 0;
while (i < total_queue)
{
//EMail Emails;
string mail = "";
lock (((ICollection)_queue).SyncRoot)
{
mail = _queue.Dequeue();
i = i + 1;
}
try
{
conn.SendMessage(_socket, mail);
_syncEvents.NewResetEvent.Set();
}
catch (SocketException ex)
{
//log exception
}
}
}
else
{
//log exception
_syncEvents.NewAbortEvent.Set();
Thread.CurrentThread.Abort();
}
}
catch (InvalidOperationException e)
{
//log exception
}
catch (Exception e)
{
//log exception
}
}
//release ANY instance that could be using memory
_socket.Dispose();
conn = null;
log = null;
Thread 3
while (_socket.Connected)
{
int total_queue = 0;
try
{
_syncEvents.NewItemEvent.WaitOne();
lock (((ICollection) _queue).SyncRoot)
{
total_queue = _queue.Count();
}
int i = 0;
while (i < total_queue)
{
if (mgthreads.GetThreatdAct() <
mgthreads.GetMaxThread())
{
string message = "";
lock (((ICollection) _queue).SyncRoot)
{
message = _queue.Dequeue();
i = i + 1;
}
count++;
lock (((ICollection) _queueO).SyncRoot)
{
app.SetParameters(_socket, _id,
message, _queueO, _syncEvents,
_total_Env, _total_err);
}
Thread producerThread = new
Thread(app.ThreadJob) { Name =
"ProducerThread_" +
DateTime.Now.ToString("ddMMyyyyhhmmss"),
Priority = ThreadPriority.AboveNormal
};
producerThread.Start();
producerThread.Join();
mgthreads.IncThreatdAct(producerThread);
}
mgthreads.DecThreatdAct();
}
mgthreads.DecThreatdAct();
}
catch (InvalidOperationException e)
{
}
catch (Exception e)
{
}
Thread.Sleep(500);
}
//release ANY instance that could be using memory
_socket.Dispose();
app = null;
log = null;
mgthreads = null;
Thread 4
MessageVO mesVo =
fac.ParseMessageXml(_message);
I would lower the thread priority and have all threads pass through a Semaphore that limits concurrency to Environment.ProcessorCount. This not a perfect solution but it sounds like it is enough in this case and an easy fix.
Edit: Thinking about it, you have to fold the 10 services into one single process because otherwise you won't have centralized control about the threads that are running. If you have 10 independent processes they cannot coordinate.
There should normally be no collapse because of high cpu usage. While any of the threads is waiting for something remote to happen (for instance for the remote server to response to the request), that thread uses no cpu resource. But while it is actually doing something, it uses cpu accordingly. In the Task you mentioned, there is no inherent high cpu usage (as the saving of PCM file as WAV requires no complex algorithm), so the high cpu usage seems to be a sign of an error in programming.