Sync Android Wear with Phone whenever you open the wear app - java

I am trying to implement a basic weather app for both android phone and wear. The application gets its data from an Web API then it displays it on the phone. Right now if the app is open on the Wear and then you open it on the Phone, it syncs the weather on both. And if you change the weather on the phone, it changes on the wear too. I want to make the wear app get the weather from the phone whenever you open the wear app, and I tried to implement this by making the wear "ping" the phone via a message and then the phone sends the info via a datamap. This works except the wear doesn't receive the datamap from the phone although the phone says it has sent the datamap.
Wear Main Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_data_map);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
mTextView = (TextView) stub.findViewById(R.id.text);
sendMessage("Ping");
Log.i("OnLayoutInflated","LAYOUT INFLATED");
}
});
setAmbientEnabled();
// Register the local broadcast receiver
IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
MessageReceiver messageReceiver = new MessageReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
}
#Override
protected void onPause() {
super.onPause();
if (wearCommsManager.isConnected()) {
wearCommsManager.disconnectClient();
}
}
#Override
protected void onResume() {
super.onResume();
if (wearCommsManager == null) {
wearCommsManager = new WearCommsManager(this);
}
if (messageSender == null) {
messageSender = new WearMessageSender(wearCommsManager);
}
verifyCommsConnection();
}
protected void sendMessage(final String message) {
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {;
messageSender.processRequest(message);
return null;
}
};
task.execute();
}
private void verifyCommsConnection() {
new WearCommsManager(this).verifyCommsConnection(new WearCommsManager.CommsCallback() {
#Override
public void onSuccess() {
}
#Override
public void onFailure() {
Log.e("ERROR","CONNECTION FAILED");
}
});
}
public class MessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle data = intent.getBundleExtra("datamap");
// Display received data in UI
String display =
data.getString("city") + "\n" +
data.getString("temperature") + "\n" +
data.getString("wind_speed") + "\n" +
data.getString("cloud_percent")+"\n"+
data.getString("lastupdate");
mTextView.setText(display);
}
}
Wear Listener:
public class ListenerService extends WearableListenerService{
private static final String WEARABLE_DATA_PATH = "/wearable_data";
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
DataMap dataMap;
for (DataEvent event : dataEvents) {
Log.v("myTag", "DataMap received on watch: " + DataMapItem.fromDataItem(event.getDataItem()).getDataMap());
// Check the data type
if (event.getType() == DataEvent.TYPE_CHANGED) {
// Check the data path
String path = event.getDataItem().getUri().getPath();
if (path.equals(WEARABLE_DATA_PATH)) {}
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
// Broadcast DataMap contents to wearable activity for display
// The content has the golf hole number and distances to the front,
// middle and back pin placements.
Intent messageIntent = new Intent();
messageIntent.setAction(Intent.ACTION_SEND);
messageIntent.putExtra("datamap", dataMap.toBundle());
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
}
}
}
}
Phone Main Activity:
public class DataMapActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
private TextView cityName;
private TextView temp;
private ImageView iconView;
private TextView description;
private TextView humidity;
private TextView pressure;
private TextView wind;
private TextView sunrise;
private TextView sunset;
private TextView updated;
Weather weather = new Weather();
GoogleApiClient googleClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_data_map);
cityName = (TextView) findViewById(R.id.cityText);
iconView = (ImageView) findViewById(R.id.thumbnailIcon);
temp = (TextView) findViewById(R.id.tempText);
description = (TextView) findViewById(R.id.CloudText);
humidity = (TextView) findViewById(R.id.HumidText);
pressure = (TextView) findViewById(R.id.PressureText);
wind = (TextView) findViewById(R.id.WindText);
sunrise = (TextView) findViewById(R.id.RiseText);
sunset = (TextView) findViewById(R.id.SetText);
updated = (TextView) findViewById(R.id.UpdateText);
CityPreference cityPreference=new CityPreference(DataMapActivity.this);
System.out.println(cityPreference.getCity());
renderWeatherData(cityPreference.getCity());
IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
MessageReceiver messageReceiver = new MessageReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
// Build a new GoogleApiClient for the the Wearable API
googleClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
public void renderWeatherData(String city) {
WeatherTask weatherTask = new WeatherTask();
weatherTask.execute(new String[]{city + "&units=metric"});
}
private class WeatherTask extends AsyncTask<String, Void, Weather> {
#Override
protected Weather doInBackground(String... params) {
String data = ((new WeatherHttpClient()).getWeatherData(params[0]));
System.out.println(data);
weather = JSONParser.getWeather(data);
return weather;
}
#Override
protected void onPostExecute(Weather weather) {
super.onPostExecute(weather);
if(weather.currentCondition.getIcon() != null){
new DownloadImageAsyncTask().execute(weather.currentCondition.getIcon());
}
cityName.setText(weather.place.getCity() + "," + weather.place.getCountry());
temp.setText("" + (int)weather.currentCondition.getTemperature() + "°C");
wind.setText("Wind Speed: " + weather.wind.getSpeed()+"m/s" + " Degree: " + weather.wind.getDegree());
description.setText("Clouds: " + weather.clouds.getPrecipitation() + "%, " + weather.currentCondition.getDescription());
pressure.setText("Pressure: " + weather.currentCondition.getPressure()+"hpa");
humidity.setText("Humidity: " + weather.currentCondition.getHumidity()+"%");
Date mydate = new Date(weather.place.getSunrise() * 1000);
SimpleDateFormat dateformat = new SimpleDateFormat("HH:mm");
dateformat.setTimeZone(TimeZone.getTimeZone("GMT+3"));
String date = dateformat.format(mydate);
sunrise.setText("Sunrise: " + date);
mydate = new Date(weather.place.getSunset() * 1000);
date = dateformat.format(mydate);
sunset.setText("Sunset: " + date);
mydate = new Date(weather.place.getLastupdate() * 1000);
dateformat = new SimpleDateFormat("dd.MM.yyyy, HH:mm, z");
dateformat.setTimeZone(TimeZone.getDefault());
date = dateformat.format(mydate);
updated.setText("Last Updated: " + date);
sendWear();
//This part synchronizes perfectly with wear
}
}
private void sendWear(){
String WEARABLE_DATA_PATH = "/wear_data";
// Create a DataMap object and send it to the data layer
DataMap dataMap = new DataMap();
dataMap.putString("lastupdate", updated.getText().toString());
dataMap.putString("city", cityName.getText().toString());
dataMap.putString("temperature", temp.getText().toString());
dataMap.putString("wind_speed", wind.getText().toString());
dataMap.putString("cloud_percent", description.getText().toString());
//Requires a new thread to avoid blocking the UI
new SendToDataLayerThread(WEARABLE_DATA_PATH, dataMap).start();
}
public class MessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String s= intent.getStringExtra("Pinger");
if(s!=null) {
new SendToWearAsyncTask().execute();
}
}
}
private class SendToWearAsyncTask extends AsyncTask<Void,Void,Void>{
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
sendWear();
//this part wear doesn't receive the datamap
}
#Override
protected Void doInBackground(Void... params) {
return null;
}
}

Make sure that the applicationID were the same in the build.gradle for mobile and wear app. Also make sure that the buildTypes part and the signingConfigs part are the same in both apps. Source. You can also send Long.toString(System.currentTimeMillis()) to verify that as it changes every time.

Related

Getting different response on voice input and text input using dialog flow in android

I am creating an android app chatbot using google's dialog flow (API.AI). The problem is, If I am sending text input for my intents,it is giving right response, whereas if same thing I am sending using voice input, am getting wrong response. I am not able to understand what is the problem.
Here is my code :-
public class MyChatActivity extends AppCompatActivity implements View.OnClickListener, AIListener {
public String TAG = this.getClass().getSimpleName();
private List<ChatMessageBean> chatList = new ArrayList<>();
private String CLIENT_ACCESS_TOKEN = "My dialog flow agent's client access token";
AIConfiguration config;
AIService aiService;
AIRequest aiRequest;
AIDataService aiDataService;
TextToSpeech textToSpeech;
RecyclerView chatRecyclerView,menuRecyclerView;
ChatMessageListAdapter chatMessageListAdapter;
FloatingActionButton sendMessageButton,recordMessageButton;
EditText enterMessage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_chat_activity);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initializeVariables();
setListeners();
}
public void initializeVariables() {
config = new AIConfiguration(CLIENT_ACCESS_TOKEN, AIConfiguration.SupportedLanguages.English, AIConfiguration.RecognitionEngine.System);
aiService = AIService.getService(getApplicationContext(), config);
aiRequest = new AIRequest();
aiDataService = new AIDataService(getApplicationContext(), config);
chatRecyclerView = (RecyclerView) findViewById(R.id.chat_list_recycler_view);
setMenuRecyclerView();
enterMessage = (EditText) findViewById(R.id.enter_text_message);
sendMessageButton = (FloatingActionButton) findViewById(R.id.send_message_button);
recordMessageButton =(FloatingActionButton) findViewById(R.id.record_message_button);
textToSpeech = new TextToSpeech(getApplicationContext(),new TextToSpeech.OnInitListener(){
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR) {
textToSpeech.setLanguage(Locale.US);
}
}
});
}
public void setListeners() {
sendMessageButton.setOnClickListener(this);
aiService.setListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.record_message_button:
aiService.startListening();
break;
case R.id.send_message_button:
String message = enterMessage.getText().toString().trim();
enterMessage.setText("");
sendMessage(message);//sending message with text input
break;
}
}
private boolean validateMessage(String message) {
if ((message.equals("")) || (message.isEmpty()) || (message.length() == 0))
return false;
return true;
}
public void sendMessage(String message) {
// In this method i am sending the message to dialog flow
if (validateMessage(message)) {
ChatMessageBean chatMessageBean = new ChatMessageBean(message); // this is the bean I am using for chatbot app's messages
chatList.add(chatMessageBean);
chatMessageListAdapter = new ChatMessageListAdapter(chatList);// this is the adapter for recycler view that I am using for app's messages
chatRecyclerView.setAdapter(chatMessageListAdapter);
chatRecyclerView.setLayoutManager(new LinearLayoutManager(this));
aiRequest.setQuery(message);
new AsyncTask<AIRequest, Void, AIResponse>() {
#Override
protected AIResponse doInBackground(AIRequest... aiRequests) {
final AIRequest request = aiRequests[0];
try {
final AIResponse response = aiDataService.request(aiRequest);
return response;
} catch (AIServiceException e) {
}
return null;
}
#Override
protected void onPostExecute(AIResponse response) {
if (response != null) {
Result result = response.getResult();
String reply = result.getFulfillment().getSpeech();
ChatMessageBean chatMessageBean = new ChatMessageBean(reply.trim());
chatList.add(chatMessageBean);
chatMessageListAdapter = new ChatMessageListAdapter(chatList);
chatRecyclerView.setLayoutManager(new LinearLayoutManager(PersonaAssistantChatActivity.this));
chatRecyclerView.setAdapter(chatMessageListAdapter);
textToSpeech.speak(reply,TextToSpeech.QUEUE_FLUSH,null);
if(reply.trim().equalsIgnoreCase(API_ACCESS_STRING)){ //API_ACCESS_STRING is the string after which I have to get response from my own defined intents. So I am cheking if the reply is equal to API_ACCESS_STRING
String intentName=result.getMetadata().getIntentName();
switch(intentName){
case "AvailableEmployees":
Log.d(TAG, "CallIntents: AvailableEmployees:"+intentName);
String jobName=result.getStringParameter("JobName");
String date = result.getStringParameter("Date");
Log.d(TAG,"JobName:"+jobName+"date: "+date); // When I send voice input here I get jobName="AvailableEmployees" automatically, and dialog flow doesnot ask for jobName, where as with text input I get everything right.
}
}
}
}
}.execute(aiRequest);
} else {
Toast.makeText(getApplicationContext(), "Please enter some text first or record your message", Toast.LENGTH_LONG).show();
}
}
#Override
public void onResult(AIResponse result) {
String message= result.getResult().getResolvedQuery().toString().trim();
sendMessage(message);//sending message with voice input
}
#Override
public void onError(AIError error) {
Log.i(TAG, ": onError" + error);
}
#Override
public void onAudioLevel(float level) {
Log.i(TAG, ": onAudioLevel:" + level);
}
#Override
public void onListeningStarted() {
Log.i(TAG, ": onListeningStarted");
}
#Override
public void onListeningCanceled() {
Log.i(TAG, ": onListeningCanceled");
}
#Override
public void onListeningFinished() {
Log.i(TAG, ": onListeningFinished");
}
}
You can not call sendMessage(message);//sending message with voice input in the onResult method. This method is called when aiService finishes listening and has already sent a request to Dialogflow and you get the response. When you call aiService.startListening(); the service detect what the user is saying and sends it to Dialogflow.
If you want to know the text "aiService" is sending to Dialogflow you have to use PartialResultsListener and implement it:
#Override
public void onPartialResults(final List<String> partialResults) {
if (!partialResults.isEmpty()) {
String partialResult = partialResults.get(0);
}
}
That way you will get what the user says, but be aware as the method will be called BEFORE onListeningFinished() ends.
Best of luck playing with Handler.postDelayed() :)

How to restart Handler after changing data value?

Good morning StackOverFlow i'm having some issues with Handler i'm trying to start in the MainActivity my Client.java after 50 seconds and also send the message and stop the client and that's work but i have to reopen the connection on every change of ip_txt or term_txt in settings.java
(data is saved from a EditText to DB by clicking on a button )
here is my MainActivity :
public class MainActivity extends AppCompatActivity {
Server server;
Client client;
Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
new ConnectTask().execute("");
if (client != null) {
client.sendMessage("IP#" + ipp + " " + "N#" + trm);
}
if (client != null) {
client.stopClient();
}
}
};
settings Settings;
public static TextView terminale, indr, msg;
TextView log;
String ipp,trm;
DataBaseHandler myDB;
allert Allert;
SharedPreferences prefs;
String s1 = "GAB Tamagnini SRL © 2017 \n" +
"Via Beniamino Disraeli, 17,\n" +
"42124 Reggio Emilia \n" +
"Telefono: 0522 / 38 32 22 \n" +
"Fax: 0522 / 38 32 72 \n" +
"Partita IVA, Codice Fiscale \n" +
"Reg. Impr. di RE 00168780351 \n" +
"Cap. soc. € 50.000,00 i.v. \n" + "" +
"REA n. RE-107440 \n" +
"presso C.C.I.A.A. di Reggio Emilia";
ImageButton settings, helps, allerts, home;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Utils.darkenStatusBar(this, R.color.colorAccent);
server = new Server(this);
myDB = DataBaseHandler.getInstance(this);
msg = (TextView) findViewById(R.id.msg);
log = (TextView) findViewById(R.id.log_avviso);
settings = (ImageButton) findViewById(R.id.impo);
helps = (ImageButton) findViewById(R.id.aiut);
allerts = (ImageButton) findViewById(R.id.msge);
home = (ImageButton) findViewById(R.id.gab);
terminale = (TextView) findViewById(R.id.terminal);
indr = (TextView) findViewById(R.id.indr);
final Cursor cursor = myDB.fetchData();
if (cursor.moveToFirst()) {
do {
indr.setText(cursor.getString(1));
terminale.setText(cursor.getString(2));
Client.SERVER_IP = cursor.getString(1);
trm = cursor.getString(2);
} while (cursor.moveToNext());
}
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
ipp = Formatter.formatIpAddress(wm.getConnectionInfo().getIpAddress());
handler.postDelayed(runnable,5000);
cursor.close();
server.Parti();
home.setOnClickListener(new View.OnClickListener() {
int counter = 0;
#Override
public void onClick(View view) {
counter++;
if (counter == 10) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setCancelable(true);
builder.setMessage(s1);
builder.show();
counter = 0;
}
}
});
settings.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent impostazioni = new Intent(getApplicationContext(), settingsLogin.class);
startActivity(impostazioni);
}
});
helps.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent pgHelp = new Intent(getApplicationContext(), help.class);
startActivity(pgHelp);
}
});
allerts.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Server.count = 0;
SharedPreferences prefs = getSharedPreferences("MY_DATA", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.clear();
editor.apply();
msg.setVisibility(View.INVISIBLE);
Intent pgAlert = new Intent(getApplicationContext(), allert.class);
startActivity(pgAlert);
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
server.onDestroy();
}
public class ConnectTask extends AsyncTask<String, String, Client> {
#Override
protected Client doInBackground(String... message) {
client = new Client(new Client.OnMessageReceived() {
#Override
public void messageReceived(String message) {
publishProgress(message);
}
});
client.run();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
Log.d("test", "response " + values[0]);
}
}
}
Here is my settings.java:
public class settings extends AppCompatActivity {
TextView indr;
Client client;
EditText ip_txt,term_txt;
ImageButton home;
Button save;
DataBaseHandler myDB;
MainActivity activity;
String ipp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myDB = DataBaseHandler.getInstance(this);
setContentView(R.layout.activity_settings);
Utils.darkenStatusBar(this, R.color.colorAccent);
home = (ImageButton) findViewById(R.id.stgbtn);
indr = (TextView) findViewById(R.id.ipp);
ip_txt = (EditText) findViewById(R.id.ip);
term_txt = (EditText) findViewById(R.id.nTermin);
save = (Button) findViewById(R.id.save);
Cursor cursor = myDB.fetchData();
if(cursor.moveToFirst()){
do {
ip_txt.setText(cursor.getString(1));
term_txt.setText(cursor.getString(2));
}while(cursor.moveToNext());
}
cursor.close();
AddData();
home.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
ipp = Formatter.formatIpAddress(wm.getConnectionInfo().getIpAddress());
indr.setText(ipp);
}
public void AddData() {
save.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
myDB.insertData(ip_txt.getText().toString(),
term_txt.getText().toString());
MainActivity.indr.setText(ip_txt.getText().toString());
MainActivity.terminale.setText(term_txt.getText().toString());
Client.SERVER_IP = ip_txt.getText().toString();
finish();
}
}
);
}
}
( If I did not explain it i want to start the handler on the start of the app and also to start it again or immediatly after i change the data in EditText ip_txt or in EditText term_txt )
I would create Variables to store the handler and the runnable, then when you want to restart it just use:
yourHandler.removeCallback(yourRunnable);
yourHandler.postDelayed(yourRunnable,time);
and to start it, just do it as you did,
yourHandler.postDelayed(yourRunnable,5000);
Hope is what you are looking for.
How to create them:
public class ClassName{
Handler yourHandler = new Handler();
Runnable yourRunnable = new Runnable(){
#Override
public void run() {
//yourCode
}
};
// Rest of class code
}
Is just same as you did in your code but in a variable.

AsyncTask and custom listener

I have a list with RadioButtons. When the user selects an item, AsyncTask should start. I created an interface to send events to the adapter. When the download starts, it should open ProgressDialog. I can't get a reference ProgressDialog after screen rotation. In the logs it says that progressDialog != null and progressDialog.isShowing = true while dialog disappears from the window. How can I retrieve this reference and why the dialogue has retained its state when I turned the screen?
Adapter:
...
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final ProgressDialog dialog = new ProgressDialog(getContext());
dialog.setIndeterminate(false);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
Log.d(LOG_TAG, getClass().getSimpleName() + ": click ");
checked = position;
notifyDataSetChanged();
if (translationDownloadTask != null) {
translationDownloadTask.cancel(true);
}
translationDownloadTask = new TranslationDownloadTask(translations[position], translations[position]);
translationDownloadTask.setListener(new OnFileDownloadListener() {
#Override
public void onStartDownloading(String title) {
dialog.show();
}
#Override
public void onProgress(String title, int progress) {
dialog.setProgress(progress);
Log.d(LOG_TAG, getClass().getSimpleName() + ": progressDialog " + dialog.isShowing());
}
#Override
public void onDonwloadingComplete() {
}
#Override
public void onError() {
}
});
translationDownloadTask.execute();
}
});
...
AsyncTask:
public class TranslationDownloadTask extends AsyncTask<Void, Integer, Void> {
private static final String LOG_TAG = "myQuranTag";
String url;
String progressDialogTitle;
OnFileDownloadListener listener;
public void setListener(OnFileDownloadListener listener){
this.listener = listener;
}
public TranslationDownloadTask(String url, String title) {
this.url = url;
this.progressDialogTitle = title;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
listener.onStartDownloading(progressDialogTitle);
Log.d(LOG_TAG, getClass().getSimpleName() + ": Начало " );
}
#Override
protected Void doInBackground(Void... params) {
int lenght = 30;
for (int i = 0; i < lenght; i++) {
try {
if (!isCancelled()){
Thread.sleep(200);
int progress = i*100/lenght;
publishProgress(progress);
}else {
listener.onError();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
listener.onDonwloadingComplete();
Log.d(LOG_TAG, getClass().getSimpleName() + ": Задача завершена ");
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
listener.onProgress(progressDialogTitle, values[0]);
}
}
OnFileDownloadListener:
public interface OnFileDownloadListener {
void onStartDownloading(String title);
void onProgress(String title, int progress);
void onDonwloadingComplete();
void onError();
}
I think you should assign dialog to a ProgressDialog before anything
private ProgressDialog dialog;
and change from this one to this one:
final ProgressDialog dialog = new ProgressDialog(getContext());
to this one:
final ProgressDialog dialog = new ProgressDialog(getActivity());

Service and activity communication....update UI when data is received from service

I am trying to implement a app which updates user location at every 15 seconds,stores data to database and show it to listview in my activity.
Location should always update even activity destroys,for that i have created LocationService class.
The problem is I am able to get updates and also able to store into database but i am unable to show these updates in listview at runtime means i want list should refresh at every 15 sec and show it to UI..
Also when I get details from database I am unable to get latest detail instead i get whole arraylist every time which affects my activity response.I want that only newly added data will be fetch from database so that it will take less time in loading but I want to display all data to list everytime.
I have implement a thread (Commented code)which fetch data and show to listview but this is not right way to update UI..please suggest me a way so that i can refresh my list when new data is added into database
This is my activity
public class MainActivity extends Activity {
List<MyLocation> locationList = new ArrayList();
ListView mList;
LocationAdapter adapter;
BroadcastReceiver receiver;
LocationService mService;
boolean mBound = false;
private DbHelper dbHelper;
private Button updateLocation;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
LocationService.LocalBinder binder = (LocationService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
updateLocation = (Button) findViewById(R.id.update_location);
mList = (ListView) findViewById(R.id.listView);
dbHelper = new DbHelper(this);
updateLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
locationList = mService.displayLocation();
adapter = new LocationAdapter(MainActivity.this, locationList);
mList.setAdapter(adapter);
}
});
/*
Thread mThread = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(500);
runOnUiThread(new Runnable() {
#Override
public void run() {
locationList = dbHelper.getLocationDetails();
Collections.reverse(locationList);
adapter = new LocationAdapter(MainActivity.this, locationList);
mList.setAdapter(adapter);
}
});
}
} catch (InterruptedException e) {
}
}
};
mThread.start();*/
}
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, LocationService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}
LocationService
public class LocationService extends Service implements LocationListener, GoogleApiClient.ConnectionCallbacks {
private final IBinder mBinder = new LocalBinder();
ArrayList<MyLocation> locationList = new ArrayList<>();
private DbHelper dbHelper;
private Location mLocation;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private String TAG = "Service";
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addApi(LocationServices.API).build();
mGoogleApiClient.connect();
dbHelper = new DbHelper(this);
createLocationRequest();
displayLocation();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "service destroy");
}
public List<MyLocation> displayLocation() {
mLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
if (mLocation != null) {
double latitude = mLocation.getLatitude();
double longitude = mLocation.getLongitude();
String lastUpdateTime = DateFormat.getTimeInstance().format(new Date());
dbHelper.insertLocationDetails(longitude, latitude, lastUpdateTime);
locationList = dbHelper.getLocationDetails();
return locationList;
} else {
return null;
}
}
protected void startLocationUpdates() {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
Log.d(TAG, "Connected to update");
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
public void onLocationChanged(Location location) {
mLocation = location;
Toast.makeText(getApplicationContext(), "Location changed",
Toast.LENGTH_SHORT).show();
displayLocation();
}
public void onConnected(Bundle arg0) {
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int arg0) {
mGoogleApiClient.connect();
}
public class LocalBinder extends Binder {
public LocationService getService() {
return LocationService.this;
}
}
}
Dbhelper
public class DbHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String LONGITUDE = "longitude";
private static final String LATITUDE = "latitude";
private static final String LOCATION_CHANGE_TIME = "location_change_time";
private static final String LOCATION_DETAIL_TABLE = "location_detail_table";
private static final String CREATE_TABLE_LOCATION = "CREATE TABLE "
+ LOCATION_DETAIL_TABLE + " (" + LONGITUDE + " TEXT,"
+ LOCATION_CHANGE_TIME + " TEXT,"
+ LATITUDE + " TEXT)";
public static String DATABASE_NAME = "Location_database";
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(CREATE_TABLE_LOCATION);
}
public void insertLocationDetails(double longitude, double latitude, String time) {
SQLiteDatabase database = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(LONGITUDE, longitude);
values.put(LATITUDE, latitude);
values.put(LOCATION_CHANGE_TIME, time);
long id= database.insert(LOCATION_DETAIL_TABLE, null, values);
System.out.println("Newly added item id "+id);
database.close();
}
public ArrayList<MyLocation> getLocationDetails() {
ArrayList<MyLocation> locationList = new ArrayList();
String selectQuery = "SELECT * FROM " + LOCATION_DETAIL_TABLE;
SQLiteDatabase database = this.getReadableDatabase();
Cursor cursor = database.rawQuery(selectQuery, null);
if (cursor.moveToNext()) {
do {
MyLocation location = new MyLocation();
String longitude = cursor.getString(cursor
.getColumnIndexOrThrow(LONGITUDE));
String latitude = cursor.getString(cursor.getColumnIndexOrThrow(LATITUDE));
String time = cursor.getString(cursor
.getColumnIndexOrThrow(LOCATION_CHANGE_TIME));
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setLastUpdatedTime(time);
locationList.add(location);
} while (cursor.moveToNext());
}
if (cursor != null) {
cursor.close();
}
database.close();
return locationList;
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
In your case, you can use ContentProvider and implements LoaderManager.LoaderCallbacks in your activity.
#Nullable
#Override
public Uri insert(Uri uri, ContentValues values) {
db = dbHelper.getWritableDatabase();
String table = uri.getLastPathSegment();
long rowID = db.insert(table, null, values);
Uri CONTENT_URI = Uri.parse("content://"
+ AUTHORITY + "/" + table);
Uri resultUri = ContentUris.withAppendedId(CONTENT_URI, rowID);
getContext().getContentResolver().notifyChange(resultUri, null);
return resultUri;
}
Line
getContext().getContentResolver().notifyChange(resultUri, null);
in ContentProvider will cause requery data. And using SimpleAdapter in activity will update your UI.
You can use Callback for this purpose.
Define some interface like
public class LocationInterface(){
public void sendLocationDetails(Long lat, Long lon, String time);
}
Now let your Activity implement this interface.
public class MyActivity implements LocationInterface {
#Override
public void sendLocationDetails(Long lat, Long lon, String time){
//At this point, you have the required details
}
}
Now in LocationService.java you need to pass this interface as an argument.
public class LocationService {
private LocationInterface locationInterface;
LocationInterface(LocationInterface locationInterface){
this.locationInterface = locationInterface;
}
}
Now whenever you call displayLocation() method, you can call this interface and send data to the activity.
public List<MyLocation> displayLocation() {
mLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
if (mLocation != null) {
double latitude = mLocation.getLatitude();
double longitude = mLocation.getLongitude();
String lastUpdateTime = DateFormat.getTimeInstance().format(new Date());
//At this point, you are calling the interface.
locationInterface.sendDetails(latitude,longitude,lastUpdateTime);
dbHelper.insertLocationDetails(longitude, latitude, lastUpdateTime);
locationList = dbHelper.getLocationDetails();
return locationList;
} else {
return null;
}
}

Calling notifyOnDataSetChanged in AsyncTask (not within the class)

*************PROBLEM FIXED, CHECK BELOW FOR A SOLUTION*************
I have been struggling with that nearly half a day. Cannot get it work properly.
I have AsyncTask with private method, so I can pass boolean and String values in CustomLvAdapter
private void changeJobStatus(final boolean isAppliedforAJob, final String jobID){
class ChangeJobStatus extends AsyncTask<Void,Void,String> {
//private Delegates del = null;
ProgressDialog loading;
#Override
protected void onPreExecute() {
super.onPreExecute();
if(isAppliedforAJob) {
loading = ProgressDialog.show(context, "","Canceling application", false);
}
else {
loading = ProgressDialog.show(context, "","Applying for position", false);
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//del.asyncCompleteOnCustomJob(true);
loading.dismiss();
}
#Override
protected String doInBackground(Void... v) {
String res;
HashMap<String,String> params = new HashMap<>();
params.put(Config.KEY_USER_ID, studentID);
params.put(Config.KEY_JOB_ID, jobID);
RequestHandler rh = new RequestHandler();
if(isAppliedforAJob)
res = rh.sendPostRequest(Config.URL_CANCEL_APPLICATION, params);
else
res = rh.sendPostRequest(Config.URL_APPLY_FOR_A_JOB, params);
Log.d("Stringas", "CustomListViewBackground " + res);
return res;
}
}
ChangeJobStatus cjs = new ChangeJobStatus();
cjs.execute();
}
and in onPostExcecute() I want to call notifyOnDataSetChanged() to my another activity lvAdapters.
As far as I read I have to implement delegate interface, but I didnt succeed doing that. I fail at initializing delegate in my main class, because changeJobStatus method is private and it is called in customLvAdapter class.
If I make a constructor in ChangeJobStatus class
public ChangeJobStatus(Delegates delegate)
{
this.del = delegate;
}
I have to pass something in the parameters, when excecuting it. If I pass new Delegate, my delegate implementation, which is in my another activity is not triggered.
ChangeJobStatus cjs = new ChangeJobStatus(new Delegates() {
#Override
public void asyncCompleteOnCustomJob(boolean success) {
//whatever
}
});
cjs.execute();
I hope you can help me figure out right implementation for that,
Cheers
***********SOLUTION***********
Sadly, I couldn't implement what fellow user gave to me, but I am very glad that I heard from one of you I can use broadcast receiver. And it worked.
This is what I did
Create a Broadcast Receiver in your main class
private final BroadcastReceiver broadcastJobList = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//what will happen, when event triggers
}
};
Register custom intent and register it to Broadcast receiver in your main class onCreate method or wherever you feel comfortable :)
IntentFilter filter = new IntentFilter();
filter.addAction("jobListChanged");
registerReceiver(broadcastJobList, filter);
All we left to do is send intent which will trigger Broadcast receiver. Following code in my scenario went to onPostExcecute method in custom adapter (context was initialized for Context at the beggining of custom adapter)
Intent intent = new Intent();
intent.setAction("jobListChanged");
context.sendBroadcast(intent);
Hope I will help anyone that has this problem. Cheers!
// your asynctask class
public class ChangeJobStatus extends AsyncTask<String, Void, String> {
private ProgressDialog loading;
private OnResponseListener responseListener;
private boolean isAppliedforAJob;
private Context con;
public ChangeJobStatus(Context con,boolean state) {
super();
// TODO Auto-generated constructor stub
this.con=con;
isAppliedforAJob = state;
}
public void setOnResponseListener(OnResponseListener onLoadMoreListener) {
this.responseListener = onLoadMoreListener;
}
public interface OnResponseListener {
public void onResponse(String responsecode);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if (isAppliedforAJob) {
loading = ProgressDialog.show(con, "", "Canceling application", false);
} else {
loading = ProgressDialog.show(con, "", "Applying for position", false);
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// del.asyncCompleteOnCustomJob(true);
loading.dismiss();
responseListener.onResponse(s);
}
#Override
protected String doInBackground(String... param) {
String res="";
HashMap<String, String> params = new HashMap<>();
params.put(Config.KEY_JOB_ID, param[0]);// job id
params.put(Config.KEY_USER_ID, param[1]);// student id
RequestHandler rh = new RequestHandler();
if (isAppliedforAJob)
res = rh.sendPostRequest(Config.URL_CANCEL_APPLICATION, params);
else
res = rh.sendPostRequest(Config.URL_APPLY_FOR_A_JOB, params);
return res;
}
}
in your activity class
public class MainActivity extends Activity implements OnResponseListener {
String jobId="1",studId="1";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ChangeJobStatus cbs=new ChangeJobStatus(this, true);
cbs.setOnResponseListener(this);
cbs.execute(jobId,studId);
}
#Override
public void onResponse(String responsecode) {
// TODO Auto-generated method stub
//here u can do ur stuff with the string
}
}

Categories

Resources