I am new to android programming and 've not thoroughly studied java before . I am really confused on how to use synchronized to ensure thread safety on static variables :
I usually create a class named Utils which has some static functions which are most of the time needed by all my other classes. Is this the correct way of keeping repetitive code out of my classes.
I always suffer from a problem with using Databases. When I create sqliteHelper class for certain Database and try to manage that database from say an Activity and a Background service , I usually get
into trouble. If I use local objects of helper class , I am maximum prone to getting into deadlocking of database when both the helper objects try to acquire write lock together.
For getting out of this trouble , I create a static instance of the helper class in my utils class. Now for performing any operation on database my activity and my service do the following thing :
public class Utils{
public static MDatabaseHelper mHelper;
public static void instantiateHelper(Context context){
if(mHelper==null)
mHelper=new MDatabaseHelper(context);
}
}
public class mActivity extends Activity{
public void insert some item in database(final Item item) // this method is called in the Activity at some time
(new Thread(){
#Override public void run(){
Utils.instantiateHelper(getBaseContext());
mHelper.insertItem(item); }
}).start();
}
public class mService extends Service{
public void insert some item in database(final Item item) // this method is called in the service at some time
(new Thread(){
#Override public void run{
Utils.instantiateHelper(getBaseContext());
mHelper.insertItem(item); }
}).start();
}
Now what if both the service and the activity try to insert the item together. I oftentimes get into this situation and an error occurs .
To avoid this I use this workaround :
I put the insert operation in a try block and on failure I wait for random time and try again
public void insertSomeItemInDatabase(final Item item)
(new Thread(){
#Override public void run(){
int i=0;
Random rand=new Random();
while(true){
if(i>10)
return;
try{
Utils.instantiateHelper(getBaseContext());
mHelper.insertItem(item);
break;
}catch(Exception e){
i++;
try{
Thread.sleep(rand.nextInt(1000));
}catch(Exception e){}
}
}
}
}
}).start();
}
I know this is the Worst method of synchronizing but since I am so new to java can any one please explain how to use synchronized in this Scenario .
Thank You
I think all your need is to create Application Class
[1] All those variables you have taken in Util, which are used in about all other class, can be taken in this Application class. So these variables will be available to all other classes.
[2] Create Singelton instance of Appliction class. Just Google about it.
[3] Also create Singleton of DataBaseHelper(if possible and can apply), so, single instance helps you every where.
Application Class is Global class in android, so you can use it to store and access all Global-Data. e.g. :
public class AppData extends Application {
public static AppData appData;
public int currentUserId; // etc.
//Const.
public AppData() {
appData = this;
}
#Override
public void onCreate() {
super.onCreate();
loginPreferences = getSharedPreferences(
SPF_NAME, 0);
pathToSDCard = Environment.getExternalStorageDirectory().getAbsolutePath();
System.out.println("Path : " + pathToSDCard);
//etc.
}
// MOST IMP FOR GETTIN SINGELTON INSTANCE <<<---<<<---<<<---
public static AppData getAppData() {
return appData;
}
}
HOW TO USE IT, SEE THIS
class ABC extends Activity {
AppData appData;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.xyz);
appData = AppData.getAppData();
...........
...........
appData.VARIABLE_NAME...
}
}
One thing more. In AndroidMenifest.xml
...
...
<application // In Application Tag
android:name="PACKAGE_NAME.AppData" // << Add here class name in which you have extended Application
android:icon="#drawable/ic_launcher"
...
...
Related
I'm trying to call a method in another class, however, I'm getting an error. I initialize the class to a variable, but I do not get the option to call that method. not even the variable shows up in the auto-complete when I start typing.
this is the class I'm calling:
public class aMessageBuffer {
private Collection<Message> messageBuffer = new ArrayList<Message>();
private Collection<Integer> responseBuffer = new ArrayList<Integer>();
private boolean messageBufferFull = false;
private boolean responseBufferFull = false;
//Called by aProducerTask
public void sendMsg(String op, int val){
//place message in messageBuffer
Message msg = new Message();
msg.setValues(op,val);
messageBuffer.add(msg);
messageBufferFull = true;
//todo: notify
while (responseBufferFull == false){
//wait...
}
//remove response from responseBuffer
responseBuffer.clear();
responseBufferFull = false;
//todo: Out Response
}
}
and this is where I'm calling it from:
public class aProducerTask extends Thread {
//TODO: Send Messages
private aMessageBuffer msgbuf = new aMessageBuffer();
msgbuf.sendMsg("add",3);
//TODO: Print Results
}
I'm getting the error in the msgbuf.sendMsg("add",3);
it is not allowing me to call the method with that variable
This is my Main:
public class Main{
public static void main(String args[]){
new aConsumerTask().start();
new aProducerTask().start();
}
public void run() {
}
}
You should define run method in your class aProducerTask.
public class aProducerTask extends Thread {
//TODO: Send Messages
private aMessageBuffer msgbuf = new aMessageBuffer();
public void run() {
msgbuf.send("add",3);
}
//TODO: Print Results
}
Don't call non-assignment methods naked in the class and outside of any method, constructor or similar block.
Here you'll want to call the non-assignment method in the run method.
Don't extend Thread, implement Runnable and give it a run method which will hold your method call. Then create a new Thread when needed, pass in the Runnable and call start() on the Thread.
You will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.
In the future if you have similar questions about a compilation error, post the full error message with your question, and please proof-read your code for correctness. 90% of our comments to questions are about clarification and correction.
So not:
public class aProducerTask extends Thread {
//TODO: Send Messages
private aMessageBuffer msgbuf = new aMessageBuffer();
msgbuf.sendMsg("add",3);
//TODO: Print Results
}
but rather this:
// improve class name and have it implement Runnable
public class AProducerTask implements Runnable {
private aMessageBuffer msgbuf = new aMessageBuffer();
#Override // don't forget this!
public void run() {
msgbuf.sendMsg("add",3);
}
}
Then to use:
public new Thread(new AProducerTask()).start();
I have a custom adapter that it's associated with a ListView in my MainActivity class and when I press on one of the items of the List (setOnItemClickListener method) I execute an AsyncTask to retrieve the info from the database and send it into a bundle.
Therefore, I have to wait until the AsyncTask finishes to send the info retrieved in the bundle.
For this purpose, I created an interface:
public interface OnCarListener {
void onCarCompleted(String c);
void onCarError(String error);
}
And I have my AsyncTask in another class:
class findCar extends AsyncTask<Integer, Integer, String> {
private final OnCarListener mListener;
public findCar(OnCarListener listener)
{
mListener = listener;
}
protected void onPreExecute() {
}
protected String doInBackground(Integer... idCar) {
String nameCar = "";
//Here the code to retrive the info
nameCar = obj.getString("name");
//Now nameCar = "Car1"
} catch (Exception ex) {
}
return nameCar;
}
protected void onProgressUpdate() {
}
protected void onPostExecute(String c) {
if (mListener != null) {
mListener.onCarCompleted(c);
}
}
}
And I execute my AsyncTask (in my MainActivity) as follows:
new findCar(new OnCarListener()
{
#Override
public void onCarCompleted(String c) {
synchronized (c)
{
name = c;
}
}
#Override
public void onCarError(String error) {
}
}).execute(idCar);
And after executing the AsyncTask I throw the bundle:
bundle.putString("name", name);
Note: I send more info with the bundle but I omitted it to simplify the question.
It should work in my opinion but in the first click in one element of the List the name isn't being passed by the bundle, just in the second and the rest of the clicks I made at the same or in the rest elements of the List, it works.
Expected result: AsyncTask will be executed and until it finishes the rest of the code shouldn't work. It is clear that it's not what it's doing right now.
What I want to know: Why the synchronized doesn't work in the first iteration? I mean, when I have the List and I click on one of the elements of the List the information of the element it's show (in another Activity) but the value name it's not shown.
If I go back and I do one or more clicks on the same element (or a different one) from the List, in all of them appears the value name correctly.
Why in the first iteration it doesn't work?
And I have another question: Why if I quit the synchronized as adelphus said in his answer, any of the times that I click on the elements of the List the value name appears?
I tried the solution in this question: synchronized not synchronizing but still doesn't work.
What could I do? (Without changing the logic of the program)
Thanks in advance!
I'm not sure you understand what synchronized does - it creates an exclusive lock on a given object to create ordered access to a section of code. When multiple threads attempt to enter a synchronized block (with the same lock object), only one thread will be allowed to continue into the block at a time.
In your code, you're synchronizing on the String parameter c. Since no other threads will be accessing this parameter, synchronized has no effect here.
Since your interface callback is being called on the UI thread (via onPostExecute()), you can just set the bundle value in the callback:
void amethod() {
final Bundle bundle = new Bundle();
new findCar(new OnCarListener()
{
#Override
public void onCarCompleted(String c) {
bundle.putString("name", c);
}
#Override
public void onCarError(String error) {
}
}).execute(idCar);
}
I have 2 Classes: a Main Class handling the UI and a second Class for retrieving Data from SQL Server by using PHP.
From the first class a mehtod in the second class is called with passing and retrieving variables.
Actually it is working fine without AsyncTask.
But since I want to use the code on devices running Android 3.0 and above, I need to change the method to be an AsyncTask. Else I get this error: "android.os.networkonmainthreadexception"
the actual working code Looks like this:
Main class:
...
String inputString="1";
String outputString;
outputString = Class2.SomeMethodInClass2(inputString);
....
Class2:
public class Class2 {
public static String SomeMethodInClass2(String input) {
String Output;
...
//Do some php-sql stuff based on "input"-variable
//and return the "output"-variable
...
return output;
}
}
This code works perfectly on Android 2.0 but I need to change it to AsyncTask, because Andoid 3.0 and above is giving me: "android.os.networkonmainthreadexception"
I have read a lot of threads about AsyncTask, but I can not get it to work with Input and Output in my code.
Eclipse allways tells me there is something wrong with my code.
How do I have to change my code, to be a working async Task? (please explain using my above code sample)
--edit: if there is an easier way to get rid of "android.os.networkonmainthreadexception" on 3.0 an above than AsyncTask, this would be fine too! --
Have a Callback in SecondClass
Extend your SecondClass with Asynctask
Implement preExecute,doinbackground, postExecute methods
Do your stuff in doinbackground
return result in doinbackground
In postExecute pass result to the Callback
Implement SecondClass.Callback in FirstClass
start SecondClass (execute) and pass a Callback reference from FirstClass
In Callback just handle your next operations with the result
EDIT :
public class SecondClass extends AsyncTask<String, Void, String> {
public interface Callback {
public void update(String result);
}
Callback mCallback;
public SecondClass(Callback callback) {
super();
mCallback = callback;
}
#Override
protected String doInBackground(String... params) {
String result = null;
//do your stuff and save result
return result;
}
#Override
protected void onPostExecute(String result) {
if(mCallback != null)
mCallback.update(result)
super.onPostExecute(e);
}
}
public class FirstClass implements SecondClass.Callback{
#Override
public void update(String result){
//do your stuff with result
}
return_type someMethod(){
SecondClass sc = new SecondClass(this) ;
sc.execute(someurl);
}
}
thanks for your Posts!
But i found an alternative way that seems much easier and better to me than doing async Task.
i added to my main class:
public class MainClass extends Activity implements OnTouchListener {
...
BackgroundOperations1 ourBackgroundOperations; //<===new
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
ourBackgroundOperations = new BackgroundOperations1(); //<===new
...
}
#Override
protected void onPause() {
....
ourBackgroundOperations.pause(); // <===new
}
#Override
protected void onResume() {
....
ourBackgroundOperations.resume(); // <===new
}
//whole new class inside of "MainClass"
//runs a different thread, i believe...?
public class BackgroundOperations1 implements Runnable {
Thread ourThread = null;
boolean isRunning = false;
public void pause() {
isRunning = false;
while (true) {
try {
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
public void resume() {
isRunning = true;
ourThread = new Thread(this);
ourThread.start();
}
#Override
public void run() {
while (isRunning) {
if (dothis==true){
//here i call my mehtod from class2, whenever "dothis" is set to true (somewhere in my onTouch or where ever i want)
String inputString="1";
String outputString;
outputString = Class2.SomeMethodInClass2(inputString);
}
}
}
}
}
this works on Android 4.0 and i think it is the best way to do what i want. and to me it seems a lot clearer then AsyncTask, because i can call my methods an pass varaibles in a simple way.
or is there a reason to not do it like this?
I really cannot think anymore, somehow I am almost at the end but now I hope, this will not be a dead-end-street.
I want to pass data from a inherited thread object back to my parent object.
And also return to main thread all in one.
Here is my Parent-Object
public class ControllerBase implements IController , IHandleRequestOnChange, IHandlesCustomTimer{
private QueueWorkerThread _QueueWorker;
// some other vars and methods
// ctor and so on .....
// initializer
public void init(){
// some other code
_QueueWorker = new QueueWorker();
_QueueWorker.SetEventListener(this); // i want to announce this object from _QueueWorker
_QueueWorker.start() // starts the thread
// other initializations
}
#Override
public void OnQueueWorkerReady(DataToPass){
// from IHandleRequestOnChange
// ALL INSIDE THIS CODE SHALL BE PROCESSED IN UI THREAD. BUT HOW ?
DataReceived dataRec = new DataReceived();
dataRec = this.Request(DataToPAss);
this.ApplyDataToUIControls(dataRec);
}
}
Here is my QueueWorkerThread :
public class QueueWorkerThread extends Thread implements IRequestQueueProcessed{
// ctor
public QueueWorkingThread(){
super();
}
// other variables and methods
IHandlesRequestOnChange _Listener;
public void Enque(DataToPass Data){
this.add(Data);
}
public void SetEventListener( IHandlesRequestOnChange pEventListener) {
this._Listener = pEventListener;
#Override
public void run(){
// here a LinkedBlockingQueue is polled
// AND UNDER SOME CONDITIONS I WANT TO PASS THE POLLED DATA BACK TO
// THE PARENT OBJECT AND RETURN TO MAIN THREAD. HOW CAN I ACHIEVE THIS?
if(AcertainConditionIsMet == true){
// I want to return to UI thread
this.OnQueueWorkerReady(the_polled_data)
}
// and this thread shall proceed and do some other stuff......
}
#Override
public void OnQueueWorkerReady(TableToPass Data){
// of interface IRequestQueueProcessed
//
// calling parents callback via interface-casting
((IHandleRequestOnChange)_Listener).OnQueueWorkerReady(null, Data);
// this passes execution AND DATA to my parent object BUT I do not return to main thread
}
}
I think you must share your handler in the application object to be able to pass data back in handler's message. You could have for instance:
public class MyApplication extends Application {
private Handler handler;
public Handler getHandler(){ return handler;}
public void setHandler(Handler handler){ this.handler = handler;}
private static MyApplication instance;
public static MyApplication getMyApplication(){return instance;}
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
}
Notice the static method to be able to retrieve the application object without a context (like in your thread).
I suppose if you want to update your UI you should be inside some activity context, so in your activity, you declare the handler:
private Handler handler;
inside onCreate(), you can instantiate and store the handler in the app object:
handler = new Handler(){
public void handleMessage(android.os.Message msg) {
//In here you can do your UI update using the references to the views
}
};
((MyApplication)getApplication()).setHandler(handler);
EDIT:
You can now get an instance of your app object from your thread using the public static method..
Hope it helps.
So I'm having problems with my threads in an Android project. I have a ThreadStarter class, with a BuildScreen() function, which actually creates the layout for each activity. The only problem is, sometimes the threads just won't start, and I have no idea why. They work like 98% of the time though, but when they don't, the current activity will never get initalized, and the user has to restart the app, which is inconvenient.
Here is a snippet of my code:
public class ThreadStarter
{
public static void BuildScreen()
{
try
{
GlobalVariables.screenDrawer.onStart();
GlobalVariables.listInitaliser.onStart();
Logger.log("ThreadStarter.BuildScreen", "Threads started");
}
catch(IllegalThreadStateException e)
{
GlobalVariables.screenDrawer.StopThread();
GlobalVariables.listInitaliser.StopThread();
Logger.log("ThreadStarter.BuildScreen", "Threads stopped");
GlobalVariables.screenDrawer.onStart();
GlobalVariables.listInitaliser.onStart();
}
catch(Exception e)
{
Logger.Error("Couldn't stop or start the threads!");
Logger.Error("Exception () Message: " + e.getMessage());
}
}
}
The threads:
public class ListInitialiser extends Thread
{
private static ListInitialiser _thread;
public synchronized void run()
{
GlobalVariables.CurrentActivity.UpdateLists();
}
public void onStart()
{
_thread = new ListInitialiser();
_thread.start();
}
public void StopThread()
{
if (_thread != null)
{
_thread.interrupt();
_thread = null;
}
}
}
I won't insert the ScreenDrawer thread here, because it's pretty much the same, except it calls another function.
And this is how every activity is created (of course the contentView differs in each file):
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getWindow().getAttributes().windowAnimations = R.style.Fade;
setContentView(R.layout.activity_fine_data_3);
GlobalVariables.CurrentActivity = this;
ThreadStarter.BuildScreen();
Logger.log("INFORMATION", "Person3DataActivity (Information 3/5)");
}
In the GlobalVariables section I have these variables:
public static ScreenDrawer screenDrawer = new ScreenDrawer();
public static ListInitialiser listInitaliser = new ListInitialiser();
If anyone has a solution or and idea, please share it with me.
Thanks in advance.
EDIT: Okay, so I took onof's (rather harsh but useful :)) advice, and refactored my code to use AsyncTask instead. It seems to be working pretty fine. I managed to implement it into my AbstractActivity class, which is the parent of every Activity I use, and now all I have to do is call BuildScreen() method in every onCreate method.
Thanks for the replies everyone.
try to add this to your class where u declared Global Variables
private static ListInitialiser instance;
public static synchronized ListInitialiser getInstance() {
if (instance == null)
instance = new ListInitialiser();
return instance;
}
Everytime you donot have to create new when u r taking static.I dont know but may be this can help
You can't rely on static variables as everything that is static (non final) in Android can be cleared any time the system need memory. So don't think static = storage.
You should instead instantiate the objects when you need them, like following:
public static ScreenDrawer getScreenDrawer() {
return new ScreenDrawer();
}
public static ListInitialiser getListInitialiser () {
return new ListInitialiser ();
}