I have a Handler that is in my MainActivity. This Handler has to update the UI of one of my Fragments inside of the MainActivity's layout.
I then have a separate class that has a loop; when I create this class, let's called it myLooper it does some sort of calculation then send the information inside of the loop to the Handler in my MainActivity. Which in turn will then update that data onto a GraphView that I have implemented within my MainActivity's Fragment.
FLOW:
Step 1: Calculate data on MyLooper.
Step 2: Send data to MainActivity via my Handler.
Step 3: Have my Handler update MainActivity's Fragment's GraphView with the sent data.
Relevant code:
public class MainActivity extends ActionBarActivity implements
ActionBar.TabListener {
public MyLooper myDataLooper;
Fragment graphFrag = fragment_graphpage.newInstance(1);
public final Handler myHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
((fragment_graphpage) graphFrag).updateGraphUI(msg.getData().getFloat("myvoltage"));
}
};
SectionsPagerAdapter mSectionsPagerAdapter;
globalControlInstance globalControl;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
globalControl = globalControlInstance.getInstance();
myDataLooper = (IOIOBoard) getApplicationContext();
myDataLooper.create(getBaseContext(), this,_myIOIOHandler);
myDataLooper.start();
}
MyLooper class:
public class MyLooper extends Application implements IOIOLooperProvider {
globalControlInstance globalData = globalControlInstance.getInstance();
public AnalogInput AI1;
public Handler IOIOHandler;
private final IOIOAndroidApplicationHelper helper_ = new IOIOAndroidApplicationHelper(
this, this);
protected void create(Context myContext, Activity myActivity, Handler myHandler) {
IOIOHandler = myHandler;
helper_.create();
}
protected void destroy() {
helper_.destroy();
}
protected void start() {
helper_.start();
}
protected void stop() {
helper_.stop();
}
protected void restart() {
helper_.restart();
}
class Looper extends BaseIOIOLooper {
#Override
protected void setup() throws ConnectionLostException {
}
#Override
public void loop() throws ConnectionLostException, InterruptedException {
Message myVoltageMessage = new Message();
Bundle myVoltageBundle = new Bundle();
myVoltageBundle.putFloat("myvoltage", AI1.getVoltage());
myVoltageMessage.setData(myVoltageBundle);
IOIOHandler.sendMessage(myVoltageMessage);
}
}
#Override
public IOIOLooper createIOIOLooper(String connectionType, Object extra) {
return new Looper();
}
}
Finally the Fragment that contains my GraphView's updateGraphUI method.:
public void updateGraphUI(float newReading) {
final double newReadingDouble = newReading;
mTimer2 = new Runnable() {
#Override
public void run() {
graphLoopCounter++;
if (globalData.isLiveUpdatingEnabled()) {
alarmCheck(newReadingDouble);
globalData.setGraph2LastXValue(globalData
.getGraph2LastXValue() + 1d);
globalData.getGraphViewSeries().appendData(
new GraphViewData(globalData.getGraph2LastXValue(),
newValue), true, 1000);
if (globalData.getGraphPeak() < newReadingDouble) {
globalData.setGraphPeak(newReadingDouble);
graphPeak.setText("Graph Peak: "
+ Double.toString(newReadingDouble));
}
avgSum += globalData.getLatestGraphData();
graphAvg.setText("Graph Avg: " + Double.toString(avgSum/graphLoopCounter));
mHandler.postDelayed(this, 100);
}
}
};
mHandler.postDelayed(mTimer2, 100);
}
where mHandler is a handler in my Fragment's implementation. and both mTimer1 and mTimer2 are Runnables.
my problem is; no matter what I try to do data is not sent to my GraphView and it never updates...
In MainActivity you name your Handler instance "myHandler" but then you pass your MyLooper class "_myIOIOHandler".
Related
In my android app I'm trying to extend the Thread class to easy pass my values between the original thread and a another one. So I can easily update my UI.
To do this I extended the Thread class:
public class ThreadUpdateUI extends Thread {
AppCombatActivityExtended activity;
Map<?,?> values;
public ThreadUpdateUI(AppCombatActivityExtended activity, Map<?,?> values){
this.activity = activity;
this.values = values;
}
public void UpdateUI(Map<?,?> values){
this.activity.UIThreadFinished(values);
}
public Map<?,?> GetValues()
{
return this.values;
}
}
Not only did I extend Threads, but I also extended the class for Activity so I have a main function I can call in every activity to update my UI:
public class AppCombatActivityExtended extends AppCompatActivity {
protected void UIThreadFinished(Map<?,?> values){}
}
In my activity I use the ThreadUpdateUI class to run a thread in which I can pass all my own values to use in the other thread:
public class MainActivity extends AppCombatActivityExtended {
static final String carlooking_key = "text_carlooking";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//init views
final TextView text_carlooking = (TextView) findViewById(R.id.main_text_carlooking);
//init parameters for thread
HashMap<String, String> UIThreadParameters = new HashMap<>();
UIThreadParameters.put(carlooking_key, text_carlooking.getText().toString().replace(".", ""));
//ThreadUpdateUI
ThreadUpdateUI TU_UI = new ThreadUpdateUI(this, UIThreadParameters) {
#Override
public void run() {
try {
Integer counter = 0;
while (true) {
sleep(1000);
Map values = GetValues();
String text = values.get(carlooking_key).toString();
text += "_test";
Map result = new HashMap<String,String>();
result.put(carlooking_key, text);
UpdateUI(result);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
TU_UI.start();
}
#Override
protected void UIThreadFinished(Map<?, ?> values) {
super.UIThreadFinished(values);
final TextView text_carlooking = (TextView) findViewById(R.id.main_text_carlooking);
text_carlooking.setText(values.get(carlooking_key).toString());
}
}
My code crashes at:
UpdateUI(result);
Saying: "Only the original thread that created a view hierarchy can touch its views."
In my trace I can see the following:
at MainActivity.UIThreadFinished(MainActivity.java:56)
at ThreadUpdateUI.UpdateUI(ThreadUpdateUI.java:21)
at MainActivity$1.run(MainActivity.java:42)
Which could indicate that the reference changed in my ThreadUpdateUI causing to call ThreadUpdateUIFinished in a different thread than the original.
Is it possible to make this code return to the original thread to update my UI in a loop?
I have a newbie question about Class/Task/Activity. I'm coming from C so I don't know if it's a good approach to do what I need.
I've created a class:
public class UDPServer {
private MyDatagramReceiver myDatagramReceiver = null;
private static int MAX_UDP_DATAGRAM_LEN = 1024;
private static int UDP_SERVER_PORT = 5000;
public void start() {
myDatagramReceiver = new MyDatagramReceiver();
myDatagramReceiver.start();
}
public void kill() {
myDatagramReceiver.kill();
}
private class MyDatagramReceiver extends Thread {
private boolean bKeepRunning = true;
private String lastMessage = "";
public void run() {
String message;
byte[] lmessage = new byte[MAX_UDP_DATAGRAM_LEN];
DatagramPacket packet = new DatagramPacket(lmessage, lmessage.length);
DatagramSocket socket = null;
try
{
socket = new DatagramSocket(UDP_SERVER_PORT);
while(bKeepRunning)
{
socket.receive(packet);
message = new String(lmessage, 0, packet.getLength());
lastMessage = message;
//Here should call activity method
});
}
}
catch (Throwable e)
{
e.printStackTrace();
}
finally
{
if (socket != null)
{
socket.close();
}
}
}
public void kill() {
bKeepRunning = false;
}
}
}
Inside my Activity I've:
#Override
public void onResume() {
super.onResume();
mUDPServer = new UDPServer();
mUDPServer.start();
}
#Override
public void onPause() {
super.onPause();
mUDPServer.kill();
}
Now, every time I received a packet I want that this thread/class pass received packet to an Activity method that elaborate(do some calculation or update some UI ecc..) this incoming data. But I can't figure how to do this, maybe my approach is not correct. I can place thread code inside Activity but it seems to make code less readable.
Suggestion how to do this?
#Anshul Jain CODE UPDATE:
public class Main_activity extends Activity implements Interface_UDPServer{
TextView recived_message;
UDPServer mUDPServer;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
recived_message = (TextView)findViewById(R.id.recived_message);
}
#Override
public void onResume() {
super.onResume();
mUDPServer = new UDPServer(this);
mUDPServer.start();
}
#Override
public void onPause() {
super.onPause();
mUDPServer.kill();
}
public void sendData(final String str){
runOnUiThread(new Runnable() {
#Override
public void run() {
recived_message.setText(str);
}
});
}
}
XML file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_below="#+id/linearLayout"
android:layout_alignLeft="#+id/linearLayout"
android:layout_alignStart="#+id/linearLayout">
<TextView
android:id="#+id/recived_message"
android:layout_width="200dp"
android:layout_height="35dp"
android:textColor="#444444"
android:textSize="20dp" />
</LinearLayout>
</RelativeLayout>
You can use Callback for this purpose.
Define some interface like
public interface MyCustomInterface(){
public void sendData(String str);
}
Now let your Activity implement this interface.
public class MyActivity implements MyCustomInterface {
#Override
public void sendData(String str){
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
recived_message.setText(str);
}
});
}
}
Now in UDPServer.java, write the following code
public class UDPServer {
private MyCustomInterface interface;
UDPServer(MyCustomInterface interface){
this.interface = interface;
}
}
Now whenever you have some data available lets say a string, you can send it like this
interface.sendData(str);
You have an A activity and B one, when you finish actions on B activity side you need it to effect A side when you come back.
Create an Instance Class and a method that u type u need, let's say;
public interface SelectedBirthday {
void onSelectedData(String date);
}
Now we are on B side, Create an instance of your Interface Class
private SelectedBirthday mCallback;
Override
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (SelectedBirthday) activity;
} catch (ClassCastException e) {
Log.d("MyDialog", "Activity doesn't implement the ISelectedData interface");
}
}
Now upload the value you needed
String userBirth = (day + " " + month + " " + year);
mCallback.onSelectedData(userBirth);
Ok let's go to A side
Implement our Interface Class
implements SelectedBirthday
it will warn you for its method and you implemented it
#Override
public void onSelectedData(String date) {
if (!date.equals("")) {
txt_poup_age.setText(date);
//now you are free to do what you want with the value you received automaticaly
}
}
In android 4 option to do this
In android you can send data through Intent or Intent followed by Bundle.Like
Intent i = new Intent(current_class.this, linked_class.class);
i.putextra("Key", value);
And get the value(suppose string value) in another class like:
String value = getIntent.getExtra("String key which you used when send value");
option 2
class A{
public static String _utfValue = "";
void sendValue(){
_utfValue = "some value";
}
}
And fetch this value in your java class like:
String value = A._utfValue ;
You can use SharedPreference to save the value and get it from other class.
You can use a static method with some return value and fetch the method in your java class through class name.
I am sharing the code as suggested by #Shadman Akhtar and reply by #Singee which worked .
As soon as the button is clicked the Textview value is set with the value you want to send to MainActivity from retrivedata.java .I haved used Button to simulate the Asynchronous methods which can be inside retrivedata.java
MainActivity.java
package com.example.interfacetesting;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements MyCustomInterface {
TextView tv1;
Button btn1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1=(TextView)findViewById(R.id.tv1);
btn1=(Button)findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
retrivedata rd=new retrivedata(MainActivity.this);
rd.recievedataa();
}
});
}
#Override
public void sendData(String str){
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
tv1.setText(str);
}
});
}
}
MyCustomInterface.java //this is interface
package com.example.interfacetesting;
public interface MyCustomInterface{
public void sendData(String str);
}
retrivedata.java //class from which data will be sent to MainActivity.
package com.example.interfacetesting;
public class retrivedata{
private MyCustomInterface otherNameInterface;
retrivedata(MyCustomInterface otherNameInterface){
this.otherNameInterface = otherNameInterface;
}
void recievedataa()
{
otherNameInterface.sendData("---any string you want to send to mainactivity-------");
}
}
Maybe you could use a Handler, load it with some data, and then read those data from your activity. Check more infos here about handlers
You'd just pass an handler from your activity to your class, use handler.sendMessage("") inside your run method, and analyse what you receive inside your activity.
In your case I would use activity as interface. The interface is stored as a static parameter inside Application class.
there are many ways you can achieve this following are some
you can use interfaces as explained in one of the answers
you can create a IntentServce instead of your class and use Result Receiver to communicate the data.
you can use handlers and messages as well
you can also create a service and use IBinders (Bound Service)
you can Google out more about these methods and chose what suits you better
I have a problem with displaying sensors data on screen. I have class: SensorsData.class which have all needed data (all sensors results) and I want to display this data on screen in activity: SensorsActivity.class.
This is example of SensorsData.class (example of Light Sensor data):
public class SensorsData extends ContextWrapper implements EventListener, StepCounterListener, LinearAccListener, StepDetectorListener, LightSensorListener, PressureSensorListener, GravitySensorListener, RotationVectorListener, RelativeHumidityListener, ProximitySensorListener, TempSensorListener, AccelerometerSensorListener, GyroSensorListener, MagSensorListener {
private LightSensor mLightSensor;
public long accelx, accely, accelz, rotX, rotY, rotZ;
public long magnX, magnY, magnZ, gravityX, gravityY, gravityZ;
public long gyroX, gyroY, gyroZ, press, linaccelX, linaccelY, linaccelZ;
public String temp, hum, step_detector;
public int prox, light, step_counter;
SensorsActivity cos;
public SensorsData(Context base) {
super(base);
// TODO Auto-generated constructor stub
}
public void register(Context base) {
mLightSensor = new LightSensor(getBaseContext());
mLightSensor.setListener(SensorsData.this);
}
#Override
public void onLightSensorChanged(int lux) {
// TODO Auto-generated method stub
cos.ustawiamyTextLight(lux);
}
}
and SensorsActivity.class:
public class SensorsActivity extends Activity {
private TextView lightText, pressureText, signText, noiseText, humidityText, linearAccText, proximityText, tempText, accelText, gyroText, magText, rotationText, gravityText, stepDetectorText, stepCounterText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sensors);
lightText = (TextView)findViewById(R.id.rLight);
SensorsData sData = new SensorsData(getBaseContext());
sData.register(getBaseContext());
}
#Override
protected void onResume() {
super.onStart();
}
public void ustawiamyTextLight(int lighttt) {
lightText.setText("LIGHT level: " + lighttt + " lx");
}
#Override
protected void onPause() {
super.onStop();
}
}
Variable "lighttt" is changed all the time, and i don;t know how to display it on screen, because now it doesn't work. Screen is black.
So am trying to use runOnUiThread() to update my LogUI (found in my apps MainActivity) which is a TextView. The issue is am trying to update the TextView using runOnUiThread() from another class by getting the strings to be made on the View.
Here is details of my code to elaborate my issue:
private LoggingClass getLogs;
getLogs.AddtoLogUI(String.format("Established on port: %d", obj));
Then the LoggingClass code:
public class LoggingClass {
private MainActivity updateUI;
private String stringValue;
public void AddtoLogUI(final String format) {
this.stringValue = format;
updateUI.runOnUiThread(new Runnable(){
#Override
public void run() {
MainActivity.log_this(stringValue);
}
});
}
}
The method MainActivity.log_this() code is like this:
public static void log_this(final String msg){
if(editable.toString().split("\n").length >=50) {
editable.delete(0, editable.toString().indexOf("\n"));
}
Runnable runnable = new Runnable(){
#Override
public void run() {
editable.append(msg);
editable.append("\n");
}
};
LogView.post(runnable);
}
PS: LogView is a TextView.
The NullpointerException is thrown when am trying to get the Strings using the getLogs.AddtoLogUI() method.
Any suggestions?
Additional Info as regards the object:
`Object obj[] = new Object[1];
obj[0] = Integer.valueOf(Port);`
You declare private LoggingClass getLogs; in your Activity
getLogs=new LoggingClass (MainActivity.this) in your onCreate
then u can use getLogs.AddtoLogUI(String.format("Established on port: %d", obj));
createLoggingClass constructor
public class LoggingClass {
private MainActivity updateUI;
private String stringValue;
public LoggingClass (MainActivity updateUI){
this.updateUI=updateUI;
}
public void AddtoLogUI(final String format) {
this.stringValue = format;
updateUI.runOnUiThread(new Runnable(){
#Override
public void run() {
MainActivity.log_this(stringValue);
}
});
}
}
I solved the issue myself using a handler instead. Here is a sample code of what I did:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
// UI code goes here
}
});
I would like to know just out of curiosity if there are any convenient ways of pulling data out of an async task created inside a class, and then modifying the data in another class (Without extending classes)
I have a way to do it, but it involves making methods static along with the Async task itself
for example, here I'm just making a string "text" in the Async task
public class Main extends Activity{
//Context ctx;
static class MyAsyncTask extends AsyncTask<Void,String,String>{
static String result;
private static Context context;
public MyAsyncTask(Context m)
{
this.context = m;
}
#Override
protected String doInBackground(Void... noArgs) {
result = "text";
return result;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
public static String getStr()
{
return result;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText et = (EditText)findViewById(R.id.editText1);
Button btn = (Button)findViewById(R.id.button1);
MyAsyncTask task = new MyAsyncTask(this);
task.execute();
final Test t = new Test();
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
et.append(t.modifiedString());
}
});
}
}
and in a new class I make a simple String method to modify that data from the async task
public class Test{
public String modifiedString()
{
// Main main = null;
// MyAsyncTask task = new MyAsyncTask(main.ctx);
// task.execute();
String s = (String)Main.MyAsyncTask.getStr();
return "modified " + s + "\n";
}
}
I'm wondering, is there a way I can do this without having to make the async task static? Perhaps with sharing contexts or something?
by the way I'm not doing this to solve any particular problem, I'm only doing it out of curiosity
Just create a singleton
public class Main extends Activity{
public static Main instance;
public static String thestring;
public class MyAsyncTask extends AsyncTask<Void,String,String>{
static final String result = "text";
Context context;
public MyAsyncTask(Context m)
{
this.context = m;
}
#Override
protected String doInBackground(Void... noArgs) {
return result;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
public String getStr()
{
return result;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText et = (EditText)findViewById(R.id.editText1);
Button btn = (Button)findViewById(R.id.button1);
MyAsyncTask task = new MyAsyncTask(this);
task.execute();
thestring = task.getStr();
instance = this;
final Test t = new Test();
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
et.append(t.modifiedString());
}
});
}
public String pulledFromAsyncTask()
{
return thestring;
}
public static Main getInstance(){
return instance;
}
}
and then in the another class
public class Test{
public String modifiedString()
{
Main main = Main.getInstance();
//so with main.something.. you can call the methods you want
//a good solution is to make a singleton class only for MyAsyncTask setting the
//functions get/set so you can take the values from other classes
return "modified " + main.pulledFromAsyncTask() + "\n";
}
}
Reference to a Context in a static way is generally bad idea, it can cause memory leaks
Why don't you simply pass MyAsyncTask object to Test and then do whatever modifications you want, i.e. non-static fashion?
When it comes to testable code static/ singleton is a tough choice.
Depending upon your requirement on the state of data you can however start with an Observer pattern or producer-consumer pattern.
Check out Event bus library for probably an out of the box solution for this use case