Android - Cannot make a static reference to a non static method - android

I refactoring my threads in order to avoid memory leaks, and I got 2 errors regarding handler and startActivityForResult being called from within the thread ( dealing with GoogleDrive)
I have in my DownloadActivity :
public class DownloadActivity extends Activity {
....
private void getFolderId(){
getFolderIdThread = new GetFolderIdThread();
getFolderIdThread.start();
}
private static class GetFolderIdThread extends Thread {
private Boolean mRunning = false;
#Override
public void run() {
mRunning = true;
fResultList = new ArrayList<File>();
Files f1 = mService.files();
Files.List request = null;
aFolderId = null;
do {
try {
request = f1.list();
String aQuery = "'root' in parents and mimeType='application/vnd.google-apps.folder' and title='"+ aFolderName + "'";
request.setQ(aQuery);
FileList fileList = request.execute();
fResultList.addAll(fileList.getItems());
request.setPageToken(fileList.getNextPageToken());
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION); <= THIS RAISES THE ERROR
} catch (IOException e) {
e.printStackTrace();
if (request != null){
request.setPageToken(null);
}
}
} while (request.getPageToken() !=null && request.getPageToken().length() > 0);
if (fResultList.size() == 0) {
Log.d(TAG, "cannot find the training folder at root level");
Message msg = handler.obtainMessage(); <= THIS RAISES THE ERROR
Bundle bundle = new Bundle();
bundle.putInt("msgKey", DownloadActivity.NO_TRAININGS_FOLDER);
msg.setData(bundle);
handler.sendMessage(msg); <= THIS RAISES THE ERROR
} else {
File folder = fResultList.get(0);
aFolderId = folder.getId();
getFolderContents(); <= THIS RAISES THE ERROR
}
}
public void close() {
mRunning = false;
}
}
I have the handler defined in my activity
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
...
}
}
and the onActivityResult
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_ACCOUNT_PICKER:
....
break;
}
}
what are my options to bypass this error ?

Your GetFolderIdThread class is static and a static nested class cannot reference non-static methods and fields in the instance of the outer class that created it. Such a nested class can only access static methods and fields in your Activity. Remove static from the class definition and I think your problem will resolve.
You also need to post your call to startActivityForResult on the UI thread. Of course you should be able to use your handler for that, something like:
handler.post(new Runnable()
{
public void run()
{
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
}
});
Make sure your thread can gracefully complete as well when you do that because it will continue to run.

Related

NFC tag(for NfcA) scan works only from the second time

I wrote a custom plugin to read blocks of data from an NfcA(i.e.non-ndef) tag. It seems to work fine , but only after the second scan. I am using Activity intent to derive the "NfcAdapter.EXTRA_TAG" to later use it for reading the values. I am also updating the Intents in onNewIntent(). OnNewIntent gets called after the second scan and after that I get result all the time.But in the first scan onNewIntent does not gets called, hence I end up using the Activity tag that does not have "NfcAdapter.EXTRA_TAG", hence I get null. Please see the my code below.
SE_NfcA.java(my native code for plugin)
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
String Result = "";
String TypeOfTalking = "";
if (action.contains("TalkToNFC"))
{
JSONObject arg_object = args.getJSONObject(0);
TypeOfTalking = arg_object.getString("type");
if(TypeOfTalking != "")
{
if (TypeOfTalking.contains("readBlock"))
{
if(TypeOfTalking.contains("#"))
{
try
{
String[] parts = TypeOfTalking.split("#");
int index = Integer.parseInt(parts[1]);
Result = Readblock(cordova.getActivity().getIntent(),(byte)index);
callbackContext.success(Result);
}
catch(Exception e)
{
callbackContext.error("Exception Reading "+ TypeOfTalking + "due to "+ e.toString());
return false;
}
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
return true;
}
#Override
public void onNewIntent(Intent intent) {
ShowAlert("onNewIntent called");
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
super.onNewIntent(intent);
getActivity().setIntent(intent);
savedTag = tagFromIntent;
savedIntent = intent;
}
#Override
public void onPause(boolean multitasking) {
Log.d(TAG, "onPause " + getActivity().getIntent());
super.onPause(multitasking);
if (multitasking) {
// nfc can't run in background
stopNfc();
}
}
#Override
public void onResume(boolean multitasking) {
Log.d(TAG, "onResume " + getActivity().getIntent());
super.onResume(multitasking);
startNfc();
}
public String Readblock(Intent Intent,byte block) throws IOException{
byte[] response = new byte[]{};
if(Intent != null)
{
Tag myTag = Intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(savedTag != null)
myTag = savedTag;
if(myTag != null)
{
try{
Reader nTagReader = new Reader(myTag);
nTagReader.close();
nTagReader.connect();
nTagReader.SectorSelect(Sector.Sector0);
response = nTagReader.fast_read(block, block);
nTagReader.close();
return ConvertH(response);
}catch(Exception e){
ShowAlert(e.toString());
}
}
else
ShowAlert("myTag is null.");
}
return null;
}
private void createPendingIntent() {
if (pendingIntent == null) {
Activity activity = getActivity();
Intent intent = new Intent(activity, activity.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
}
}
private void startNfc() {
createPendingIntent(); // onResume can call startNfc before execute
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null && !getActivity().isFinishing()) {
try {
nfcAdapter.enableForegroundDispatch(getActivity(), getPendingIntent(), getIntentFilters(), getTechLists());
if (p2pMessage != null) {
nfcAdapter.setNdefPushMessage(p2pMessage, getActivity());
}
} catch (IllegalStateException e) {
// issue 110 - user exits app with home button while nfc is initializing
Log.w(TAG, "Illegal State Exception starting NFC. Assuming application is terminating.");
}
}
}
});
}
private void stopNfc() {
Log.d(TAG, "stopNfc");
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null) {
try {
nfcAdapter.disableForegroundDispatch(getActivity());
} catch (IllegalStateException e) {
// issue 125 - user exits app with back button while nfc
Log.w(TAG, "Illegal State Exception stopping NFC. Assuming application is terminating.");
}
}
}
});
}
private Activity getActivity() {
return this.cordova.getActivity();
}
private PendingIntent getPendingIntent() {
return pendingIntent;
}
private IntentFilter[] getIntentFilters() {
return intentFilters.toArray(new IntentFilter[intentFilters.size()]);
}
private String[][] getTechLists() {
//noinspection ToArrayCallWithZeroLengthArrayArgument
return techLists.toArray(new String[0][0]);
}
}
My index.js file
nfc.addTagDiscoveredListener(
function(nfcEvent){
console.log(nfcEvent.tag.id);
alert(nfcEvent.tag.id);
window.echo("readBlock#88");//call to plugin
},
function() {
alert("Listening for NFC tags.");
},
function() {
alert("NFC activation failed.");
}
);
SE_NfcA.js(plugin interface for interaction b/w index.js and SE_NfcA.java)
window.echo = function(natureOfTalk)
{
alert("Inside JS Interface, arg =" + natureOfTalk);
cordova.exec(function(result){alert("Result is : "+result);},
function(error){alert("Some Error happened : "+ error);},
"SE_NfcA","TalkToNFC",[{"type": natureOfTalk}]);
};
I guess I have messed up with the Intents/Activity Life-Cycle, please help. TIA!
I found a tweak/hack and made it to work.
Before making any call to read or write, I made one dummy Initialize call.
window.echo("Initialize");
window.echo("readBlock#88");//call to plugin to read.
And in the native code of the plugin, on receiving the "Initialize" token I made a startNFC() call.
else if(TypeOfTalking.equalsIgnoreCase("Initialize"))
{
startNfc();
}

Runnable is getting blocked, why is this happening? ANDROID

I am making an inhouse navigation application with google glass. I am sending orientation data from the google glass to the android phone true WIFI (SOCKETS). My code is running fine and ok, but after about 25 seconds the receiving thread (on the phone) stops for 5 seconds and then continues, this is very annoying.
I tested this by closing the connection (when i see the thread becoming unresponsive) and it takes 5 seconds for the debugger to hit the breakpoint that i set in the application (obviously this is the thread that is causing the problem)
The weird thing is that the UI thread is still responsive i can move every object in the activity, it is just the specific thread containing the connection (Socket) that is getting blocked. I will post the code (i suspect memory leak) so that maybe someone can give me a indication why this could be happening, any advice is welcome.
CHANGED CODE AFTER COMMENT:
public class GlassOrientationSocket implements Runnable {
private final static int PORT = 6604;
private static Socket mClientSocket;
private static String mResult;
private static Handler handler = null;
private static boolean threadIsRunning;
private static BufferedReader inputReader;
public GlassOrientationSocket(Handler handler) {
this.handler = handler;
this.threadIsRunning = true;
}
public void terminateThread() {this.threadIsRunning = false;}
#SuppressWarnings("deprecation")
#Override
public void run() {
//Replace this with ip-address of android server (aka Google glass) // put ip on NFC TAG for easier configuration
String ServerIP = SECRET;
//port should be same as ServerSocketActivity
try {
mClientSocket = new Socket(serverIP, PORT);
inputReader = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
int angleCutter;
int orientationCutter;
float[] results = new float[2];
while(threadIsRunning)
{
if (((mResult = inputReader.readLine()) != null)) {
angleCutter = mResult.indexOf("|", 0);
orientationCutter = mResult.indexOf("|", angleCutter + 1);
results[0] = Float.valueOf(mResult.substring(0, angleCutter));
results[1] = Float.valueOf(mResult.substring(angleCutter + 1, orientationCutter));
Message msg = new Message();
msg.arg1 = 1;
msg.obj = results;
handler.sendMessage(msg);
} else {
if (mClientSocket != null) mClientSocket.close();
Message msg = new Message();
msg.arg1 = 2;
handler.sendMessage(msg);
threadIsRunning = false;
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}}
////
public class CompassMonitor {
static protected ArrayList<CompassListener> listeners=new ArrayList<CompassListener>();
static protected GlassOrientationSocket monitor=null;
private static Handler msgHandler = new Handler();
private static CompassListener orientationListener;
private static float[] dataReturned = new float[2];
static public synchronized void registerListener(Context context,CompassListener listener){
if(listeners.size()==0){
orientationListener = listener;
monitor=new GlassOrientationSocket(msgHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.arg1) {
case 1:
dataReturned = (float[])msg.obj;
notifyListeners(dataReturned[0],dataReturned[1],"Useless Parameter");
break;
case 2:
unregisterListener(orientationListener);
monitor.terminateThread();
}
}
});
Thread t = new Thread(monitor);
t.start();
}
listeners.add(listener);
}
static synchronized public void unregisterListener(CompassListener listener){
if (listeners != null && listener != null)
listeners.remove(listener);
}
static synchronized protected void notifyListeners(float azimuth,float angle, String direction){
for(CompassListener l:listeners){
try{
l.onCompassChanged(azimuth,angle,direction);
}catch(Exception ex){}
}
}}

Android: Background thread in Singleton class

I have Singleton class which holds all the data (visitors of some site) and the data is updated by a service. I have an interface, which is implemented by an (list) activity (which shows visitors), so now as I get the data updated, I simply call the interface method so that the list activity can refresh it.
Now I need to maintain the time visitors are on site (at client end). I want to make a thread in Singleton class which will run a loop after every second, but I am not able to call any method on Main thread, using Handlers.
Here's the code of thread:
void startHeavyDutyStuff() {
Thread t = new Thread() {
public void run() {
try {
while(true) {
sleep(1000);
ArrayList<VisitorMC> data = SharedAppManager.appManager().visitorsData;
boolean doReload = false;
for (VisitorMC item: data) {
item.secsOnSite++;
if(item.secsOnSite == 60) {
item.secsOnSite = 0;
item.minsOnSite++;
doReload = true;
}
}
if(doReload) {
messageHandler.sendEmptyMessage(1);
} else {
messageHandler.sendEmptyMessage(0);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
}
And here's the code where I am making the Handler on Main Thread (in Singleton class):
private SharedAppManager() {
//Initialization of the data.
Looper.prepare();
messageHandler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what) {
case 0:
Log.d("THREAD", "after every second");
break;
case 1:
if(visitorsDelegate != null) {
visitorsDelegate.updateVisitorsTime();
}
break;
default:
}
}
};
startHeavyDutyStuff();
}
What am I doing wrong here?
Edit:
I need to update the UI after each second, that's why I am running a separate thread which could change the Data and call update on UI.

Make sure that my code is thread safe

I am doing an Android service that gives content to other apps that can register as callback.
I am not 100% sure about how the Android Handler class works, so can someone confirm me that this code is thread safe?
public class MyService extends Service {
private static final String MESSAGE = "message";
private final RemoteCallbackList<IMyCallback> readerCallbacks = new RemoteCallbackList<IMyCallback>();
private static final int REPORT_MSG = 1;
private Thread readerThread;
#Override
public void onCreate() {
readerThread = new Thread(readerRunnable);
readerThread.setDaemon(true);
readerThread.start();
}
private Runnable readerRunnable = new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
// Blocking call
byte[] message = JniCommunicator.readMessage();
if (message == null || message.length == 0) {
continue;
}
Bundle b = new Bundle();
b.putByteArray(MESSAGE, message);
Message m = readHandler.obtainMessage(REPORT_MSG);
m.setData(b);
readHandler.sendMessage(m);
}
}
};
private final Handler readHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case REPORT_MSG:
byte[] message = msg.getData().getByteArray(MESSAGE);
// Broadcast the new message to all clients
final int N = readerCallbacks.beginBroadcast();
for (int i = 0; i < N; i++) {
try {
readerCallbacks.getBroadcastItem(i).newMessage(message);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
readerCallbacks.finishBroadcast();
break;
}
}
};
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IService.Stub mBinder = new IService.Stub() {
public void registerCallback(IMyCallback cb) {
if (cb != null)
readerCallbacks.register(cb);
}
public void unregisterCallback(IMyCallback cb) {
if (cb != null)
readerCallbacks.unregister(cb);
}
};
}
In particular, if someone calls unregisterCallback() while the Handler is in the for loop, will it crash?
From my understanding, the Handler run in the same thread, so it is thread safe, but I am not sure.
Thanks
Handlers are thread safe, that is their entire purpose.
I'll agree that the documentation on the thread safety of handlers isn't the best but it would be very ironic if a class designed to communicate between thread weren't thread safe.
About the remote callbacks, they are also designed to be thread safe, you should read the documentation on this, it states clearly:
Performs locking of the underlying list of interfaces to deal with multithreaded incoming calls, and a thread-safe way to iterate over a snapshot of the list without holding its lock
All you have to make sure is that all variables multiple thread access are thread safe (which they are in your case) and that they aren't being changed (yours are final so no worries there either)

Android 2.2: ProgressDialog Freezing In Second Thread

I have recently experimented with creating an easy way to open a ProgressDialog up in a second thread, so if the main thread freezes the dialog will keep working.
Here is the class:
public class ProgressDialogThread extends Thread
{
public Looper ThreadLooper;
public Handler mHandler;
public ProgressDialog ThreadDialog;
public Context DialogContext;
public String DialogTitle;
public String DialogMessage;
public ProgressDialogThread(Context mContext, String mTitle, String mMessage)
{
DialogContext = mContext;
DialogTitle = mTitle;
DialogMessage = mMessage;
}
public void run()
{
Looper.prepare();
ThreadLooper = Looper.myLooper();
ThreadDialog = new ProgressDialog(DialogContext);
ThreadDialog.setTitle(DialogTitle);
ThreadDialog.setMessage(DialogMessage);
ThreadDialog.show();
mHandler = new Handler();
Looper.loop();
}
public void Update(final String mTitle, final String mMessage)
{
while(mHandler == null)
synchronized(this) {
try { wait(10); }
catch (InterruptedException e) {
Log.d("Exception(ProgressDialogThread.Update)", e.getMessage() == null ? "MISSING MESSAGE" : e.getMessage());
}
}
mHandler.post(new Runnable(){
#Override
public void run() {
ThreadDialog.setTitle(mTitle);
ThreadDialog.setMessage(mMessage);
}});
}
public void Dismiss()
{
while(ThreadDialog == null || mHandler == null)
synchronized(this) {
try { wait(10); }
catch (InterruptedException e) {
Log.d("Exception(ProgressDialogThread.Dismiss)", e.getMessage() == null ? "MISSING MESSAGE" : e.getMessage());
}
}
mHandler.post(new Runnable(){
#Override
public void run() {
ThreadDialog.dismiss();
}});
}
public void Continue()
{
while(ThreadLooper == null || mHandler == null)
synchronized(this) {
try { wait(10); }
catch (InterruptedException e) {
Log.d("Exception(ProgressDialogThread.Continue)", e.getMessage() == null ? "MISSING MESSAGE" : e.getMessage());
}
}
mHandler.post(new Runnable(){
#Override
public void run() {
ThreadLooper.quit();
}});
}
However it sometimes work perfectly but other times the application simply freezes and crashes eventually.
Here is an example of use:
ProgressDialogThread thread = new ProgressDialogThread(this, "Loading", "Please wait...");
thread.start();
// Do Stuff
thread.Dismiss();
thread.Continue();
It generates a lot of warning and even some crashes sometimes:
eg.
Handler: Sending message to dead thread....
and exceptions like
ANR in ......
Reason: keyDispatchingTimedOut
Thanks for any help,
Alex.
When wanting to do stuff in separate threads on Android, you should look at the AsyncTask class. You can read about it here: http://developer.android.com/resources/articles/painless-threading.html
Googling (or searching here on Stack Overflow) will also give you plenty of information on how to use it it the above link isn't sufficient :)

Categories

Resources