I have the following code:
public class MainActivity extends Activity {
public String myString;
...
public void updateString()
{
new Thread() {
#Override
public void run() {
this.myString = "TEST";
}
}
}
}
The problem is that I need to update myString from the thread, but I can't access it. Any suggestions? Thank you!
You can do in this way make string global and update it.
public class MainActivity extends Activity {
public String myString;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
updateString();
}
public void updateString()
{
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
for(int i=0; i<10;i++){
myString=String.valueOf(i);
//log
Log.d("myString:",myString);
}
}
}).start();
}
In such cases create a custom class which would implement Runnable and pass myString as an argument to the constructor of the class, so when runnable object will be created, it would stored locally which can be accesed from run method whenever required.
You could use getters and setters, for example:
public class MainActivity extends Activity {
public String myString;
...
public void updateString()
{
new Thread() {
#Override
public void run() {
setMyString("TEST");
}
}
}
public void setMyString(String myString){
this.myString = myString;
}
}
Related
I am running a recursive handler which runs some code. I am posting the handler using a HandlerThread. I want to run the next recursive call only after the completion of the previous call.
Is it possible to do so? If not what are the alternatives.
HandlerThread ht = new HandlerThread();
ht.start();
Handler h = new Handler(ht.getLooper());
h.post(new Runnable() {
#override
public void run(){
//Some code
h.postDelay(this,1000);
}
});
Your code should work, but if you want a complete example how to run something recursively using HandlerThread, here it is:
public class Main2Activity extends AppCompatActivity {
private MyWorkerThread mWorkerThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mWorkerThread = new MyWorkerThread("myWorkerThread");
final Runnable task = new Runnable() {
#Override
public void run() {
Log.d("TAG", "Done.");
mWorkerThread.postTask(this);
}
};
mWorkerThread.start();
mWorkerThread.prepareHandler();
mWorkerThread.postTask(task);
}
#Override
protected void onDestroy() {
mWorkerThread.quit();
super.onDestroy();
}
}
class MyWorkerThread extends HandlerThread {
private Handler mWorkerHandler;
public MyWorkerThread(String name) {
super(name);
}
public void postTask(Runnable task){
mWorkerHandler.postDelayed(task, 1000); // set timeout which needed
}
public void prepareHandler(){
mWorkerHandler = new Handler(getLooper());
}
}
Don't forget to call handlerThread.quit() in onDestroy
I'm trying to create my own "BeaconManager" to develop different actions more easily.
So I've created a new class and I've implement "BeaconConsumer" and its functions :
public class MybeaconManager implements BeaconConsumer{
private BeaconManager beaconManager;
private final String TAG = "MybeaconManager";
private boolean mEnterArea = false;
private boolean mAlreadyArea = false;
public MybeaconManager(Context ctx){
beaconManager = BeaconManager.getInstanceForApplication(ctx);
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));
beaconManager.bind(this);
}
public void bindBeacon(BeaconConsumer consumer){
beaconManager.bind(consumer);
}
public void unBindBeacon(BeaconConsumer consumer){
beaconManager.unbind(consumer);
}
public boolean isEnterInArea() {
return mEnterArea;
}
public boolean isAlreadyInArea() {
return mAlreadyArea;
}
public void sendNotification(String Notif) {
}
#Override
public void onBeaconServiceConnect() {
beaconManager.addMonitorNotifier(new MonitorNotifier() {
#Override
public void didEnterRegion(Region region) {
mEnterArea = true;
}
#Override
public void didExitRegion(Region region) {
mEnterArea = false;
}
#Override
public void didDetermineStateForRegion(int i, Region region) {
}
});
}
Next to this, I have my MainActivity :
public class MainActivity extends Activity {
MybeaconManager mybeaconManager;
BeaconManager beaconManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mybeaconManager = new MybeaconManager(this);
if (mybeaconManager.isEnterInArea()){
Log.i("BeaconTest", "I'm detecting a Beacon");
}
}
#Override
protected void onDestroy() {
super.onDestroy();
mybeaconManager.unBindBeacon((BeaconConsumer) this);
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onStop() {
super.onStop();
}
}
So as you can see, I'm trying to use the functions didEnterRegion/didExitRegion more easily in a way that I only have to use on line in my MainActivity code.
The problem is, the bind/unbind(this) don't compile well and I think it's because I don't implement "BeaconConsumer" on the MainActivity because he can't get the consumer right.
It's telling me : "Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference" and return me on the bind thing.
So do you have any ideas on how I can deal with this in a way that I keep my beaconManager ?
Thank you in advance.
PS : Sorry if my English is not perfect
BeaconConsumer interface is designed to be implemented by an Activity or Service class. If you want to implement this interface in a POJO as shown in the question, you need to chain the method definitions shown below.
#Override
public Context getApplicationContext() {
return getActivity().getApplicationContext();
}
#Override
public void unbindService(ServiceConnection serviceConnection) {
getActivity().unbindService(serviceConnection);
}
#Override
public boolean bindService(Intent intent, ServiceConnection serviceConnection, int i) {
return getActivity().bindService(intent, serviceConnection, i);
}
I suspect your code already has empty implementations of these methods, otherwise your code would not compile. Make sure you have provided full implementations as shown above.
What I want to do is call a method which is placed in my MainActivity.java file from another subclass. But everytime i want to call this method, my app crashes.
I already tried to make SetGerateStat() static but that didn't change anything. Also, I can build the apk without any errors, the application only crashes when the SetGerateStat() is called from the Thread.
What am I doing wrong here?
My code is below (please note that this is only a snippet):
MainActivity.java:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private CheckedTextView gerätestat;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void setGeraeteStat(boolean x) {
if (x==true) {
gerätestat.setCheckMarkDrawable(android.R.drawable.presence_online);
} else {
gerätestat.setCheckMarkDrawable(android.R.drawable.presence_busy);
}
}
public void onClick(View v) {
if(v==button_refresh) {
Thread connection = new Thread(new Conn("refresh", MainActivity.this));
connection.start();
}
}
Conn.java:
public class Conn implements Runnable {
private MainActivity act;
private String actioncommand;
public Conn(String a) {
actioncommand = a;
act = null;
}
public Conn(String a, MainActivity m) {
actioncommand = a;
act = m;
}
public void run() {
switch(actioncommand) {
case "refresh": {
act.setGeraeteStat(true);
}
break;
}
}
Have you forgot to initialize gerätestat ? You have to initialize gerätestat after setcontentview. After that use runOnUIThread method as below
public void setGeraeteStat(final boolean x){
runOnUiThread (new Runnable() {
public void run() {
if (x==true) {
gerätestat.setCheckMarkDrawable(android.R.drawable.presence_online);
} else {
gerätestat.setCheckMarkDrawable(android.R.drawable.presence_busy);
}
}
});}
In my app ,there is an one button which get input from database.When I press it more than one in a short time it crashes.
How can i avoid this error with using asynctask?
show.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
showinf();
}
});
}
private String[] columns={"name","surname"};
private void showinf(){
SQLiteDatabase db=v1.getReadableDatabase();
Cursor c=db.query("infos",columns,null,null, null,null,null);
Random mn2=new Random();
int count=c.getCount();
String mn=String.valueOf(count);
int i1=mn2.nextInt(count+1);
c.move(i1);
t1.setText(c.getString(c.getColumnIndex("name")));
t2.setText(c.getString(c.getColumnIndex("surname")));
}
thanks...
You can create a boolean flag (let's say bDiscardButtonAction), and set it to true in onPreExecute() and set it to false in onPostExecute(), something like:
public class FooTask extends AsyncTask<Foo, Foo, Foo>
{
private static boolean bDiscardButtonAction = false;
private boolean isDiscareded = false;
#Override
public void onPreExecute()
{
if(bDiscardButtonAction)
{
isDiscareded = true;
return;
}
bDiscardButtonAction = true;
}
#Override
public Foo doInBackground(Foo... params)
{
if(isDiscareded) return;
// ...
}
#Override
public void onPostExecute(Void result)
{
if(!isDiscareded) bDiscardButtonAction = false;
}
#Override
public void onCancelled(Foo result)
{
if(!isDiscareded) bDiscardButtonAction = false;
}
}
disable the show button in onPreExecute() and enable it back onPostExecute().
public class getAsyncDataTask extends AsyncTask<Void, Void, Void>
{
#Override
public void onPreExecute()
{
show.setAlpha(0.5);
show.setEnable(false);
}
#Override
public void doInBackground(Void... params)
{
//retrieve the data from db;
}
#Override
public void onPostExecute()
{
show.setAlpha(1.0);
show.setEnable(true);
}
}
I hope this code will help u out.
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
new AsynchTaskManualLocation().execute();
});
public class AsynchTaskGetData extends AsyncTask<String,Void,String>
{
#Override
protected String doInBackground(String... url) {
//showinf(); this method contains operation of getting data from //database OR ur logic to getdata
return showinf();
}
#Override
protected void onPostExecute(String result) {
//here u get result in resul var and process the result here
}
}
}
In my DataTrak activity I defined the following method:
public void updateTotal(IAmount totalAmount, int transactionType) {
switch (transactionType) {
case AccountTotals.VALUE_CANCELS:
txtView_cancels_value.setText("" + (Long.parseLong(txtView_cancels_value.getText().toString()) + totalAmount.getValue()));
break;
case AccountTotals.VALUE_PAYS:
txtView_pays_value.setText("" + (Long.parseLong(txtView_pays_value.getText().toString()) + totalAmount.getValue()));
break;
case AccountTotals.VALUE_SALES:
txtView_sales_value.setText("" + (Long.parseLong(txtView_sales_value.getText().toString()) + totalAmount.getValue()));
break;
default:
break;
}
btn_total.setBackgroundResource(R.drawable.button_green );
}
The method computes and updates some TextViews and changes the color of a button. Then I need to call this method from a Java abstract class. The method call appears in a method that runs on a non-UI thread. Here's how I call the method:
new Thread()
{
public void run()
{
new DataTrak().runOnUiThread(new Runnable()
{
public void run()
{
new DataTrak().updateTotal(totalAmount,transactionType);
}
});
}
}.start();
The problem is that I get a run time exception. Here's the LogCat output:
05-13 16:52:13.325: E/AndroidRuntime(22101): FATAL EXCEPTION: Thread-1577
05-13 16:52:13.325: E/AndroidRuntime(22101): Process: com.ilts.lct, PID: 22101
05-13 16:52:13.325: E/AndroidRuntime(22101): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
05-13 16:52:13.325: E/AndroidRuntime(22101): at android.os.Handler.<init> (Handler.java:200)
05-13 16:52:13.325: E/AndroidRuntime(22101): at android.os.Handler.<init>(Handler.java:114)
05-13 16:52:13.325: E/AndroidRuntime(22101): at android.app.Activity.<init>(Activity.java:786)
05-13 16:52:13.325: E/AndroidRuntime(22101): at com.ilts.lct.ap.mainframe.DataTrak.<init>(DataTrak.java:37)
05-13 16:52:13.325: E/AndroidRuntime(22101): at com.ilts.lct.ap.customerfunctions.CustomerTransaction$2.run(CustomerTransaction.java:736)
In fact, initially I had just the line with the method call but I got the same run time exception. I searched for "Can't create handler inside thread that has not called Looper.prepare()" and I found several posts on this issue. One of them made me put the method call inside a new Thread, as shown above. But I still get the same run time exception. What should I change? Could you help me understand what's the problem actually and how to fix it? Thanks in advance.
After I read the answer by #Metero here's the code in the Java abstract class:
public abstract class CustomerTransaction extends Transaction {
...................................................
public interface CallBack {
public void updateTotal(IAmount a,int n);
}
private static CallBack callback;
public static void registerCallback(CallBack callback1){
callback = callback1;
}
/**
* Method to update the transaction state
*
* #param state The new transaction state
**/
public void setState(final int state) {
this.state = state;
/*
* Update the status
*/
if (state == TRANSACTION_COMPLETE) {
new Thread()
{
public void run() {
Looper.prepare();
new DataTrak().runOnUiThread(new Runnable()
{
public void run() {
Log.i("HERE", "HERE");
Looper.prepare();
callback.updateTotal(totalAmount,transactionType);
Looper.loop();
}
});
}
}.start();
}
}
....................
}
The very nature of this question suggests a MVC violation. Instead of your model calling methods in an Activity, it should call a method on some callback that the Activity has registered on the model. This callback should be queued in the UI thread.
You should never instantiate an Activity by yourself, if you do that, it won't be a normal activity, it will be just a problematic plan Java object.
So what you can maybe to to solve your problem is use the Observer pattern where you can define an interface with the 'callback' method and you let the Activity implement it and make it subscribe to the 'provider' of the notification. So basically, when this update Thread is running, you will run thru the list of subscribed listeners and dispatch the call, it will be just like a normal method call.
Just keep in mind to: 'subscribe' and 'unsubscribe' respecting the Activity lifecycles..like subscribe on onCreate() and unsubscribe on onDestroy().
Activity:
public class YourActivity extends Activity implements ControlListener {
public void onCreate(...) {
....
control.registerListener(this);
control.performOperation();
}
public void onDestroy(...) {
....
control.unregisterListener(this);
}
public void updateTotal(String newValue) {
runOnUiThread(new Runnable() {
public void run() {
textView.setText(newValue);
}
});
}
}
Control class:
public class Control {
private Set<ControlListener> listeners = new HashSet<ControlListener>();
public synchronized void registerListener(ControlListener listener) {
listeners.add(listener);
}
public synchronized void unRegisterListener(ControlListener listener) {
listeners.remove(listener);
}
public synchronized void notifyListeners(String newValue) {
for(ControlListener listener : listeners) {
listener.updateTotal(newValue);
}
}
public void performOperation() {
new Thread() {
public void run() {
String newValue= service.performBackgroundOperationToGetNewValue();
notifyListeners(newValue);
}
}.start();
}
}
Control listener:
public interface ControlListener {
public void updateTotal(String newValue);
}
Alternatively, you can use a very HANDY library to apply the Observer pattern on your project, it's the Otto: http://square.github.io/otto/ With the Otto, you wouldn't need to have the register/unregister/notifylisteners methods in your control, it would be placed somewhere else automatically.
This is not the best choice.
new Thread()
{
public void run()
{
new DataTrak().runOnUiThread(new Runnable()
{
public void run()
{
Looper.prepare();//This is not the best choice.
new DataTrak().updateTotal(totalAmount,transactionType);
}
});
}
}.start();
I recommend use AsyncTask, like this.
class SampleTask extends AsyncTask<Boolean, Boolean, Boolean> {
private int totalAmount;
private yourActivity activity;
//passing parameters
public void SampleTask(yourActivity activity){
this.activity = activity;
}
#Override
protected Boolean doInBackground(Boolean... params) {
while (totalAmount < 10){
totalAmount++;
}
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
// this is not the best choice
// because you are creating two instances.
new DataTrak().updateTotal(totalAmount,transactionType);
//If you pass a parameter, this for me is the best option.
activity.updateTotal(totalAmount,transactionType);
}
}
I agree #Alécio, please use a callback to do this. Add a callback interface in the non-activity class:
class yourclass{
public interface callBack{
public void updateTotal(...);
}
private callBack callback;
public void registerCallback(callBack callback){
this.callback = callback;
}
//somewhere call the updateTotal(...)
callback.updateTotal(...);
}
In the Activity
//the activity implement the callback and then register it, and call the callback when neccesary
class yourActivity extends Activity implement callBack{
#Override
onCreate(...){
...
yourclass.registerCallback(this);
}
#Override
public void updateTotal(...){
.......
}
}
The sample code for multiple class comunicating.
public class Controller {
callBack callBack;
public void registerCallBack(callBack back){
this.callBack = back;
}
public void show(){
callBack.update(1, "my name");
}
public interface callBack{
public void update(int type, String message);
}
public callBack getCallBack(){
return callBack;
}
}
public class AnotherClass {
Controller controller = new Controller();
public void registerCallBack(callBack back){
controller.registerCallBack(back);
}
public void show(){
controller.getCallBack().update(1, "show me!");
}
}
public class MyActivity extends Activity implements callBack {
AnotherClass myclass = new AnotherClass();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("TAG", "This is message!");
setContentView(R.layout.main);
myclass.registerCallBack(this);
}
#Override
protected void onResume() {
super.onResume();
myclass.show();
}
#Override
public void update(int type, String message) {
((TextView) findViewById(R.id.display)).setText(message);
}
}