Reputation: 310
I am using Android Studio and I am a little stuck on AsyncTask
My Application is meant to run on RFID scanner and one of the features is to find one specific tag in a warehouse full of tagged items.
So I need to be able to continuously scan and read tags as the device moves around the warehouse and when a match is found, the device makes a sound to alert the user. I get this to work with a loop, but the problem is that I need to allow the user to cancel out of this on the click of a button, which would suggest moving the searching of the tag to an async task.
What I am currently doing is in an onKeyDown event, fire the code that does the reading of tag and update a variable with the tagNumber, then put a loop around the change listener of this variable to to pull the tag number on this event, if the result is unsuccessful (no match) call re-fire the keydown event and repeat the process until a match is found.
public boolean onKeyDown(int keyCode, KeyEvent event) {
while (Scan.equals("true")) {
try {
// ReadAction.onStart();
if ((keyCode == KeyEvent.KEYCODE_SOFT_RIGHT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT
|| keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_F7 || keyCode == KeyEvent.KEYCODE_F8) && event.getRepeatCount() <= 0
&& ReadAction.mReader.getAction() == ActionState.Stop && ReadAction.mReader.getState() == ConnectionState.Connected) {
ATLog.i(TAG, "INFO. onKeyDown(%d, %d)", keyCode, event.getAction());
mElapsedTick = SystemClock.elapsedRealtime() - mTick;
if (mTick == 0 || mElapsedTick > SKIP_KEY_EVENT_TIME) {
startAction();
mTick = SystemClock.elapsedRealtime();
} else {
ATLog.e(TAG, "INFO. Skip key down event(elapsed:" + mElapsedTick + ")");
return super.onKeyDown(keyCode, event);
}
final String SearchedTagNo = getScannedTag();
ReadAction.setListener(new BaseReadAction.ChangeListener() {
@Override
public void onChange() {
if (Scan.equals("true")) {
String scannedTag= ReadAction.getEpcNo();
if (!SearchedTagNo .equals(scannedTag)) {
onKeyDown(2, keyEvent);
} else if (SearchedTagEPC.equals(EPCTag)) {
//indicate success to user on screen and by sound
mSound.playSuccess();
txtSearchResult.setText(" Found in this Area");
}
}
}
});
return true;
}
} catch (Exception e) {
logWork.AppendLog("ERROR: " + e.getMessage() + " m_KeyDown(), a_AssignTag");
Toast.makeText(Search_Activity.this, e.getMessage().toString(),
Toast.LENGTH_LONG).show();
}
}
return super.onKeyDown(keyCode, event);
}
I wanted to call this onKeyDown method/event from the doInBackground method in the async class, but it failed and from what I read it is not possible to access UI items in an async task/method
Alternatives that I have read up on were to put it in the onProgressUpdate method of the AsyncTask
class and call publish progress from doInBackground, but that did not work for me either.
class AsyncSearch extends AsyncTask <Void, Void, Void> {
KeyEvent keyEvent;
Search_Activity searchActivity = new Search_Activity(); //thinking this is causing the problem
public AsyncSearch() {
keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 2);
}
@Override
protected Void doInBackground(Void... params) {
try {
//calling onProgressUpdate to fire, and placing code that needs access to UI thread in the onProgressUpdate method
//because you cannot instantiate a class in a background worker.
publishProgress();
} catch (Exception e) {
throw e;
}
return null;
}
@Override
protected void onProgressUpdate(Void... values) {
//calls the onKeyDown event in Search_Activity Asynchornously
searchActivity.onKeyDown(2, keyEvent);
}
There is no equivalent for IsInvokeRequired like one would use in .net, that I could find anyway...
Is there a workaround I have not yet stumbled across? should I just change the approach to this problem altogether? Not sure how I can keep this search running and listen to the Cancel click event to cancel out of this search "loop"
Upvotes: 1
Views: 149
Reputation: 410
I already had this doubt one day and I was not finding a solution for that (I was getting crazy), so I found the solution reading the android developer official guide. I noticed I was doing something like your question and I was on the wrong road, cause any looping running on the currently Activity will always blocks the UI interation.
Solution:
The solution for this problem is creat at least two runnable classes (extends Threads), to be both runnable in a new Thread different from the currently Activity.
Create the first runnable class only to management the lifecycle of the connection and another to exchange of messages between the rfid devices and the smartphone.
I recommend you to study this simple BluetoothChat example and maybe you will have your questions answered.
Upvotes: 2
Reputation: 37584
I can give you a generic answer on how to approach the issue since I implemented something similar for rfid devices. First of all I suppose you have a Bluetooth connection something a long the lines of the android developer bluetooth guide. If you implement it like that you can read/write into the socket whatever and whenever you want. It is not Activity dependent and runs alongside the application.
Even if your application does not use Bluetooth it still can use the same structure with a SocketThread
and a ConnectorThread
. For communication purpose you either use the android.os.Handler
or something like EventBus.
Do not try to hard-wire any Activity
like that. Rather let the Activity
implement an Interface
to control/listen the connection between the devices.
Upvotes: 0