NullPointerException using runOnUiThread() - java

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
}
});

Related

How to pass values from a Class to Activity - Android

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

Android System.Err for setVisibility(View.GONE)?

I've noticed a bug in a basic survey app I'm making to better learn android.
Occasionally I get a W/System.errīš• at MainActivity.surveyAvailable(MainActivity.java:40) that points to this line of code:
button.setVisibility(View.GONE);
I've used setVisibility many times before and never had any issues.
Here's the function, this gets called when the user first enters the app, and after they finish taking a survey to check the server and see if there is another survey available for the user:
public void surveyAvailable(boolean surveyIsAvailable) {
Log.d("MainActivity", "App survey is available? " + surveyIsAvailable );
Button button = (Button)findViewById(R.id.takeSurveyButton);
if (surveyIsAvailable) {
button.setVisibility(View.VISIBLE);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
App.getInstance().showSurvey();
}
});
} else {
Log.d("MainActivity", "We hit here");
button.setVisibility(View.GONE);
}
}
When a survey isn't available, the appropriate lines are logged - App survey is available? false and 'We hit here'. But then the button sometimes doesn't get set to View.GONE and I see the System.Err line. But sometimes it works fine and the button's visibility does change. Any idea how to fix that? Or how to get more information on what the System.Err actually means?
EDIT:
I found that by setting Button surveyButton; in my activity and then referencing the button as this.surveyButton seems to get the functionality to work more along the lines of what we'd expect (e.g. when we call button.setVisibility(View.GONE) the view is actually consistently GONE). But it still throws the System.Err line which has me hesitant that things are working correctly.
Edited Activity:
public class MainActivity extends ActionBarActivity implements SurveyListener {
Button surveyButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.surveyButton = (Button)findViewById(R.id.takeSurveyButton);
}
public void surveyAvailable(boolean surveyIsAvailable) {
Log.d("MainActivity", "App survey is available? " + surveyIsAvailable );
if (surveyIsAvailable) {
this.surveyButton.setVisibility(View.VISIBLE);
this.surveyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
App.getInstance().showSurvey();
}
});
} else {
Log.d("MainActivity", "We hit here");
this.surveyButton.setVisibility(View.GONE);
}
}
}
The activity implements this class:
public abstract interface SurveyListener
{
public abstract void surveyAvailable(boolean surveyAvailable);
}
Main App class that checks for surveys and calls 'surveyAvailable()`:
public class App
{
private static App _instance;
private SurveyListener _eventsHandler;
private String _apiKey = "";
private String _appuserId = "";
private String _surveyUrl = "";
private Activity _parentContext;
private Boolean _surveyAvailable;
public static App initWithApiKeyAndListener(String apiKey, SurveyListener surveyEventsHandler) {
if (_instance == null)
{
_instance = new App();
_instance._parentContext = (Activity) surveyEventsHandler;
_instance.setSurveyListener(surveyEventsHandler);
_instance.setApiKey(apiKey);
String appuserId = PreferenceManager.getDefaultSharedPreferences((Activity) _instance._eventsHandler).getString(tag, "no_appuser");
if (appuserId == "no_appuser") {
_instance._surveyAvailable = true;
_instance.alertAvailability(true);
} else {
_instance.checkForCampaigns();
}
}
return _instance;
}
private void alertAvailability(boolean surveyAvailable) {
App.getInstance()._eventsHandler.surveyAvailable(surveyAvailable);
}
private void checkForCampaigns() {
new CampaignCheck().execute();
}
public static App getInstance()
{
if (_instance == null)
{
_instance = new App();
}
return _instance;
}
public void donePushed()
{
App.getInstance().checkForCampaigns();
}
private class CampaignCheck extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
Boolean surveysAvailable = false;
try {
surveysAvailable = new AppuserConnection().checkCampaigns();
App.getInstance()._surveyAvailable = surveysAvailable;
App.getInstance().alertAvailability(_surveyAvailable);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
}
}
}
You shouldn't modify the UI elements from a different thread. You are doing this by calling App.getInstance().alertAvailability(_surveyAvailable); on a background thread. Move this to the AsyncTask's onPostExecute.

Passing data to a handler, from another class

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".

Modifying data from an Async task in an entirely different class

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

Avoiding threads restarting when changing activity

Right now, when I change the activity, my thread seams to go to sleep or something. And when I come back to the main activity, there are two threads running, doing the same things. I'm not sure if this is the case, but it seems like it's something equal.
...
public class MainActivity extends Activity {
public static double cowCount = 195;
public static double income = 0.100;
static boolean twiceCow = false, Threadrunning = false;
...
public void inc() {
new Thread(new income()).start();
}
class income implements Runnable {
#Override
public void run() {
for (int i = 0; i < 20;) {
final int value = i;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
cowCount = cowCount + income;
refresh();
}
});
}
}
}
This is how my thread looks like.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
checkThread();
}
private void checkThread() {
if (Threadrunning == false)
inc();
Threadrunning = true;
}
public void inc() {
new Thread(new income()).start();
}
...
public void refresh () {
TextView myTextView = (TextView)findViewById(R.id.myText);
myTextView.setText("You Have " + String.valueOf((nf.format(cowCount)) + " Cows!"));
}
I don't really understand what I've done wrong.
Please review this post: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
Consider your activity re-start as the same thing as a config change.
This pattern, i.e. using a retained Fragment as a container for your thread, and proxying UI updates via callbacks to your activity, is a pattern that will work much better for you.
In your case you'd need only a single TaskCallback for your UI refresh(), e.g. onRefreshCowCount(int cows);

Categories