Guarantee only one timerTasks with threads in service - android

My Android application has a service, that will be created at timer task with specified interval. The task should check out webservice by async task, if the Internet is enabled, send some informations, otherwise it should wait (for example, 5 seconds) and check connection again.
My problem is: how to prevent creating tasks while timertask is waiting?
I wish that at any time there is only one task working.
My code:
mTimer.scheduleAtFixedRate(new MyTask(), 0, 10000); //creating tasks in service
class MyTask extends TimerTask {
#Override
public void run() {
if (!isLocked) {
new Thread(new Runnable() {#Override
public void run() {
isLocked = true;
if (!isInternet) {
do {
Log.v("TestService", "Waiting...");
SystemClock.sleep(5000);
isInternet = getInternetConn();
} while (!isInternet);
} else {
//do work
}
isLocked = false;
}).run();
}
}
}

I would suggest you to follow this process, which i have used for getting GCM_Registration id, same as you can use it check your internet connection.
which works like : in onStartCommand(), mServiceHandler.sendMessage(msg); starts a asynctask which check does we have GCM-ID if yes we stop the service and if no, then we again check for GCM-ID by asynctask.
package com.urbanft.utils;
import java.io.IOException;
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.text.TextUtils;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.urbanft.app.GlobalPreference;
public class GCMIdFetchService extends Service {
private final String SENDER_ID = "916449540455";
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private static final long INTERVAL = 1000;
private GoogleCloudMessaging mGoogleCloudMessaging;
private String mRegisterationId;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg){
new GCMIdFetchSearviceTask().execute("");
}
}
protected void initialization() {
mGoogleCloudMessaging = GoogleCloudMessaging.getInstance(getApplicationContext());
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments",Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
}
class GCMIdFetchSearviceTask extends AsyncTask<String, String, String>{
#Override
protected String doInBackground(String... params) {
getGCMID();
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
String gcmId = GlobalPreference.getInstance(getApplicationContext()).getGCMRegistrationId();
if(!TextUtils.isEmpty(gcmId)){
stopSelf();
return;
}
new Handler().postDelayed(new Runnable() {
public void run() {
Message msg = mServiceHandler.obtainMessage();
mServiceHandler.sendMessage(msg);
}
}, INTERVAL);
}
}
private void getGCMID() {
try{
if(mGoogleCloudMessaging == null){
mGoogleCloudMessaging = GoogleCloudMessaging.getInstance(getApplicationContext());
}
mRegisterationId = mGoogleCloudMessaging.register(SENDER_ID);
GlobalPreference.getInstance(getApplicationContext()).setGCMRegistrationId(mRegisterationId);
}
catch (IOException err){
err.printStackTrace();
}
}
}

Related

Wait for TextToSpeech onInit() initialization on Android

I am writing a text-to-speech android application. I am refactoring the code and trying to separate TextToSpeech class from an activity to a service so the UI can be updated without blocking, while the audio is playing in the background. However I am not able to wait for the TTS engine to initialize.
When I use
while(isInit==false)
Thread.sleep(1000);
the service never calls the onServiceConnected method.
If anybody knows how to wait for initialization of the TTS engine to complete, and avoid blocking the UI for too long (which causes the application to crash), help would be greatly appreciated!
Here is my service
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import java.util.HashMap;
import java.util.Locale;
public class MyTTSService extends Service {
private static final String TAG = "Class-MyTTSService";
private TextToSpeech tts;
private boolean isInit = false;
private final IBinder myBinder = new MyBinder();
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Creating TTS Service");
Context context = this.getApplicationContext();
this.tts = new TextToSpeech(context, onInitListener);
this.tts.setOnUtteranceProgressListener(utteranceProgressListener);
Log.d(TAG, "TTS Service Created");
// why is this blocking everything?
while(!isInitComplete()){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.d(TAG, e.toString());
}
}
}
public boolean isInitComplete(){
return isInit;
}
#Override
public void onDestroy() {
// Don't forget to shutdown tts!
if (tts != null) {
tts.stop();
tts.shutdown();
}
super.onDestroy();
}
public void waitToFinishSpeaking() {
while (tts.isSpeaking()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Log.d(TAG, e.toString());
}
}
}
public void speak(String text, AppCompatActivity appCompatActivity) {
Log.d(TAG, "Speak" + text);
appCompatActivity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
HashMap<String, String> param = new HashMap<>();
param.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_MUSIC));
tts.speak(text, TextToSpeech.QUEUE_ADD, null);
} else {
String utteranceId=this.hashCode() + "";
Bundle bundle = new Bundle();
bundle.putInt(TextToSpeech.Engine.KEY_PARAM_STREAM, AudioManager.STREAM_MUSIC);
tts.speak(text, TextToSpeech.QUEUE_ADD, null, null);
}
}
private UtteranceProgressListener utteranceProgressListener = new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
}
#Override
public void onDone(String utteranceId) {
}
#Override
public void onError(String utteranceId) {
Log.e(TAG, "Error while trying to synthesize sample text");
}
};
private TextToSpeech.OnInitListener onInitListener = new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e("TTS", "This Language is not supported");
} else {
//init success
isInit = true;
Log.d(TAG, "TTS Initialized.");
}
} else {
Log.e("TTS", "Initilization Failed!");
}
}
};
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "Binding TTS Service");
return myBinder;
}
public class MyBinder extends Binder {
MyTTSService getService() {
return MyTTSService.this;
}
}
#Override
public boolean onUnbind(Intent intent) {
return false;
}
}
And here is my activity
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
import android.widget.TextView;
import java.util.ArrayList;
public class ReaderActivity extends AppCompatActivity {
private static final String TAG = "Class-ReaderActivity";
EditText textBox;
ArrayList<String> sentences = new ArrayList<String>();
MyTTSService tts;
boolean isBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reader);
textBox = (EditText) findViewById(R.id.readerTextArea);
Intent intentExtras = getIntent();
Bundle extrasBundle = intentExtras.getExtras();
sentences = extrasBundle.getStringArrayList("sentences");
textBox.setText(sentences.toString(), TextView.BufferType.NORMAL);
textBox.setKeyListener(null);
}
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MyTTSService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Log.d(TAG, "Waiting to bind to service");
}
public void readSentences(){
for(String sentence : sentences){
Log.d(TAG +"Sencence", sentence);
//updateUI(sentence);
tts.speak(sentence, this);
tts.waitToFinishSpeaking();
}
}
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyTTSService.MyBinder binder = (MyTTSService.MyBinder) service;
tts = binder.getService();
isBound = true;
readSentences();
}
#Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
}
I found the solution. Remove the existing wait loop from MyTTSService.onCreate().
Place the following at the end of the onServiceConnected method
new Thread(new Runnable() {
public void run(){
readSentences();
}
}).start();
Then add a method to MyTTSService
public boolean isInit(){
return isInit;
}
In some circumstances the tts module may need to be reinitialised. Add the following to TextToSpeech.OnInitListener.OnInit in the cases where initialisation is unsuccessful.
isInit = false;
Then finally add the following to the readsentences method
while(!tts.isInit()){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.d(TAG, e.toString());
}
}
tts.speak(sentence, this);
With these changes the TTS module initialises, audio works, the Activity loads and the UI can be refreshed while audio is playing.
This should finally put the issue (which has been asked several times but never resolved) to bed for good.

How to receive Messages in chat App using signalR in Android

hello i am new in signalR i am making one chating app with using signalR i take reference from SignalR integration in android studio here with the help of this i able to send the messages to the chat group but i am not able to receive messages i read lots of Q&A here but i am not able to solve this problem i paste here my code and please anyone tell me how do i receive message from the server.following is my code.
Activity main
package myapp.chatapp;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.Toast;
import com.google.gson.JsonElement;
import java.util.ArrayList;
import microsoft.aspnet.signalr.client.MessageReceivedHandler;
import microsoft.aspnet.signalr.client.Platform;
import microsoft.aspnet.signalr.client.http.android.AndroidPlatformComponent;
import microsoft.aspnet.signalr.client.hubs.HubConnection;
import microsoft.aspnet.signalr.client.hubs.HubProxy;
import microsoft.aspnet.signalr.client.hubs.SubscriptionHandler2;
import microsoft.aspnet.signalr.client.transport.ClientTransport;
import microsoft.aspnet.signalr.client.transport.LongPollingTransport;
public class MainActivity extends AppCompatActivity implements SignalRService.Something {
private StringBuilder mLog;
private ListView mTestCaseList;
private Spinner mTestGroupSpinner;
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private final Context mContext = this;
private SignalRService mService;
private SignalRService mMessageResive;
private boolean mBound = false;
ListView list_item;
EditText editText;
ArrayList<String> listItems;
ArrayAdapter<String> adapter;
ClientTransport transport;
private Handler mHandler; // to display Toast message
private Thread t;
#Override
public void onConfigurationChanged(Configuration newConfig) {
// don't restart the activity. Just process the configuration change
super.onConfigurationChanged(newConfig);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClass(mContext, SignalRService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
editText = (EditText)findViewById(R.id.edit_message);
ImageButton btn = (ImageButton)findViewById(R.id.btn);
list_item = (ListView)findViewById(R.id.list_item);
listItems = new ArrayList<String>();
/*listItems.add("First Item - added on Activity Create");*/
/* adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, listItems);*/
adapter = new ArrayAdapter<String>(mContext,R.layout.custom_list, R.id.textView,listItems);
list_item.setAdapter(adapter);
final Handler handler = new Handler();
handler.postDelayed( new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
handler.postDelayed( this, 1000 );
}
}, 1000 );
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listItems.add(editText.getText().toString());
adapter.notifyDataSetChanged();
sendMessage(view);
}
});
}
#Override
protected void onStop() {
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
super.onStop();
}
public void sendMessage(View view) {
if (mBound) {
String message = editText.getText().toString();
String email = "kn#yopmail.com";
String name = "Kunal From Android";
String group ="1";
mService.sendMessage(name,email,group,message);
editText.setText("");
// Call a method from the SignalRService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
/*EditText editText = (EditText) findViewById(R.id.edit_message);
if (editText != null && editText.getText().length() > 0) {
}*/
}
}
public void setmMessageResive(JsonElement jsonElement)
{
listItems.add(10, String.valueOf(jsonElement));
}
/**
* Defines callbacks for service binding, passed to bindService()
*/
private final ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// We've bound to SignalRService, cast the IBinder and get SignalRService instance
SignalRService.LocalBinder binder = (SignalRService.LocalBinder) iBinder;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
#Override
public void doSomething(String msg) {
listItems.add(msg);
}
}
Service code
package myapp.chatapp;
import android.app.Service;
import android.bluetooth.BluetoothClass;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import com.google.gson.JsonElement;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;
import microsoft.aspnet.signalr.client.Action;
import microsoft.aspnet.signalr.client.Credentials;
import microsoft.aspnet.signalr.client.LogLevel;
import microsoft.aspnet.signalr.client.MessageReceivedHandler;
import microsoft.aspnet.signalr.client.Platform;
import microsoft.aspnet.signalr.client.SignalRFuture;
import microsoft.aspnet.signalr.client.http.Request;
import microsoft.aspnet.signalr.client.http.android.AndroidPlatformComponent;
import microsoft.aspnet.signalr.client.hubs.HubConnection;
import microsoft.aspnet.signalr.client.hubs.HubProxy;
import microsoft.aspnet.signalr.client.hubs.SubscriptionHandler1;
import microsoft.aspnet.signalr.client.hubs.SubscriptionHandler2;
import microsoft.aspnet.signalr.client.hubs.SubscriptionHandler4;
import microsoft.aspnet.signalr.client.transport.ClientTransport;
import microsoft.aspnet.signalr.client.transport.LongPollingTransport;
import microsoft.aspnet.signalr.client.transport.ServerSentEventsTransport;
/**
* Created by NULLPLEX7 on 11/28/2017.
*/
public class SignalRService extends Service {
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private Handler mHandler; // to display Toast message
private final IBinder mBinder = new LocalBinder(); // Binder given to clients
ClientTransport transport;
registerListener registerListener;
private MainActivity setmMessageResive;
public Something list;
public SignalRService() {
}
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler(Looper.getMainLooper());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = super.onStartCommand(intent, flags, startId);
startSignalR();
return result;
}
#Override
public void onDestroy() {
mHubConnection.stop();
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
// Return the communication channel to the service.
startSignalR();
return mBinder;
}
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
public SignalRService getService() {
// Return this instance of SignalRService so clients can call public methods
return SignalRService.this;
}
}
/**
* method for clients (activities)
*/
public void sendMessage(String name, String email, String group, String msg ) {
String SERVER_METHOD_SEND = "BroadCastMessage";
mHubProxy.invoke(SERVER_METHOD_SEND, name,email,group,msg);
}
private void startSignalR() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
Credentials credentials = new Credentials() {
#Override
public void prepareRequest(Request request) {
request.addHeader("User-Name", "BNK");
}
};
String serverUrl = "myurlhere";
mHubConnection = new HubConnection(serverUrl);
mHubConnection.setCredentials(credentials);
String SERVER_HUB_CHAT = "ChatHub";
mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT);
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
mHubProxy.subscribe(this);
transport = new LongPollingTransport(mHubConnection.getLogger());
mHubConnection.start(transport);
/* ****new codes here**** */
/* ****seems useless but should be here!**** */
mHubProxy.subscribe(new Object() {
#SuppressWarnings("unused")
public void newMessage(final String message, final String messageId, final String chatId,
final String senderUserId, final String fileUrl, final String replyToMessageId) {
}
});
try {
signalRFuture.get();
}catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return;
}
mHubProxy.on("receiveGroupMessage",
new SubscriptionHandler4<String, String, String, String>() {
#Override
public void run(final String name,final String msg ,final String avtar,final String date ) {
final String finalMsg = name + " says " + msg;
/*final String finalMsg = msg;*/
// display Toast message
mHandler.post(new Runnable() {
#Override
public void run() {
list.doSomething(msg);
}
});
}
}
, String.class,String.class,String.class,String.class);
mHubConnection.received(new MessageReceivedHandler() {
#Override
public void onMessageReceived(final JsonElement json) {
Log.e("receiveGroupMessage ", json.toString());
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), ""+json, Toast.LENGTH_SHORT).show();
}
});
}
});
}
public interface Something
{
void doSomething(String msg);
}
}
i read on stack overflow that in onMessageReceived i get the server responses but i did not get any response here . I want when any one send message in group from web i want that message in my chat app someone suggest me that i need to create Event listener but i don't no how to create it . please tell me how do i get messages in my chat app.
mHubProxy.on("receiveGroupMessage",
new SubscriptionHandler4<String, String, String, String>() {
#Override
public void run(final String name,final String msg ,final String avtar,final String date ) {
final String finalMsg = name + " says " + msg;
/*final String finalMsg = msg;*/
// display Toast message
mHandler.post(new Runnable() {
#Override
public void run() {
list.doSomething(msg);
}
});
}
}
, String.class,String.class,String.class,String.class);
i thought that i got messages here but execution not go inside the Run.
Any Help is Welcome

IntentService Thread.sleep() limit?

i was wondering if the IntentService has thread blocking limit like calling Thread.sleep(); and if so what's the maximum time limit for it?
so i wrote the following code snippet:
package net.yassin.aaaservice;
import android.app.IntentService;
import android.content.Intent;
import android.os.Handler;
import android.os.SystemClock;
import android.widget.Toast;
public class MyService extends IntentService {
private Thread t;
private static int i = 0;
private static final int SLEEP_DURATION = 2000;
private Handler handler;
public MyService() {
super("MyService");
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
this.handler = new Handler();
}
#Override
protected void onHandleIntent(Intent arg0) {
this.t = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
MyService.this.handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MyService.this,
"This is toast #" + (++i),
Toast.LENGTH_SHORT).show();
}
});
try {
Thread.sleep(SLEEP_DURATION);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
this.t.start();
}
}
and i found that whenever i change the time SLEEP_DURATION constant to over than 2000 Milis the service will stop showing Toasts if i removed the app form the recent menu?
am i right or there is another time limit or behavior ?
thnx :)

Getting NDEF message from tag freezes Android app

I'm trying to read an NDEF message from an NFC tag. The detection of the tag works correctly. For reading the NDEF data from the tag I'm running a TimerTask. The task polls the NDEF message from the tag with getNdefMessage() every 900 ms and updates the UI.
The procedure works perfect until I remove the phone. Than the app freezes without a logcat error message.
Does anyone have an idea why this happens?
package com.example.infcdemo;
import java.io.IOException;
import java.util.Timer;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;
import android.nfc.tech.NfcA;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
public class MainActivity extends Activity
{
protected NfcAdapter mAdapter;
protected PendingIntent mPendingIntent;
protected IntentFilter mIntentfilter;
protected String[][] mTechLists;
protected IntentFilter[] mFilters;
protected NfcA nfca = null;
protected Intent mIntent = null;
protected Tag mTag;
private boolean nfc_initialized = false;
Tag myTag = null;
Ndef _ndef = null;
Timer _incomingMessageTimer;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (nfc_initialized == false)
{
// Initialize NFC Specific
mAdapter = NfcAdapter.getDefaultAdapter(this);
mPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass())
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 1);
IntentFilter ndef = new IntentFilter(
NfcAdapter.ACTION_TAG_DISCOVERED);
mTechLists = new String[][] { new String[] { NfcA.class.getName(), Ndef.class.getName(),
NdefFormatable.class.getName() } };
mFilters = new IntentFilter[] { ndef, };
nfc_initialized = true;
}
}
public void updateIncomingMessage(String msg)
{
TextView txtView = (TextView) findViewById(R.id.txtReceive);
txtView.setText(msg);
}
#Override
protected void onStart()
{
super.onStart();
_incomingMessageTimer = new Timer();
_incomingMessageTimer.schedule(new MessageReceiveTimer(new Handler(), this),0,900);
}
#Override
protected void onStop()
{
super.onStop();
_incomingMessageTimer.cancel();
_incomingMessageTimer.purge();
}
#Override
public void onNewIntent(Intent intent)
{
mIntent = intent;
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action))
{
myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(_ndef != null)
{
try
{
_ndef.close();
_ndef = null;
}
catch (IOException e)
{
e.printStackTrace();
}
}
if(_ndef == null)
{
_ndef = Ndef.get(myTag);
try
{
_ndef.connect();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
#Override
public void onPause()
{
super.onPause();
mAdapter.disableForegroundDispatch(this);
}
#Override
public void onResume()
{
super.onResume();
mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters,
mTechLists);
}
}
//TimerTask Class
package com.example.infcdemo;
import java.util.TimerTask;
import android.nfc.NdefMessage;
import android.os.Handler;
public class MessageReceiveTimer extends TimerTask
{
Handler _handler;
MainActivity _mainActivity;
MessageReceiveTimer(Handler handler, MainActivity mainActivity)
{
super();
_handler = handler;
_mainActivity = mainActivity;
}
#Override
public void run()
{
_handler.post(new Runnable()
{
#Override
public void run()
{
try
{
if(_mainActivity._ndef != null)
{
NdefMessage ndefMsg = null;
if(_mainActivity._ndef.isConnected())
ndefMsg = _mainActivity._ndef.getNdefMessage();
else
ndefMsg = null;
byte[] ndefRecord = ndefMsg.getRecords()[0].getPayload();
String strMsg = new String(ndefRecord, "US-ASCII");
_mainActivity.updateIncomingMessage(strMsg);
}
}
catch (Exception e)
{
return;
}
}
});
}
}
The reason your app blocks when you remove a tag is that you execute IO operations on the tag in your app's main thread (UI thread).
You first create a timer that processes its scheduled tasks in a separate thread
_incomingMessageTimer = new Timer();
^^^^^^^^^^^
_incomingMessageTimer.schedule(new MessageReceiveTimer(new Handler(), this), 0, 900);
^^^^^^^^
However, when the TimerTask executes (on the Timer thread)
public class MessageReceiveTimer extends TimerTask {
#Override
public void run() {
// code excecution happens in the Timer thread
}
}
you immediately return control to the main (UI) thread by posting a Runnable on its message queue:
_handler.post(new Runnable() {
#Override
public void run() {
// code execution happens in the Handler's thread
}
});
The Handler's thread is the main (UI) thread in your case as you created the handler on the main thread:
_incomingMessageTimer.schedule(new MessageReceiveTimer(new Handler(), this),0,900);
^^^^^^^^^^^^^
Consequently the IO operation (_mainActivity._ndef.getNdefMessage()) will block the main thread. Note that the Android documentation explicitly says that this method "must not be called from the main application thread" (see here). The same applies to the connect() method, btw.

How to display toast inside timer?

I want to display toast message inside timer and I used the following code :
timer.scheduleAtFixedRate( new TimerTask()
{
public void run()
{
try {
fun1();
} catch (Exception e) {e.printStackTrace(); }
}
}, 0,60000);
public void fun1()
{
//want to display toast
}
And I am getting following error:
WARN/System.err(593): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
WARN/System.err(593): at android.os.Handler.(Handler.java:121)
WARN/System.err(593): at android.widget.Toast.(Toast.java:68)
WARN/System.err(593): at android.widget.Toast.makeText(Toast.java:231)
Thanks.
You can't make UI updates inside separate Thread, like Timer. You should use Handler object for UI update:
timer.scheduleAtFixedRate( new TimerTask() {
private Handler updateUI = new Handler(){
#Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
fun1();
}
};
public void run() {
try {
updateUI.sendEmptyMessage(0);
} catch (Exception e) {e.printStackTrace(); }
}
}, 0,60000);
The easiest way (IMO) is:
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
final String message = "Hi";
MyActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MyActivity.this, message, Toast.LENGTH_SHORT).show();
}
});
}
});
The key being MyActivity.this.runOnUiThread(Runnable).
create a Handler and display toast in this
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
// Toast here
}
};
You need access to the Context of the application to be able to do this. Try creating your own class which takes the context as input parameter:
private class MyTimerTask extends TimerTask {
private Context context;
public MyTimerTask(Context context) {
this.context = context;
}
#Override
public void run() {
Toast.makeText(context, "Toast text", Toast.LENGTH_SHORT).show();
}
}
Then in your timer:
timer.scheduleAtFixedRate( new MyTimerTask(this), 0,60000);
I wanted to make a simple project that could display a Toast in a Timer.
The Timer would be started using a service. Then, the Timer starts when the service is started and stops when service is stopped.
Class 1
package com.example.connect;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
Button button1,button2;
private Handler mHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1=(Button)findViewById(R.id.button1);
button2=(Button)findViewById(R.id.button2);
}
public void Start(View v)
{
startService(new Intent(MainActivity.this , Connect_service.class));
}
public void Stop(View v)
{
stopService(new Intent(MainActivity.this , Connect_service.class));
}
}
Class 2
package com.example.connect;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class Connect_service extends Service{
Timer timer = new Timer();
TimerTask updateProfile = new CustomTimerTask(Connect_service.this);
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
timer.scheduleAtFixedRate(updateProfile, 0, 5000);
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Toast.makeText(this, "Service Stopped", Toast.LENGTH_SHORT).show();
timer.cancel();
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
Class 3
package com.example.connect;
import java.util.TimerTask;
import android.content.Context;
import android.os.Handler;
import android.widget.Toast;
public class CustomTimerTask extends TimerTask {
private Context context;
private Handler mHandler = new Handler();
public CustomTimerTask(Context con) {
this.context = con;
}
#Override
public void run() {
new Thread(new Runnable() {
public void run() {
mHandler.post(new Runnable() {
public void run() {
Toast.makeText(context, "In Timer", Toast.LENGTH_SHORT).show();
}
});
}
}).start();
}
}
I'm trying to make my own toast with my own views.
I've successfully combined your approaches. The following code allows me to show toasts and change/remove views without crashing, just change the parameters of the MyTimerTask constructor to whatever you need to work on.
public void yourFunction(){
Timer timer = new Timer();
MyTimerTask mtc = new MyTimerTask(this.getContext(), tvNotice);
timer.schedule(mtc, 1000);
}
private class MyTimerTask extends TimerTask {
private TextView tv;
private Context context;
public MyTimerTask(Context pContext, TextView pTv) {
this.tv = pTv;
this.context = pContext;
}
#Override
public void run() {
updateUI.sendEmptyMessage(0);
}
private Handler updateUI = new Handler(){
#Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
tv.setText("TextView Message");
Toast.makeText(context, "Toast Message", 0).show();
}
};
}
You have to call UIThread for showing Toast, not from timer thread.
Else call UI thread from that timer thread.
This link will help you,
http://developer.android.com/resources/articles/timed-ui-updates.html
and this
http://developer.android.com/guide/appendix/faq/commontasks.html#threading

Categories

Resources