I am new to android studio, I am making an app that gets the json of a field in thingspeak, but I don't know how can I make an auto refresh to the data I get every second. Can you please help me?
public class MainActivity extends AppCompatActivity {
private TextView mTextViewResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextViewResult = findViewById(R.id.text_view_result);
OkHttpClient client = new OkHttpClient();
// Read field url from thingspeak
String url = "https://api.thingspeak.com/channels/XXXXXXX/fields/1.json?api_key=XXXXXXXXXXXXX&results=2";
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onResponse(#NonNull okhttp3.Call call, #NonNull Response response) throws IOException {
if (response.isSuccessful()) {
// this is what I want to refresh every second
final String myResponse = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mTextViewResult.setText(myResponse);
}
});
}
}
});
}
}
I found a solution finally, I placed the data request inside the following code and it worked perfectly:
final Handler handler = new Handler();
Runnable refresh = new Runnable() {
#Override
public void run() {
// data request
handler.postDelayed(this, 5000);
}
};
handler.postDelayed(refresh, 5000);
Use a CountDown Timer . Set the timer for 1 second and in onFinish method call request data .
new CountDownTimer(1000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//Request Data
}
}.start();
Related
So, I was bothering with this issue.
I have in my code value named
public String currentSong = "artist- title";
and I use it in code like this
private MetadataOutput getSongTime() {
return new MetadataOutput() {
#Override
public void onMetadata(Metadata metadata) {
final int length = metadata.length();
if (length > 0) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(existingURL.split("play")[0] + "currentsong").build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e) {
call.cancel();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
currentSong = response.body().toString();
}
});
Toast.makeText(RadioService.this, currentSong, Toast.LENGTH_SHORT).show();
}
}
};
}
But value in Toast is always behind the change (on second run it have value I expected on first run)
Is there any way to make it work correctly?
currentSong get the value on the onResponse, and its asynchronous
You must wait the response to show the Toast Message
#Override
public void onResponse(Call call, Response response) throws IOException {
currentSong = response.body().toString();
// you new a new Thread to show info in the screen beacausre the methos is asynchronous
Activity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// show toast here
}
}
}
I'm new to android studio and I'm trying to create a simple weather app using OpenWeatherMap API. I am using OkHttp library to perform a GET request. All it does is take an input throught EditText and update the TextView on button click using a Button.
But the problem is, the TextView updates after two clicks on the Button. I want to update it right after the first click. So, how do I go over this?
Here is my code:
public class MainActivity extends AppCompatActivity {
private EditText cityName;
private TextView weatherData;
private TextView hiddenText;
private Button getBtn;
public String s = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
weatherData = (TextView)findViewById(R.id.weatherText);
getBtn = (Button)findViewById(R.id.getData);
cityName = (EditText)findViewById(R.id.cityName);
getBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getWeatherData(cityName.getText().toString());
weatherData.setText(s);
}
});
}
public void getWeatherData(String cityText){
String url = "https://api.openweathermap.org/data/2.5/weather?q=" + cityText + "&appid=ba45ceb57328448f7wd666hdc6d57aaf";
OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
s = "Something went wrong!";
}
});
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if(response.isSuccessful()){
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
try{
s = response.body().string();
}
catch (IOException ioe){
s = "Error while getting JSON.";
}
}
});
}
}
});
}
}
I know that I can update the TextView in onResponse itself but I wanna know if it is possible to update it through onClickListener. If it's not possible, which method should I use? Any help would be appreciated.
you have to update text value in server response call back
public class MainActivity extends AppCompatActivity {
private EditText cityName;
private TextView weatherData;
private TextView hiddenText;
private Button getBtn;
public String s = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
weatherData = (TextView)findViewById(R.id.weatherText);
getBtn = (Button)findViewById(R.id.getData);
cityName = (EditText)findViewById(R.id.cityName);
getBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getWeatherData(cityName.getText().toString());
}
});
}
public void getWeatherData(String cityText){
String url = "https://api.openweathermap.org/data/2.5/weather?q=" + cityText + "&appid=ba45ceb57328448f7wd666hdc6d57aaf";
OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
s = "Something went wrong!";
}
});
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if(response.isSuccessful()){
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
try{
s = response.body().string();
weatherData.setText(s);
}
catch (IOException ioe){
s = "Error while getting JSON.";
}
}
});
}
}
});
}
}
You are setting data on edit text on click after calling GET Request.
Update the textview with the data , once you get the response.
public class MainActivity extends AppCompatActivity {
private EditText cityName;
private TextView weatherData;
private TextView hiddenText;
private Button getBtn;
public String s = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
weatherData = (TextView)findViewById(R.id.weatherText);
getBtn = (Button)findViewById(R.id.getData);
cityName = (EditText)findViewById(R.id.cityName);
getBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getWeatherData(cityName.getText().toString());
}
});
}
public void getWeatherData(String cityText){
String url = "https://api.openweathermap.org/data/2.5/weather?q=" + cityText + "&appid=ba45ceb57328448f7wd666hdc6d57aaf";
OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
s = "Something went wrong!";
}
});
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if(response.isSuccessful()){
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
try{
s = response.body().string();
weatherData.setText(s);
}
catch (IOException ioe){
s = "Error while getting JSON.";
}
}
});
}
}
});
}
}
I'm looking on a way to run this task repeatedly with the listener. Right now, this is working but I'm looking on a way to make it repeatedly every 10 seconds.
Activity
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
VolleyRequest.makeRequest(this, URL, listenerResponse, listenerError);
}
private static final String URL = "https://naqil.ma/random.php";
private Response.Listener<JSONObject> listenerResponse = new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Toast.makeText(SecondActivity.this, "Resonse " + response.toString(), Toast.LENGTH_LONG).show();
}
};
private Response.ErrorListener listenerError = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(SecondActivity.this, "Error " + error, Toast.LENGTH_LONG).show();
}
};
}
Class making request
public class VolleyRequest {
public static void makeRequest(Context context, String url,
Response.Listener<JSONObject> listenerResponse, Response.ErrorListener listenerError) {
JsonObjectRequest requestWeather = new JsonObjectRequest(Request.Method.GET, url, null, listenerResponse,
listenerError);
Volley.newRequestQueue(context).add(requestWeather);
}
}
````
(Adapted from this answer: https://stackoverflow.com/a/10156550/2711811 )
Basically use a handler to reschedule request every 10 seconds. Handler is attached to main looper by virtue of creating it in onStart.
First, remove the VolleyRequest.makeRequest from onCreate.
Add members to SecondActivity:
private Handler myHandler;
private Runnable myRunnable;
In onStart of SecondActivity :
protected void onStart() {
super.onStart();
// Start issuing VolleyRequests repeating every 10 seconds.
myHandler = new Handler();
myHandler.post(new Runnable() {
#Override
public void run() {
SecondActivity.this.myRunnable = this;
VolleyRequest.makeRequest(
SecondActivity.this,
URL,
SecondActivity.this.listenerResponse,
SecondActivity.this.listenerError);
SecondActivity.this.myHandler.postDelayed(this, 10000);
}
};
}
And stop the repeated requests when the activity is stopped: in onStop of SecondActivity:
protected void onStop() {
super.onStop();
// check that it actually ran at least once - can't be null.
if (myRunnable != null) {
myHandler.removeCallbacks(myRunnable);
}
}
I am pretty new to Android studio, but so far, so good!
I have an android app which is up and running together with an websocket that is running on my computer.
So when both the websocket and the app is up and running.
I could write a message, which then gets printed in the websocket terminal, and the websocket also return an message which get printed on the list on my phone. Also, if the websocket receive a special message from the app, the webscocket also return a special message which is shown on and added on the list! Perfect! Isnt it?
Now what I am trying to do is that, the app listens to a special message/event from the websocket which in this case is "SuperSpecialMessage". If the websocket sends this specific message, the application is
going to react and do something. In this case make an Invisible buttong to be visible.
SO WHAT IS THE PROBLEM? The problem here is that I get the error:
"android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
Could someone help me please?
Here is my code:
public class WebSocketActivity extends AppCompatActivity {
private Socket mSocket;
private TextView mSocketStatus;
EditText messageTextview;
ListView the_list_view_on_layout;
ArrayAdapter arrayAdapter;
String TheMessages;
List<String> list_with_messages;
Button theExtraButton;
Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_websocket);
this.mHandler = new Handler();
m_Runnable.run();
// Elements that are created on the layout
mSocketStatus = (TextView)findViewById(R.id.socketStatus);
theExtraButton = (Button)findViewById(R.id.extraBtn);
theExtraButton.setVisibility(View.INVISIBLE);
the_list_view_on_layout = findViewById(R.id.listViewID);
messageTextview = findViewById(R.id.messageTextView);
String[] TheMessages = new String[]{};
list_with_messages = new ArrayList<String>(Arrays.asList(TheMessages));
//ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list_with_messages);
arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list_with_messages);
the_list_view_on_layout.setAdapter(arrayAdapter);
TheSocketClass app = (TheSocketClass) getApplication();
mSocket = app.getSocket();
mSocket.connect();
checkIfConnectedToSocket();
Button sendMessageToSocketServer = (Button) findViewById(R.id.sendMessageToSocketBtn);
sendMessageToSocketServer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String theTextWeWrite = messageTextview.getText().toString();
mSocket.emit("sendTextToServer", theTextWeWrite);
list_with_messages.add(theTextWeWrite);
//arrayAdapter.notifyDataSetChanged();
}
});
runOnUiThread(new Runnable() {
#Override
public void run() {
mSocket.on("ServerMessage", new Emitter.Listener() {
#Override
public void call(Object... args) {
JSONObject data = (JSONObject) args[0];
list_with_messages.add(data.toString());
//arrayAdapter.notifyDataSetChanged(); // I GET ERROR HERE
}
});
}
});
runOnUiThread(new Runnable() {
#Override
public void run() {
mSocket.on("SuperSpecialMessage", new Emitter.Listener() {
#Override
public void call(Object... args) {
theExtraButton.setVisibility(View.VISIBLE);
}
});
}
});
}
private void checkIfConnectedToSocket(){
mSocket.connect();
if (mSocket.connected() == true) {
mSocketStatus.setText("Connected to socket!");
mSocketStatus.setTextColor(Color.GREEN);
}
else if (!mSocket.connected()){
mSocketStatus.setText("Error connecting to socket!");
mSocketStatus.setTextColor(Color.RED);
}
}
}
Thank you.
EDIT: Solved!
First i made an method like this:
private void makeTheButtonVisible(){
runOnUiThread(new Runnable() {
#Override
public void run() {
theExtraButton.setVisibility(View.VISIBLE);
}
});
}
and when the app recieve the message, the method is called like this:
runOnUiThread(new Runnable() {
#Override
public void run() {
mSocket.on("SuperSpecialMessage", new Emitter.Listener() {
#Override
public void call(Object... args) {
makeTheButtonVisible();
}
});
}
});
I am trying to use realm database to display my api data. I want to display the company name, however the data is saids it is inserted in the log but cant seem to display the data on the UI. Here is the code..
Any help would be greatly appreciated with this problem. The variables are at the top and the problem is when it hits on success, ive written the code "write to DB", but it doesnt display the data but tells me the data has been inserted.
// Variables for the search input field and results TextViews.
private EditText mCompanyInput;
private TextView mTitleText;
private TextView mDescriptionText;
private TextView mOfficerText;
private TextView mTitleText1;
private TextView mDescriptionText1;
private OkHttpClient okHttpClient;
private static final String TAG = "MainActivity";
private Request request;
private String url = "https://api.companieshouse.gov.uk/search/companies?q=";
Button save;
TextView log;
Realm realm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCompanyInput = findViewById(R.id.companyInput);
log = findViewById(R.id.log);
mDescriptionText = findViewById(R.id.descriptionText);
mOfficerText = findViewById(R.id.officerText);
mTitleText1 = findViewById(R.id.titleText1);
mTitleText = findViewById(R.id.titleText);
mDescriptionText1 = findViewById(R.id.descriptionText1);
save = findViewById(R.id.searchButton);
realm = Realm.getDefaultInstance();
save.setOnClickListener(this);
}
public void onClick(View view){
okHttpClient = new OkHttpClient();
request = new Request.Builder().url(url).header("Authorization", "k6DNRbTp-AnQWn51JBz5VuPiTl8jv4_etdzoMyhf") .method("GET", null).build();
Log.d(TAG, "onClick:"+url);
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.i(TAG, e.getMessage());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
Log.i(TAG,response.body().string());
Log.d(TAG, "onResponse:"+response.code());
}
});
writeToDB(mCompanyInput.getText().toString().trim(), (mDescriptionText.getText().toString().trim()));
showData();
}
public void showData(){
RealmResults<Company> guests = realm.where(Company.class).findAll();
// Use an iterator to invite all guests
String op="";
for (Company guest : guests) {
op+=guest.getName();
op+=guest.getAppointments();
}
log.setText(op);
}
public void writeToDB(final String mTitleText1, final String mDescriptionText1){
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm bgRealm) {
Company user = new Company(mTitleText1, mDescriptionText1);
bgRealm.insert(user);
}
}, new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess() {
writeToDB(mCompanyInput.getText().toString().trim(), (mOfficerText.getText().toString().trim()));
showData();
// Transaction was a success.
Log.v("Database", "Data Inserted");
}
}, new Realm.Transaction.OnError() {
#Override
public void onError(Throwable error) {
// Transaction failed and was automatically canceled.
Log.e("Database", error.getMessage());
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
realm.close();
}
Why are you calling writeToDB() from the onSuccess() method? This will cause recursion and keep writing the same data into the realm. It's correct to call showData() from onSuccess(), but there's not much point calling it directly from onClick().
I think your problem though is that you're trying to update the UI from a thread: it's called from an async transaction thread and not the main thread. See this answer (and there are others you can find easily once you know the problem: Updating UI / runOnUiThread / final variables: How to write lean code that does UI updating when called from another Thread.