use thread inside buttonclick in android - multithreading

I am receiving temperature values from a sensor through BLE and storing it in my db and passing the values as an array through intent to graph activity and diplaying a line graph. I am also posting the values to google app engine. i am doing this all within runOnUiThread() and hence my app crashes when there are too many values.Is it possible to pass values into the graph activity on a new thread? or any other better suggestions?
#Override
public void propertyChange(final PropertyChangeEvent event) {
final String property = event.getPropertyName();
runOnUiThread(new Runnable() {
public void run() {
try {
if (property.equals(PROPERTY_IR_TEMPERATURE)) {
double newIRValue = (Double) event.getNewValue();
// float newIRValue_1 = (Float) event.getNewValue();
TextView textView = (TextView) findViewById(R.id.ir_temperature);
String value = decimal.format(newIRValue);
String formattedText = value + DEGREE_SYM;
float value_chk = (float)(newIRValue);
String formattedText_1 = String.valueOf(value_chk);
String sensorid = test_1;
String sensortype = "temperature";
// write_data(sensorid,sensortype,value);
// Toast.makeText(getBaseContext(), "ARV sensid:"+sensorid+" senstype:"+sensortype, Toast.LENGTH_SHORT).show();
long timemilli = System.currentTimeMillis();
//Log.d("TIMMEE", String.valueOf(timemilli));
String time=String.valueOf(timemilli);
db = new DBHandler(getApplicationContext());
//db.deleteTempReadings();
// inserting data to temp table
Log.i("insert", "Inserting Records...");
);
Temperature(sensorid,formattedText_1));
//Toast.makeText(getBaseContext(), "SENSOR_ID:"+t.getSensorId()+"TEMPERATURE: "+t.getTemperature()+"TIME: "+t.getTimestamp(), Toast.LENGTH_LONG).show();
// reading data from db
Log.i("Reading", "Reading Records...");
List<Temperature> temp = db.getAllTempReadings();
int arraySize=temp.size();
double tempArray[]=new double[arraySize];
int timeArray[]=new int [arraySize];
//Log.d("ans", String.valueOf(temp.size()));
for (Temperature t : temp) {
String log="SENSOR ID: "+t.getSensorId()+"TEMPERATURE: "+t.getTemperature()+"TIME: "+t.getTimestamp();
Log.d("Record"+t, log);
}
// Reading values into the array!
for(int i=0;i<arraySize;i++){
tempArray[i]=Double.parseDouble(temp.get(i).getTemperature());
}
Button btn=(Button)findViewBy Id(R.id.btnGraph);
btn.setOnCLickListener(new View.onClickListener(){
public void onClick(View v){
Intent iIntent =new Intent(getApplicationContext(),GraphActivity.class);
tIntent.putExtra("tempArray",tempArray);
startActivity(tIntent);
}
});
// rest....posting to server code......
textView.setText(formattedText);
}
}
}
}
}

The temperature value you get from the sensor upto this you have to do stuff in one thread and after that you have to start three thread one for the inserting into the DB, the other one for the displaying the line graph and the last and the third one for the posting the data into the google app engine.

I think you are a bit confused here. The idea is to keep slow processing OUT of your UI thread. I suggest you do the writes to the DB and the App engine first in the 'current' (presumably less critical) thread and then when all is done simply update the graph display in the UI thread.
The only reason you need RunOnUiThread is to make changes to the views on the screen.

Related

Is there a way of displaying 2 input for QR code in android

So I’m creating an android app for queuing and it uses a QR code for reference and when scanned should display date and time of the chosen schedule but my code only displays one value when scanned
This is my code
String name;
setContentView(R.layout.deposit_gen);
dl_dep = findViewById(R.id.deposit_download);
qr_dep = findViewById(R.id.qr_deposit);
try {
bitmap = textToImageEncode(select_date.getText().toString().trim());
qr_dep.setImageBitmap(bitmap);
dl_dep.setVisibility(View.VISIBLE);
dl_dep.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "code_scanner",
null);
Toast.makeText(Deposit.this, "Saved to Gallery", Toast.LENGTH_LONG).show();
}
});
select_date is the variable for chosen dates and time is time

Android studio, why does progressbar disappear before asynctasks are complete?

I have the following Asyntask in Android Studio.
I'm battling to get the progressbar to work though, the progressbar pops up but then immediately disappears.
I want to know:
Why is it not waiting for the tasks in the DoInBackground to complete before it disappears?
Any advice would be appreciated. I am a beginner so please excuse the silly question if it is indeed a silly question.
The tasks within DoInBackground are calls to a volley requests, which copy data from a remote sql database into the devices sqlite database.
Thanks.
public class AsyncTask extends android.os.AsyncTask<Integer, Integer, String> {
ProgressBar pb;
int status = 0;
public void setProgressBar(ProgressBar progressBar) {
this.pb = progressBar;
}
#Override
protected void onPreExecute() {
Log.d(TAG, "zzzzz2: " + "Pre");
pb.setVisibility(View.VISIBLE);
super.onPreExecute();
}
#Override
protected String doInBackground(Integer[] objects) {
Log.d(TAG, "zzzzz2: " + "DoIn");
// if user doesnt exist in db add to server db
String strUser = mFirebaseUser.getUid();
String strDisplayName = mFirebaseUser.getDisplayName();
String strEmail = mFirebaseUser.getEmail();
clsServerClass.addUserToServer(strUser, strDisplayName, strEmail, context);
// load 12 tables into sqlite database
clsServerClass.copyTblVersions(context);
clsServerClass.copyAnimalClassTable(context);
clsServerClass.copyAnimalGroupTable(context);
clsServerClass.copyAnimalTable(context);
clsServerClass.copyTblSeasons(context);
clsServerClass.copyRegions(context);
clsServerClass.copyCountries(context);
clsServerClass.copyProvinces(context);
clsServerClass.copyHotspots(context);
clsServerClass.copyHabitats(context);
clsServerClass.getMyPlaces(strUser, context);
clsServerClass.getSightingsUser(strUser, context);
Cursor cntry = getCsr("animal_unique_key", "tbl_lookup_animals");
Log.d(TAG, "yyyya: " + cntry.getCount());
JSONArray arrayList1 = createListArray("animal_class_key", 1);
createListSharedPref("List1_name", "List 1: All birds", "List1_where", arrayList1);
JSONArray arrayList2 = createListArray("animal_class_key", 2);
createListSharedPref("List2_name", "List 2: All Mammals", "List2_where", arrayList2);
JSONArray arrayList3 = createListArray("animal_class_key", -99);
createListSharedPref("List3_name", "List 3: All Animals", "List3_where", arrayList3);
JSONArray arrayList4 = createListArray("animal_class_key", 3);
createListSharedPref("List4_name", "List 4: All Reptiles", "List4_where", arrayList4);
JSONArray arrayList5 = createListArray("animal_class_key", 4);
createListSharedPref("List5_name", "List 5: All Amphibians", "List5_where", arrayList5);
return null;
}
#Override
protected void onProgressUpdate(Integer[] values) {
Log.d(TAG, "zzzzz3: " + "Update");
pb.setProgress(values[0]);
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String s) {
Log.d(TAG, "zzzzz2: " + "post");
pb.setVisibility(View.GONE);
super.onPostExecute(s);
}
}
Problem lies in onProgressUpdate method.
Docs
onProgressUpdate() : This method receives progress updates from
doInBackground method, which is published via publishProgress method,
and this method can use this progress update to update the UI thread
Since you are not passing any value to your onProgressUpdate, your progress bar disappears immediately.
In doInBackground method after Log.d(TAG, "zzzzz2: " + "DoIn");
Add
publishProgress(5); // Calls onProgressUpdate()
//5 is just an example integer
Now, it should work fine.
To learn more about how to better make use of onProgressUpdate(), consult https://www.tanelikorri.com/tutorial/android/asynctask-tutorial/

Android studio room database - not returning values in onRestart() method

My app is a list of element names. Clicking one goes to another activity with more details, and an editText and button to change its name. When I go back to the list, I want it to have the new name if updated. My onCreate method has this code which populates it from the database perfectly (ignore the hardcoded size, its just simpler for debugging)
final String DATABASE_NAME = "element_db";
final AppDatabase appDatabase;
appDatabase = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, DATABASE_NAME).build();
ListView list = (ListView)findViewById(R.id.listView);
final String[] element = new String[3];
new Thread(new Runnable() {
#Override
public void run() {
List<Element> elements;
elements = appDatabase.elementDao().fetchElements(); // a dao query "select*from"
int size = elements.size();
for (int i = 0; i < size; i++){
element[i] = elements.get(i).getName();
}
}
}) .start();
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, R.layout.activity_list_view, R.id.textView, element);
list.setAdapter(arrayAdapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent i = new Intent(MainActivity.this, itemdetail.class);
i.putExtra("pos", position);
startActivity(i);
}
});
To achieve an updated list when returning to this screen, I copied the above code into the onRestart method, but now the database does not return anything. If I just set the array that goes into the adapter to {"a", "a", "a"} the list populates fine. Any ideas why the database works onCreate but not onRestart?
I think you can use ViewModel and livedata to observe any database change

error: cannot find symbol variable MyOpenWeatherMapApiKey Android

I am new to Android.I need help to solve the error below.
Got stuck here.
public class ForecastFragment extends Fragment {
private ArrayAdapter<String> mForecastAdapter;
public ForecastFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add this line in order for this fragment to handle menu events.
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.forecastfragment, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_refresh) {
FetchWeatherTask weatherTask = new FetchWeatherTask();
weatherTask.execute("94043");
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Create some dummy data for the ListView. Here's a sample weekly forecast
String[] data = {
"Mon 6/23 - Sunny - 31/17",
"Tue 6/24 - Foggy - 21/8",
"Wed 6/25 - Cloudy - 22/17",
"Thurs 6/26 - Rainy - 18/11",
"Fri 6/27 - Foggy - 21/10",
"Sat 6/28 - TRAPPED IN WEATHERSTATION - 23/18",
"Sun 6/29 - Sunny - 20/7"
};
List<String> weekForecast = new ArrayList<String>(Arrays.asList(data));
// Now that we have some dummy forecast data, create an ArrayAdapter.
// The ArrayAdapter will take data from a source (like our dummy forecast) and
// use it to populate the ListView it's attached to.
mForecastAdapter =
new ArrayAdapter<String>(
getActivity(), // The current context (this activity)
R.layout.list_item_forecast, // The name of the layout ID.
R.id.list_item_forecast_textview, // The ID of the textview to populate.
weekForecast);
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
// Get a reference to the ListView, and attach this adapter to it.
ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast);
listView.setAdapter(mForecastAdapter);
return rootView;
}
public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {
private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();
/* The date/time conversion code is going to be moved outside the asynctask later,
* so for convenience we're breaking it out into its own method now.
*/
private String getReadableDateString(long time){
// Because the API returns a unix timestamp (measured in seconds),
// it must be converted to milliseconds in order to be converted to valid date.
SimpleDateFormat shortenedDateFormat = new SimpleDateFormat("EEE MMM dd");
return shortenedDateFormat.format(time);
}
/**
* Prepare the weather high/lows for presentation.
*/
private String formatHighLows(double high, double low) {
// For presentation, assume the user doesn't care about tenths of a degree.
long roundedHigh = Math.round(high);
long roundedLow = Math.round(low);
String highLowStr = roundedHigh + "/" + roundedLow;
return highLowStr;
}
/**
* Take the String representing the complete forecast in JSON Format and
* pull out the data we need to construct the Strings needed for the wireframes.
*
* Fortunately parsing is easy: constructor takes the JSON string and converts it
* into an Object hierarchy for us.
*/
private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
throws JSONException {
// These are the names of the JSON objects that need to be extracted.
final String OWM_LIST = "list";
final String OWM_WEATHER = "weather";
final String OWM_TEMPERATURE = "temp";
final String OWM_MAX = "max";
final String OWM_MIN = "min";
final String OWM_DESCRIPTION = "main";
JSONObject forecastJson = new JSONObject(forecastJsonStr);
JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);
// OWM returns daily forecasts based upon the local time of the city that is being
// asked for, which means that we need to know the GMT offset to translate this data
// properly.
// Since this data is also sent in-order and the first day is always the
// current day, we're going to take advantage of that to get a nice
// normalized UTC date for all of our weather.
Time dayTime = new Time();
dayTime.setToNow();
// we start at the day returned by local time. Otherwise this is a mess.
int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);
// now we work exclusively in UTC
dayTime = new Time();
String[] resultStrs = new String[numDays];
for(int i = 0; i < weatherArray.length(); i++) {
// For now, using the format "Day, description, hi/low"
String day;
String description;
String highAndLow;
// Get the JSON object representing the day
JSONObject dayForecast = weatherArray.getJSONObject(i);
// The date/time is returned as a long. We need to convert that
// into something human-readable, since most people won't read "1400356800" as
// "this saturday".
long dateTime;
// Cheating to convert this to UTC time, which is what we want anyhow
dateTime = dayTime.setJulianDay(julianStartDay+i);
day = getReadableDateString(dateTime);
// description is in a child array called "weather", which is 1 element long.
JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
description = weatherObject.getString(OWM_DESCRIPTION);
// Temperatures are in a child object called "temp". Try not to name variables
// "temp" when working with temperature. It confuses everybody.
JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
double high = temperatureObject.getDouble(OWM_MAX);
double low = temperatureObject.getDouble(OWM_MIN);
highAndLow = formatHighLows(high, low);
resultStrs[i] = day + " - " + description + " - " + highAndLow;
}
for (String s : resultStrs) {
Log.v(LOG_TAG, "Forecast entry: " + s);
}
return resultStrs;
}
#Override
protected String[] doInBackground(String... params) {
// If there's no zip code, there's nothing to look up. Verify size of params.
if (params.length == 0) {
return null;
}
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
String format = "json";
String units = "metric";
int numDays = 7;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
final String FORECAST_BASE_URL =
"http://api.openweathermap.org/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String FORMAT_PARAM = "mode";
final String UNITS_PARAM = "units";
final String DAYS_PARAM = "cnt";
final String APPID_PARAM = "02867cfd75153da1eda43a17f213ffc5";
Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, params[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
.appendQueryParameter(APPID_PARAM, BuildConfig.OPEN_WEATHER_MAP_API_KEY)
.build();
URL url = new URL(builtUri.toString());
Log.v(LOG_TAG, "Built URI " + builtUri.toString());
// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = buffer.toString();
Log.v(LOG_TAG, "Forecast string: " + forecastJsonStr);
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
try {
return getWeatherDataFromJson(forecastJsonStr, numDays);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
// This will only happen if there was an error getting or parsing the forecast.
return null;
}
}
}
}
}
[{
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.example.patels.sunshine";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
// Fields from build type: debug
public static final String OPEN_WEATHER_MAP_API_KEY = MyOpenWeatherMapApiKey;
}
I have written this code....I got stuck here..Unable to solve the error.
Help me out....Thank you
Under the app folder you can find build.gradle file, in this make this below changes.
Since you are using a String you have to use this syntax:
it.buildConfigField "String" , "OPEN_WEATHER_MAP_API_KEY" , "\"MyOpenWeatherMapApiKey\""
The last parameter has to be a String.
You should create an account here http://openweathermap.org/ and when you register with your email, you get an APIKey for your account. Use this api key and replace the MyOpenWeatherMapApiKey in the following line:
public static final String OPEN_WEATHER_MAP_API_KEY = MyOpenWeatherMapApiKey;
Another alternative would be to write the APIKey in grandle file as proposed already.

c# wanting multiple ui threads but getting cross-reference errors instead

i'm still very new at c#, threads and forms. i'm writing a small data acquistion program. it has two threads: the main ui thread and a sensor polling/logging/charting thread. when the user clicks the "start-logging" button, it it continuously polls the sensors (over a virtual COM port), writes the response to a file, updates the main form with some basic polling stats (how many pollings per second). if the user has clicked a "monitor" button, it opens a charting form and the polling thread invokes a methods that that adds the sensors values to the chart.
i have a version of this program that works very well but i found that if i have multiple charts open (so that i can view multiple sensors in realtime), the chart updates become sporadic or stop and only the window with the focus updates smoothly. (the comm port is only 56kbaud so it's not like the polling is being swamped with data.)
so i got the "bright" idea to make charting threads, thinking this would provide multiple UI loops and would produce nice smooth charting on multiple chart forms. below is simplified code; e.g. here, the charting thread is started with the polling thread instead of when the user clicks the "monitor" button. it compiles, but when it runs, i get a cross-reference error at the point when the update_chart method is called.
seems i have a fundamental misunderstanding of several things about threads and control ownership. the chart was made in the "charting" thread, but when the "polling" thread invokes the update_chart method, the code shows that update_chart methods is being run by the "main_ui" thread. i'm open to any suggestions/advise that'll give me smooth charting and stats updates. thanks.
namespace WindowsFormsApplication1
{
public partial class Main_Form : Form
{
delegate void UpdateUIStatsDelegate(string update);
UpdateUIStatsDelegate update_stats_delegate;
static BackgroundWorker polling_thread = new BackgroundWorker();
static BackgroundWorker charting_thread = new BackgroundWorker();
public static Chart_Form chart_form = new Chart_Form();
public Main_Form()
{
Thread.CurrentThread.Name = "main_ui";
update_stats_delegate = new UpdateUIStatsDelegate(update_stats);
polling_thread.DoWork += polling_thread_DoWork;
charting_thread.DoWork += charting_thread_start;
}
private void start_logging_Click(object sender, EventArgs e)
{
start_polling_thread();
start_charting_thread();
}
private void start_polling_thread()
{
polling_thread.RunWorkerAsync();
}
private void polling_thread_DoWork(object sender, DoWorkEventArgs e)
{
string sensor_values;
Thread.CurrentThread.Name = "polling";
while (true)
{
sensor_values = poll_the_sensors_and_collect_the_responses();
log_to_file(sensor_values);
// BeginInvoke(chart_form.update_chart_delegate, new object[] { sensor_values });
chart_form.BeginInvoke(chart_form.update_chart_delegate, new object[] { sensor_values });
pps = compute_polling_performance();
BeginInvoke(update_stats_delegate, new object[] { pps.ToString("00") });
}
}
private void update_stats(string stat)
{
string tn = Thread.CurrentThread.Name;
// this says "main_ui", but i don't get a cross-reference error
pollings_per_second.Text = stat;
}
private void start_charting_thread()
{
charting_thread.RunWorkerAsync();
}
private void charting_thread_start(object sender, DoWorkEventArgs e)
{
Thread.CurrentThread.Name = "charting";
Chart_Form chart_form = new Chart_Form();
chart_form.Show();
while (charting_is_active) { }
}
}
public partial class Chart_Form : Form
{
public delegate void UpdateChartDelegate(string sensor_values);
public UpdateChartDelegate update_chart_delegate;
public Chart_Form()
{
string tn = Thread.CurrentThread.Name;
update_chart_delegate = new UpdateChartDelegate(update_chart);
this.Text = "a realtime plot of sensor values";
}
private void update_chart(string sensor_values)
{
string tn = Thread.CurrentThread.Name;
// this says "main_ui" and i get a cross reference error; set below.
int x = extract_x_value(sensor_values);
int y = extract_y_value(sensor_values);
chart1.Series[X_AXIS].Points.AddY(x); // <<--- i get a cross-reference runtime error here...
chart1.Series[Y_AXIS].Points.AddY(y);
}
}
}

Resources