Receiving Sinch messages and call in background and show notifications for incoming message and show overlay for call - sinch

i am using Sinch in my app for video, audio and messaging purpose. calling and messaging works fine when the app is running in foreground. when the app is closed and removed from stack, incoming messages and calls still works as i implemented push notification to look for incoming calls and messages (i checked in debug mode). My problem is that
1) when i start incoming call activity from firebaseMessaginService it does not show the caller name and picture i am sending in headers as i start it through relayRemotePushNotificationPayload(HashMap);
2) i am unable to get the message content data from incoming message and show notification accordingly.
My Code.
public class MyFirebaseMessagingService extends FirebaseMessagingService implements ServiceConnection {
Context context;
private SinchService.SinchServiceInterface mSinchServiceInterface;
HashMap dataHashMap;
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
context = this;
if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
Map data = remoteMessage.getData();
dataHashMap = (data instanceof HashMap) ? (HashMap) data : new HashMap<>(data);
if (SinchHelpers.isSinchPushPayload(dataHashMap)) {
getApplicationContext().bindService(new Intent(getApplicationContext(), SinchService.class), this, Context.BIND_AUTO_CREATE);
}
} else {
Intent intent;
PendingIntent pendingIntent = null;
if (remoteMessage.getData().size() > 0) {
String identifier = remoteMessage.getData().get("identifier");
if (identifier.equals("0")) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
} else if (identifier.equals("1")) {
intent = new Intent(this, Appointments.class);
pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
StaticInfo.saveData("HEALTH_TIP", "TIP", this);
}
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder.setWhen(System.currentTimeMillis());
notificationBuilder.setContentTitle(remoteMessage.getNotification().getTitle());
notificationBuilder.setContentText(remoteMessage.getNotification().getBody());
notificationBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
notificationBuilder.setDefaults(Notification.DEFAULT_ALL | Notification.DEFAULT_LIGHTS | Notification.FLAG_SHOW_LIGHTS | Notification.DEFAULT_SOUND);
notificationBuilder.setAutoCancel(true);
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
public static boolean foregrounded() {
ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
ActivityManager.getMyMemoryState(appProcessInfo);
return (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE);
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if (SinchService.class.getName().equals(componentName.getClassName())) {
mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
}
// it starts incoming call activity which does not show incoming caller name and picture
NotificationResult result = mSinchServiceInterface.relayRemotePushNotificationPayload(dataHashMap);
if (result.isValid() && result.isCall()) {
CallNotificationResult callResult = result.getCallResult();
if (callResult.isCallCanceled() || callResult.isTimedOut()) {
createNotification("Missed Call from : ", callResult.getRemoteUserId());
return;
} else {
if (callResult.isVideoOffered()) {
Intent intent = new Intent(this, IncomingVideoCall.class);
intent.putExtra(SinchService.CALL_ID, callResult.getRemoteUserId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
} else {
Intent intent = new Intent(this, IncomingAudioCall.class);
intent.putExtra(SinchService.CALL_ID, callResult.getRemoteUserId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
}
}
} else if (result.isValid() && result.isMessage()) {
//i want to get message content here
MessageNotificationResult notificationResult = result.getMessageResult();
createNotification("Received Message from : ", notificationResult.getSenderId());
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
unbindService(this);
}
private void createNotification(String contentTitle, String userId) {
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(getApplicationContext(), MainActivity.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext()).setSmallIcon(R.mipmap.ic_launcher).setContentTitle(contentTitle).setContentText(userId);
mBuilder.setContentIntent(contentIntent);
mBuilder.setDefaults(Notification.DEFAULT_SOUND);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
}
}
Sinch service is
public class SinchService extends Service {
private static final String APP_KEY = "123abc";
private static final String APP_SECRET = "123abc";
private static final String ENVIRONMENT = "sandbox.sinch.com";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;
private StartFailedListener mListener;
private PersistedSettings mSettings;
#Override
public void onCreate() {
super.onCreate();
mSettings = new PersistedSettings(getApplicationContext());
String userName = mSettings.getUsername();
if (!userName.isEmpty()) {
start(userName);
}
}
#Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminate();
}
super.onDestroy();
}
private void start(String userName) {
if (mSinchClient == null) {
mSettings.setUsername(userName);
mUserId = userName;
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName).applicationKey(APP_KEY).applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
mSinchClient.setSupportCalling(true);
mSinchClient.setSupportMessaging(true);
mSinchClient.setSupportManagedPush(true);
mSinchClient.checkManifest();
mSinchClient.setSupportActiveConnectionInBackground(true);
mSinchClient.startListeningOnActiveConnection();
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().setRespectNativeCalls(false);
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.getVideoController().setResizeBehaviour(VideoScalingType.ASPECT_FILL);
mSinchClient.start();
}
}
private void stop() {
if (mSinchClient != null) {
mSinchClient.terminate();
mSinchClient = null;
}
mSettings.setUsername("");
}
private boolean isStarted() {
return (mSinchClient != null && mSinchClient.isStarted());
}
#Override
public IBinder onBind(Intent intent) {
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public NotificationResult relayRemotePushNotificationPayload(final Map payload) {
if (mSinchClient == null && !mSettings.getUsername().isEmpty()) {
start(mSettings.getUsername());
} else if (mSinchClient == null && mSettings.getUsername().isEmpty()) {
if (!StaticInfo.getSavedData("username", SinchService.this).equals("")) {
start(StaticInfo.getSavedData("username", SinchService.this));
}
return null;
}
return mSinchClient.relayRemotePushNotificationPayload(payload);
}
public void sendMessage(String recipientUserId, String Name, String textBody, String imageUrl) {
SinchService.this.sendMessage(recipientUserId, Name, textBody, imageUrl);
}
public void addMessageClientListener(MessageClientListener listener) {
SinchService.this.addMessageClientListener(listener);
}
public void removeMessageClientListener(MessageClientListener listener) {
SinchService.this.removeMessageClientListener(listener);
}
public Call callUser(String userId, HashMap<String, String> name) {
if (mSinchClient == null) {
return null;
}
return mSinchClient.getCallClient().callUser(userId, name);
}
public Call callUserVideo(String userId, HashMap<String, String> name) {
return mSinchClient.getCallClient().callUserVideo(userId, name);
}
public String getUserName() {
return mUserId;
}
public boolean isStarted() {
return SinchService.this.isStarted();
}
public void startClient(String userName) {
start(userName);
}
public void stopClient() {
stop();
}
public void setStartListener(StartFailedListener listener) {
mListener = listener;
}
public Call getCall(String callId) {
return mSinchClient.getCallClient().getCall(callId);
}
public VideoController getVideoController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getVideoController();
}
public AudioController getAudioController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getAudioController();
}
public void LogOut() {
if (mSinchClient != null) {
mSinchClient.stopListeningOnActiveConnection();
mSinchClient.unregisterPushNotificationData();
mSinchClient.unregisterManagedPush();
//mSinchClient.terminate();
}
}
}
public interface StartFailedListener {
void onStartFailed(SinchError error);
void onStarted();
}
private class MySinchClientListener implements SinchClientListener {
#Override
public void onClientFailed(SinchClient client, SinchError error) {
if (mListener != null) {
mListener.onStartFailed(error);
}
mSinchClient.terminate();
mSinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
Log.d(TAG, "SinchClient started");
if (mListener != null) {
mListener.onStarted();
}
}
#Override
public void onClientStopped(SinchClient client) {
Log.d(TAG, "SinchClient stopped");
}
#Override
public void onLogMessage(int level, String area, String message) {
switch (level) {
case Log.DEBUG:
Log.d(area, message);
break;
case Log.ERROR:
Log.e(area, message);
break;
case Log.INFO:
Log.i(area, message);
break;
case Log.VERBOSE:
Log.v(area, message);
break;
case Log.WARN:
Log.w(area, message);
break;
}
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration clientRegistration) {
}
}
private class SinchCallClientListener implements CallClientListener {
#Override
public void onIncomingCall(CallClient callClient, Call call) {
if (call.getDetails().isVideoOffered()) {
Intent intent = new Intent(SinchService.this, IncomingVideoCall.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
SinchService.this.startActivity(intent);
} else {
Intent intent = new Intent(SinchService.this, IncomingAudioCall.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
SinchService.this.startActivity(intent);
}
}
}
private class PersistedSettings {
private SharedPreferences mStore;
private static final String PREF_KEY = "Sinch";
public PersistedSettings(Context context) {
mStore = context.getSharedPreferences(PREF_KEY, MODE_PRIVATE);
}
public String getUsername() {
return mStore.getString("Username", "");
}
public void setUsername(String username) {
SharedPreferences.Editor editor = mStore.edit();
editor.putString("Username", username);
editor.commit();
}
}
public void sendMessage(String recipientUserId, String name, String textBody, String imageUrl) {
if (isStarted()) {
WritableMessage message = new WritableMessage();
message.addHeader("imageUrl", imageUrl);
message.addHeader("Name", name);
message.addRecipient(recipientUserId);
message.setTextBody(textBody);
mSinchClient.getMessageClient().send(message);
}
}
public void addMessageClientListener(MessageClientListener listener) {
if (mSinchClient != null) {
mSinchClient.getMessageClient().addMessageClientListener(listener);
}
}
public void removeMessageClientListener(MessageClientListener listener) {
if (mSinchClient != null) {
mSinchClient.getMessageClient().removeMessageClientListener(listener);
}
}
}
i am sending message like this.
private void sendMessage() {
String textBody = mTxtTextBody.getText().toString();
if (textBody.isEmpty()) {
Toast.makeText(this, "No text message", Toast.LENGTH_SHORT).show();
return;
}
getSinchServiceInterface().sendMessage(receiver_username, name, textBody, picture);
mTxtTextBody.setText("");
}
and the adapter where extracting message headers is
public class MessageAdapter extends BaseAdapter {
public static final int DIRECTION_INCOMING = 0;
public static final int DIRECTION_OUTGOING = 1;
private List<Pair<Message, Integer>> mMessages;
private SimpleDateFormat mFormatter;
private LayoutInflater mInflater;
Context context; // modification here
int res = 0;
String photo_url;
public MessageAdapter(Activity activity) {
mInflater = activity.getLayoutInflater();
context = activity;
mMessages = new ArrayList<>();
mFormatter = new SimpleDateFormat("hh:mm aa");
}
public void addMessage(Message message, int direction) {
mMessages.add(new Pair(message, direction));
notifyDataSetChanged();
}
#Override
public int getCount() {
return mMessages.size();
}
#Override
public Object getItem(int i) {
return mMessages.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int i) {
return mMessages.get(i).second;
}
#Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
int direction = getItemViewType(i);
if (convertView == null) {
if (direction == DIRECTION_INCOMING) {
res = R.layout.message_right;
} else if (direction == DIRECTION_OUTGOING) {
res = R.layout.message_left;
}
convertView = mInflater.inflate(res, viewGroup, false);
}
Message message = mMessages.get(i).first;
String name = message.getHeaders().get("Name");
if (direction == DIRECTION_INCOMING) {
photo_url = message.getHeaders().get("imageUrl");
} else if (direction == DIRECTION_OUTGOING) {
photo_url = StaticInfo.getSavedData("photo", context);
}
CircleImageView photo = convertView.findViewById(R.id.pic);
Picasso.with(context).load(photo_url).into(photo);
TextView txtSender = convertView.findViewById(R.id.txtSender);
TextView txtMessage = convertView.findViewById(R.id.txtMessage);
TextView txtDate = convertView.findViewById(R.id.txtDate);
txtSender.setText(name);
txtMessage.setText(message.getTextBody());
txtDate.setText(mFormatter.format(message.getTimestamp()));
return convertView;
}
}

Related

Sinch Video clling APi not working when app is cleared from recents

I am using sinch Video calling API for my android application. But when the app is in the background, whenever the user is offline i.e user cleared app from the recent tab, he was unable to get the call. I used Firebase for pushing notification whenever the user is offline, but it is not getting triggered all the time, it is getting triggered sometimes only. can anyone suggest me how to push notification of incoming call when the user cleared the app from recent and will sinch actually run in the background?
public class SinchService extends Service {
private static final String APP_KEY = "key";
private static final String APP_SECRET = "secret";
private static final String ENVIRONMENT = "clientapi.sinch.com";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;
static Context context;
private StartFailedListener mListener;
#Override
public void onCreate() {
super.onCreate();
}
/* #Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminate();
}
super.onDestroy();
}*/
private void start(String userName,String fcm_token) {
if (mSinchClient == null) {
mUserId = userName;
/*LooperThread looperThread = new LooperThread();
looperThread.start();*/
/* new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
}
});*/
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(mUserId)
.applicationKey(APP_KEY)
.applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT)
.build();
//Log.d("OnMsg","coming after getSinchServiceInterface()");
mSinchClient.setSupportMessaging(true);
mSinchClient.setSupportCalling(true);
mSinchClient.setSupportManagedPush(true);
mSinchClient.setSupportPushNotifications(true);
mSinchClient.startListeningOnActiveConnection();
/* mSinchClient.startListeningOnActiveConnection();
mSinchClient.setSupportActiveConnectionInBackground(true);*/
// mSinchClient.setSupportActiveConnectionInBackground(true);
// mSinchClient.startListeningOnActiveConnection();
/* mSinchClient.setSupportManagedPush(true);
mSinchClient.setSupportPushNotifications(true);*/
// Log.d("fcm:","fcm token in bytes "+ fcm_token.getBytes());
mSinchClient.checkManifest();
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.start();
// mSinchClient.registerPushNotificationData(fcm_token.getBytes());
}
}
class LooperThread extends Thread {
public Handler mHandler;
#Override
public void run() {
// Initialize the current thread as a Looper
// (this thread can have a MessageQueue now)
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// process incoming messages here
/* mSinchClient.setSupportMessaging(true);
mSinchClient.setSupportCalling(true);
mSinchClient.setSupportManagedPush(true);
mSinchClient.setSupportPushNotifications(true);
mSinchClient.startListeningOnActiveConnection();
*//* mSinchClient.startListeningOnActiveConnection();
mSinchClient.setSupportActiveConnectionInBackground(true);*//*
// mSinchClient.setSupportActiveConnectionInBackground(true);
// mSinchClient.startListeningOnActiveConnection();
*//* mSinchClient.setSupportManagedPush(true);
mSinchClient.setSupportPushNotifications(true);*//*
// Log.d("fcm:","fcm token in bytes "+ fcm_token.getBytes());
mSinchClient.checkManifest();
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.start();*/
}
};
// Run the message queue in this thread
Looper.loop();
}
}
private void stop() {
if (mSinchClient != null) {
mSinchClient.terminate();
mSinchClient = null;
}
}
private boolean isStarted() {
return (mSinchClient != null && mSinchClient.isStarted());
}
#Override
public IBinder onBind(Intent intent) {
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public Call callUserVideo(String userId) {
return mSinchClient.getCallClient().callUserVideo(userId);
}
public String getUserName() {
return mUserId;
}
public boolean isStarted() {
return SinchService.this.isStarted();
}
public void startClient(String userName,String token) {
start(userName,token);
}
public void stopClient() {
stop();
}
public void setStartListener(StartFailedListener listener) {
mListener = listener;
}
public Call getCall(String callId) {
return mSinchClient.getCallClient().getCall(callId);
}
public VideoController getVideoController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getVideoController();
}
public AudioController getAudioController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getAudioController();
}
}
public interface StartFailedListener {
void onStartFailed(SinchError error);
void onStarted();
}
private class MySinchClientListener implements SinchClientListener {
#Override
public void onClientFailed(SinchClient client, SinchError error) {
if (mListener != null) {
mListener.onStartFailed(error);
}
/* mSinchClient.terminate();
mSinchClient = null;*/
}
#Override
public void onClientStarted(SinchClient client) {
Log.d(TAG, "SinchClient started");
if (mListener != null) {
mListener.onStarted();
mSinchClient.startListeningOnActiveConnection();
}
}
#Override
public void onClientStopped(SinchClient client) {
Log.d(TAG, "SinchClient stopped");
}
#Override
public void onLogMessage(int level, String area, String message) {
switch (level) {
case Log.DEBUG:
Log.d(area, message);
break;
case Log.ERROR:
Log.e(area, message);
break;
case Log.INFO:
Log.i(area, message);
break;
case Log.VERBOSE:
Log.v(area, message);
break;
case Log.WARN:
Log.w(area, message);
break;
}
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client,
ClientRegistration clientRegistration) {
}
}
public class SinchCallClientListener implements CallClientListener {
#Override
public void onIncomingCall(CallClient callClient, Call call) {
Log.d("OnMsg", "Incoming call");
Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchService.this.startActivity(intent);
}
}
}
public class PlaceCallActivity extends BaseActivity implements SinchService.StartFailedListener/*,PushTokenRegistrationCallback*/{
private Button mCallButton;
private EditText mCallName;
Button stopButton;
String token;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//initializing UI elements
mCallName = findViewById(R.id.callName);
mCallButton = findViewById(R.id.callButton);
mCallButton.setEnabled(false);
mCallButton.setOnClickListener(buttonClickListener);
stopButton = findViewById(R.id.stopButton);
stopButton.setEnabled(false);
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w("test", "getInstanceId failed", task.getException());
return;
}
// Get new Instance ID token
token = task.getResult().getToken();
// Log and toast
//String msg = getString(R.string.msg_token_fmt, token);
Log.d("test", token);
Toast.makeText(PlaceCallActivity.this, token, Toast.LENGTH_SHORT).show();
}
});
stopButton.setOnClickListener(buttonClickListener);
/* try {
#SuppressLint("WrongThread") String regId = FirebaseInstanceId.getInstance().getToken("Your-Sender-ID", "FCM");
} catch (IOException e) {
e.printStackTrace();
}*/
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
getSinchServiceInterface().startClient(new PreferenceUtils(PlaceCallActivity.this).getName(),token);
}
}, 4000);
}
// invoked when the connection with SinchServer is established
#Override
protected void onServiceConnected() {
TextView userName = (TextView) findViewById(R.id.loggedInName);
getSinchServiceInterface().setStartListener(this);
userName.setText(new PreferenceUtils(PlaceCallActivity.this).getName());
mCallButton.setEnabled(true);
stopButton.setEnabled(true);
}
/* #Override
public void onDestroy() {
if (getSinchServiceInterface() != null) {
getSinchServiceInterface().stopClient();
}
super.onDestroy();
}*/
/*//to kill the current session of SinchService
private void stopButtonClicked() {
if (getSinchServiceInterface() != null) {
getSinchServiceInterface().stopClient();
}
finish();
}*/
//to place the call to the entered name
private void callButtonClicked() {
String userName = mCallName.getText().toString();
if (userName.isEmpty()) {
Toast.makeText(this, "Please enter a user to call", Toast.LENGTH_LONG).show();
return;
}
Call call = getSinchServiceInterface().callUserVideo(userName);
String callId = call.getCallId();
Log.d("test","call id is"+callId);
Intent callScreen = new Intent(this, CallScreenActivity.class);
callScreen.putExtra(SinchService.CALL_ID, callId);
callScreen.putExtra("TOKEN", token);
startActivity(callScreen);
}
private OnClickListener buttonClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.callButton:
callButtonClicked();
break;
case R.id.stopButton:
// stopButtonClicked();
break;
}
}
};
#Override
public void onStartFailed(SinchError error) {
Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onStarted() {
}
}

why volley didnt read my url string completely

I have been calling this API long enough. But now, volley cannot read my URL string completely using the same code as before, except that I put sendmsgnow() function in my adapter. It's working when I put that URL in my browser.
P.s:-I have changed the password as it's a paid sms gateway.
The error:
//Adapter.java
public class Adapter extends RecyclerView.Adapter<Adapter.Viewholder> {
String contactdonor;
private static final String URL = "http://Lifetimesms.com/plain?username=opvg&password=mypassword&to=03365297078&from=ComapnyName&message=uyy kugtyf rtd ydrtjyty tku.";
private ArrayList<UserInformation> list;
private Context ctx;
public Adapter(ArrayList<UserInformation> list, Context ctx) {
this.list = list;
this.ctx = ctx;
}
#Override
public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_user_layout, parent, false);
Viewholder myHolder = new Viewholder(view);
return myHolder;
}
#Override
public void onBindViewHolder(Viewholder holder, int position) {
final UserInformation val = list.get(position);
holder.edt_contact_no.setText(val.getContact_no());
holder.edt_blood_group.setText(val.getBlood_group());
holder.btn_approve.setText("approve");
holder.btn_decline.setText("decline");
holder.btn_approve.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(ctx, "bloodgrp got= " + val.getBlood_group(), Toast.LENGTH_SHORT).show();
sendmsg(val);
}
});
holder.btn_decline.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//code to delete data
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference reference = firebaseDatabase.getReference("Patients");
reference.child(val.getContact_no()).removeValue();
}
});
}
public void sendmsg(final UserInformation val) {
//Toast.makeText(ctx, "sendmsg called", Toast.LENGTH_SHORT).show();
//Toast.makeText(ctx, "blood group received" + val.getBlood_group(), Toast.LENGTH_SHORT).show();
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference reference = firebaseDatabase.getReference("Donors");
Query query = reference.orderByChild("blood_group_donor").equalTo(val.getBlood_group());
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
DonorInformation donor = null;
for (DataSnapshot data : dataSnapshot.getChildren()) {
donor = data.getValue(DonorInformation.class);
contactdonor = donor.getContact_no_donor();
Toast.makeText(ctx, "contactno is " + contactdonor, Toast.LENGTH_SHORT).show();
nowsendtxt();
}
// Toast.makeText(ctx, "contactno selected 0is= " + contact, Toast.LENGTH_SHORT).show();
}
private void nowsendtxt() {
//Toast.makeText(ctx, "contactno received" + contactdonor, Toast.LENGTH_SHORT).show();
StringRequest request = new StringRequest(URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(ctx, "successful", Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(ctx, "error", Toast.LENGTH_SHORT).show();
}
}//
);
RequestQueue requestQueue = Volley.newRequestQueue(ctx);
requestQueue.add(request);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
/*public void nowsendtxt(String contactdonor,UserInformation p )
{
Toast.makeText(ctx, "contactno received" + contactdonor, Toast.LENGTH_SHORT).show();
UserInformation patient=p;
String patient_name,bloodgrp_common;
patient_name=patient.getPatient_name();
bloodgrp_common=patient.getBlood_group();
StringRequest request = new StringRequest(URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(ctx, "successful", Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(ctx, "error", Toast.LENGTH_SHORT).show();
}
}
);
RequestQueue requestQueue = Volley.newRequestQueue(ctx);
requestQueue.add(request);
}*/
#Override
public int getItemCount() {
return list.size();
}
public static class Viewholder extends RecyclerView.ViewHolder {
EditText edt_blood_group;
EditText edt_contact_no;
Button btn_approve, btn_decline;
public Viewholder(View itemView) {
super(itemView);
edt_blood_group = (EditText) itemView.findViewById(R.id.edt_blood_group);
edt_contact_no = (EditText) itemView.findViewById(R.id.edt_contact_no);
btn_approve = (Button) itemView.findViewById(R.id.btn_approve);
btn_decline = (Button) itemView.findViewById(R.id.btn_decline);
}
}
}

It takes a long time to load large data in recyclerview

I have 11 text files each containing 50-60 lines. I have read all the files and showed in the recyclerview. I used asynctask to track the progress through the progress bar. I have used log too to see the read lines. I have found that reading is taking short time but after reading, it takes 5-6 seconds to show data in the recyclerview. Why is this causing? What should i do to handle this? Why should i do if there are thousands of text files?
Codes reading files and binding
AsyncTask<Void,Void,Void> task = new AsyncTask<Void, Void, Void>() {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(GrammerDetails.this,
"Loading", "Please Wait for a while");
}
#Override
protected Void doInBackground(Void... voids) {
getFromFilesbagdhara(id,realm);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("first_bagdhara",false);
editor.apply();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
inflateData(listGrammerItem);
progressDialog.dismiss();
}
}.execute();
private void getFromFilesbagdhara(String id, Realm realm) {
String directory = "Grammer/Bagdhara";
AssetManager man = getAssets();
BufferedReader reader = null;
try {
String[] files = man.list(directory);
for (int i =0;i<files.length;i++){
String fileName = files[i];
reader = new BufferedReader(
new InputStreamReader(getAssets().open(directory+"/" + fileName),
"UTF-8"));
String line;
Log.e("File",files[i]);
while ((line = reader.readLine()) != null) {
Log.e("line",line);
// String[] text = line.split(" ");
String a = line.substring(0,line.indexOf("(")-1);
String b = line.substring(line.indexOf("(")+1,line.indexOf(")"));
String wordOne = a;
// String dummyTwo = text[1];
String wordTwo = b; //dummyTwo.substring(1,dummyTwo.length()-1);
final ClassGrammerItem classGrammerItem = new ClassGrammerItem(wordOne,wordTwo,id);
listGrammerItem.add(classGrammerItem);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
//log the exception
}
}
}
}
private void inflateData(RealmList<ClassGrammerItem> listGrammerItem) {
AdapterGrammerItem adapter = new AdapterGrammerItem(listGrammerItem, GrammerDetails.this);
recyclerView.setAdapter(adapter);
}
Adapter:
public class AdapterGrammerItem extends RecyclerView.Adapter<AdapterGrammerItem
.ViewHolderAdapterRecycler> {
RealmList<ClassGrammerItem> activityList = new RealmList<ClassGrammerItem>();
Context context;
private LayoutInflater layoutInflater;
public AdapterGrammerItem(RealmList<ClassGrammerItem> activityList, Context context) {
this.activityList = activityList;
this.context = context;
layoutInflater = LayoutInflater.from(context);
}
#Override
public AdapterGrammerItem.ViewHolderAdapterRecycler onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.recycler_grammer_item, parent, false);
AdapterGrammerItem.ViewHolderAdapterRecycler viewHolder = new AdapterGrammerItem.ViewHolderAdapterRecycler(view);
return viewHolder;
}
#Override
public void onBindViewHolder(AdapterGrammerItem.ViewHolderAdapterRecycler holder, int position) {
ClassGrammerItem currentItem = activityList.get(position);
holder.wordOne.setText(currentItem.getWordOne());
holder.wordTwo.setText(currentItem.getWordTwo());
}
#Override
public int getItemCount() {
return activityList.size();
}
public class ViewHolderAdapterRecycler extends RecyclerView.ViewHolder {
MyTextView wordOne, wordTwo;
public ViewHolderAdapterRecycler(View itemView) {
super(itemView);
wordOne = (MyTextView) itemView.findViewById(R.id.wordOne);
wordTwo = (MyTextView) itemView.findViewById(R.id.wordTwo);
}
}
}

TableColumn, How to connect it with property but not fill the cells

I have a TableView and Data class with integer properties for columns. However I would like columns at first show empty cells so user can put value he wants.
Right now its impossible because when creating Data object, integer values has to be created with initial value, so table shows up filled already with numbers.
private ObservableList<MyData> dataList = FXCollections.observableArrayList();
.....edited....
private void buttAddColumnAction(ActionEvent event){
int i = numberOfColumns;// thats the key for lambda expression. Unicate number for column to access its variable;
if(dataList.size() > 0)//resizing each data object with new variable
for(MyData x: dataList)
x.addNew();
TableColumn<MyData, Integer> newColumn = new TableColumn<>("#" + String.valueOf(++numberOfColumns));
newColumn.setCellValueFactory(cellData -> cellData.getValue().getCellValue(i));
// newColumn.setCellFactory(TextFieldTableCell.<MyData, Integer>forTableColumn(new IntegerStringConverter()));
Callback<TableColumn<MyData, Integer>, TableCell<MyData, Integer>> cellFactoryInt = (TableColumn<MyData, Integer> p) -> new EditingCellNumbers(tableView);
newColumn.setCellFactory(cellFactoryInt);
tableView.getColumns().add(newColumn);
}
public class MyData{ //dont forget about public because you wont get acces to properties
private ObservableList<ObjectProperty<Integer>> cellValue = FXCollections.observableArrayList();
public MyData(int howManyColumns) {
for(int i=0; i<howManyColumns; ++i)
this.cellValue.add(new SimpleObjectProperty<Integer>(null));
}
public ObjectProperty<Integer> getCellValue(int whichOne) {
return cellValue.get(whichOne);
}
public void setCellValue(int cellValue, int whichOne) {
this.cellValue.set(whichOne, new SimpleObjectProperty<Integer>(cellValue));
}
public void addNew(){ //ads another variable for another column
cellValue.add(new SimpleObjectProperty<Integer>(null));
}
public void deleteLast(){ //deletes last variable when column is deleted
cellValue.remove(cellValue.size()-1);
}
}
CellFactory
//Klasa ta pozwala na definiowania zachowania komórek, które edytuje użytkownik
public class EditingCellNumbers extends TableCell<MyData, Integer>{
private TextField textField;
private TableView<MyData> parentTableView;
public static int numberOfColumns;
public EditingCellNumbers(TableView<MyData> parent) {
this.parentTableView = parent;
numberOfColumns = parent.getColumns().size();
}
#Override
public void startEdit(){
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
textField.requestFocus();
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(String.valueOf(getItem()));
setGraphic(null);
}
#Override
public void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
textField.focusedProperty().addListener(
(ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) -> {
if (!arg2) {
XXX commitEdit(Integer.valueOf(textField.getText()));
}
});
textField.setOnKeyReleased(new EventHandler<Event>() {
#Override
public void handle(Event event) {
try{
int i = Integer.valueOf(textField.getText());
//digit given...
if( (i>=0) && (i<10) ){//making sure cell is filled with just one digit
commitEdit(Integer.valueOf(textField.getText()));
int selectedColumn = parentTableView.getSelectionModel().getSelectedCells().get(0).getColumn(); // gets the number of selected column
int selectedRow = parentTableView.getSelectionModel().getSelectedCells().get(0).getRow();
if(selectedColumn < numberOfColumns-1){
parentTableView.getSelectionModel().selectNext();
parentTableView.edit(selectedRow, parentTableView.getColumns().get(selectedColumn+1));
}else{
parentTableView.getSelectionModel().select(selectedRow+1, parentTableView.getColumns().get(0));
parentTableView.edit(selectedRow+1, parentTableView.getColumns().get(0));
}
}else
textField.clear();
}catch(NumberFormatException e){
textField.clear();
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
Allow null values in your column by using an ObjectProperty<Integer> instead of an IntegerProperty. This gives a more natural way to define "not initialized" than representing it with 0 (or some other proxy value).
Then you can use the TextFieldTableCell, but just supply a custom StringConverter<Integer>:
public class MyData{ //dont forget about public because you wont get acces to properties
private ObservableList<ObjectProperty<Integer>> cellValue = FXCollections.observableArrayList();
public MyData(int howManyColumns) {
for(int i=0; i<howManyColumns; ++i)
this.cellValue.add(new SimpleObjectProperty<>(new Random().nextInt(10)));
}
// ...
}
and
newColumn.setCellValueFactory(cellData -> cellData.getValue().getCellValue(i));
newColumn.setCellFactory(TextFieldTableCell.<MyData, Integer>forTableColumn(new StringConverter<Integer>() {
#Override
public String toString(Integer i) {
if (i == null) {
return "" ;
} else {
return i.toString();
}
}
#Override
public Integer fromString(String string) {
if (string.trim().length() == 0) {
return null ;
} else {
try {
return Integer.valueOf(string);
} catch (NumberFormatException nfe) {
return null ;
}
}
}
}));
Complete example:
import java.util.Random;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class TableViewWithEmptyIntegerColumn extends Application {
#Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView<>();
table.setEditable(true);
TableColumn<Item, String> nameCol = createCol("Name", Item::nameProperty);
TableColumn<Item, Integer> valueCol = createCol("Value", Item::valueProperty);
valueCol.setEditable(true);
valueCol.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<Integer>() {
#Override
public String toString(Integer i) {
if (i == null) {
return "" ;
} else {
return i.toString() ;
}
}
#Override
public Integer fromString(String string) {
if (string.trim().length() == 0) {
return null ;
} else {
// better to check for a valid int format instead of using try-catch...
try {
return Integer.valueOf(string);
} catch (NumberFormatException nfe) {
return null ;
}
}
}
}));
Random rng = new Random();
for (int i=1; i<=20; i++) {
if (rng.nextDouble() < 0.5) {
table.getItems().add(new Item("Item "+i));
} else {
table.getItems().add(new Item("Item "+i, rng.nextInt(10)+1));
}
}
table.getColumns().addAll(nameCol, valueCol);
primaryStage.setScene(new Scene(new BorderPane(table), 400, 600));
primaryStage.show();
}
private <S,T> TableColumn<S,T> createCol(String title, Function<S, ObservableValue<T>> property) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
return col ;
}
public static class Item {
private final StringProperty name = new SimpleStringProperty();
private final ObjectProperty<Integer> value = new SimpleObjectProperty<>();
public Item(String name, Integer value) {
setName(name);
setValue(value);
}
public Item(String name) {
this(name, null);
}
public final StringProperty nameProperty() {
return this.name;
}
public final String getName() {
return this.nameProperty().get();
}
public final void setName(final String name) {
this.nameProperty().set(name);
}
public final ObjectProperty<Integer> valueProperty() {
return this.value;
}
public final Integer getValue() {
return this.valueProperty().get();
}
public final void setValue(final Integer value) {
this.valueProperty().set(value);
}
}
public static void main(String[] args) {
launch(args);
}
}

TableView, setting editable cells

I try to make Table cells editable. I managed to do this with two Collumns that have String values in it, but I cant make this with columns that represent Integer values.
Places with X is where compiler get the error:
The method setCellFactory(Callback<TableColumn<DataModel,Integer>,TableCell<DataModel,Integer>>) in the type TableColumn<DataModel,Integer> is not applicable for the arguments (Callback<TableColumn<DataModel,String>,TableCell<DataModel,String>>)
and places with XX is where compiler get the error:
The method setOnEditCommit(EventHandler<TableColumn.CellEditEvent<DataModel,Integer>>) in the type TableColumn<DataModel,Integer> is not applicable for the arguments ((CellEditEvent<DataModel, Integer> event) -> {})
Heres the code:
public void initialize(URL location, ResourceBundle resources) {
//Tworzymy sobie kolumny, które będą odpowiadać oraz przyjmować konretne dane
TableColumn<DataModel, String> nameColumn = new TableColumn<DataModel, String>("Name");
nameColumn.setMinWidth(100);
TableColumn<DataModel, String> surnameColumn = new TableColumn<DataModel, String>("Surname");
surnameColumn.setMinWidth(100);
TableColumn<DataModel, Integer> ageColumn = new TableColumn<DataModel, Integer>("Age");
ageColumn.setMinWidth(100);
TableColumn<DataModel, Integer> telNumberColumn = new TableColumn<DataModel, Integer>("Tel. Number");
telNumberColumn.setMinWidth(100);
//dodajemy kolumny do okna
tableView.getColumns().addAll(nameColumn,surnameColumn,ageColumn,telNumberColumn);
//podajemy nazwy zmiennych, których wartości mają się wyświetlać w poszczególnych kolumnach
nameColumn.setCellValueFactory(new PropertyValueFactory<>("sName"));
surnameColumn.setCellValueFactory(new PropertyValueFactory<>("sSurname"));
ageColumn.setCellValueFactory(new PropertyValueFactory<>("iAge"));
telNumberColumn.setCellValueFactory(new PropertyValueFactory<>("iPhoneNumber"));
//Sprawiamy że poszczególne kolumny stają się edytowalne
nameColumn.setCellFactory(TextFieldTableCell.<DataModel>forTableColumn());
nameColumn.setOnEditCommit((CellEditEvent<DataModel, String> event) -> {
((DataModel) event.getTableView().getItems(). get(event.getTablePosition().getRow())). setsName(event.getNewValue());
});
surnameColumn.setCellFactory(TextFieldTableCell.<DataModel>forTableColumn());
surnameColumn.setOnEditCommit((CellEditEvent<DataModel, String> event) -> {
((DataModel) event.getTableView().getItems(). get(event.getTablePosition().getRow())). setsSurname(event.getNewValue());
});
X ageColumn.setCellFactory(TextFieldTableCell.<DataModel>forTableColumn());
XX ageColumn.setOnEditCommit((CellEditEvent<DataModel, Integer> event) -> {
// ((DataModel) event.getTableView().getItems(). get(event.getTablePosition().getRow())). setiAge(Integer.valueOf(event.getNewValue()));
});
X telNumberColumn.setCellFactory(TextFieldTableCell.<DataModel>forTableColumn());
XX telNumberColumn.setOnEditCommit((CellEditEvent<DataModel, Integer> event) -> {
// ((DataModel) event.getTableView().getItems(). get(event.getTablePosition().getRow())). setiPhoneNumber(Integer.valueOf(event.getNewValue()));
});
tableView.setPlaceholder(new Label("Pust tabelka!"));//jaki element dodać jeśli tabelka nie jest wyświetlona
tableView.setEditable(true);
tableView.setItems(dataList); //wczytujemy dane do przygotowanej tabelki
buttAdd.setOnAction((ActionEvent e) -> {
buttAddAction(e);
});
}
Im taking oracle TableView tutorial, and its quite difficult. Help.
The issue is that TextFieldTableCell.forTableColumn() is typed to a String value. See the default implementation:
public static <S> Callback<TableColumn<S,String>, TableCell<S,String>> forTableColumn() {
return forTableColumn(new DefaultStringConverter());
}
What you need is the TextFieldTableCell with an IntegerStringConverter, for example:
ageColumn.setCellFactory(TextFieldTableCell.<DataModel, Integer>forTableColumn(new IntegerStringConverter()));
I searched through a lot of answers and I've borrowed/extended/merged to this solution. Edits are committed when focus moves from edited cell. I have a public class for each datatype that can be represented in a table: EditingTextCell, EditingIntegerCell etc. These public classes can be applied to any table provided that the data is represented as an observable list of a class that accesses the data to be displayed as properties. I publish this solution because I was faced with creating a class for each column of each table in my application. Currently, the double value and combobox cell versions are tied to specific columns of specific tables. I'll do a generalized version of these as time permits. Please forgive my not presenting the source links -- I forgot to bookmark them as I perused them.
Java documentation suggests that easier ways of doing this are forthcoming.
Example usage for Integer field:
TableColumn<Factor, Number> noLevelsCol =
new TableColumn<>("No. Levels");
noLevelsCol.setCellValueFactory(
new PropertyValueFactory("numberLevels"));
noLevelsCol.setMinWidth(40);
noLevelsCol.setCellFactory(col -> new EditingIntegerCell<>());
noLevelsCol.setOnEditCommit((CellEditEvent<Factor, Number> t) -> {
((Factor) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setNumberLevels(t.getNewValue().intValue());
});
Example usage for String field:
TableColumn<Factor, String> nameCol = new TableColumn<>("Name");
nameCol.setMinWidth(60);
nameCol.setCellValueFactory(
new PropertyValueFactory("factorName"));
nameCol.setCellFactory(cellFactory);
nameCol.setOnEditCommit((CellEditEvent<Factor, String> t) -> {
((Factor) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setFactorName(t.getNewValue());
});
Definition of Factor class:
public class Factor {
private final IntegerProperty factorID = new SimpleIntegerProperty();
public IntegerProperty getFactorID() { return factorID; }
private StringProperty factorName = new SimpleStringProperty();
public void setFactorName(String value) {
factorNameProperty().set(value); }
public String getFactorName() { return factorNameProperty().get(); }
public StringProperty factorNameProperty() {
if (factorName == null) factorName =
new SimpleStringProperty(this, "factorName");
return factorName;
}
private IntegerProperty numberLevels = new SimpleIntegerProperty();
public void setNumberLevels(int value) {
numberLevelsProperty().set(value); }
public IntegerProperty getNumberLevels() { return numberLevels; }
public IntegerProperty numberLevelsProperty() {
if (numberLevels == null) numberLevels =
new SimpleIntegerProperty(this, "numberLevels");
return numberLevels;
}
private StringProperty listOfLevels = new SimpleStringProperty();
public void setListOfLevels(String value) {
listOfLevelsProperty().set(value); }
public String getListOfLevels() { return listOfLevelsProperty().get(); }
public StringProperty listOfLevelsProperty() {
if (listOfLevels == null) listOfLevels =
new SimpleStringProperty(this, "listOfLevels");
return listOfLevels;
}
// Constructors
public Factor(int factorID, String factorName) {
this.factorID.set(factorID);
this.factorName.set(factorName);
this.numberLevels.set(1);
this.listOfLevels.set("-1, 1");
}
public Factor(int factorID, String factorName, int numberLevels,
String listOfLevels) {
this.factorID.set(factorID);
this.factorName.set(factorName);
this.numberLevels.set(numberLevels);
this.listOfLevels.set(listOfLevels);
}
#Override
public String toString() {
return "Factor{" + "factorName=" + factorName + '}';
}
public String[] getLevels() {
return listOfLevels.getValue().split(",");
}
}
Loading the data into the table
final ObservableList factorList =
FXCollections.observableArrayList(
new Factor(1, "Factor1", 2, "-1, 1")
);
factorTableView.setEditable(true);
factorTableView.getColumns().clear();
factorTableView.setItems(factorList);
boolean addAll;
addAll = factorTableView.getColumns().addAll(idCol,
nameCol, noLevelsCol, levelsCol);
The EditingIntegerCell class
public class EditingIntegerCell extends TableCell {
private TextField textField;
private final Pattern intPattern = Pattern.compile("-?\\d+");
public EditingIntegerCell() {
}
#Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem().toString());
setGraphic(null);
}
#Override
public void updateItem(Number item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
textField.focusedProperty().addListener(
(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2)
-> {
if (!arg2) {
processEdit();
}
});
}
private void processEdit() {
String text = textField.getText();
if (intPattern.matcher(text).matches()) {
commitEdit(Integer.parseInt(text));
} else {
cancelEdit();
}
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
** The EditingTextCell class **
public class EditingTextCell extends TableCell {
private TextField textField;
public EditingTextCell() {
}
#Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
textField.focusedProperty().addListener(
(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2)
-> {
if (!arg2) {
commitEdit(textField.getText());
}
});
}
private String getString() {
return getItem() == null ? "" : getItem();
}
}

Resources