Im currently trying to develop a little game where i want to use a class that extends SurfaceView and have it to draw in i thread (similar to LunarLander). However when i would like to change contentview to the one from xml, the one im not drawing in i was trying to call a method from my surfaceview class that is in activity class that will change contentview by setContentView, i get an RuntimeException:
"Can't create handler inside thread that has not called Looper.prepare()"
It's probably just because im somehow new to android and java development but i don't understand why it will work when the method is a static method but not otherwise?
(method in my Start class that extends activity)
public void simulationDone()
{
.....
}
(trying to access it)
new Start().simulationDone();
A couple of problems:
First, you shouldn't call setContentView multiple times.
Second, your surface view will need a reference to your activity. I tend to define listeners on my views that need to communicate back with an activity. In a custom SurfaceView called MySurfaceView:
public static interface Listener {
public void simulationDone();
}
private Listener listener;
public void setListener(Listener listener) {
this.listener = listener;
}
Then have your activity implement MySurfaceView.Listener and call mySurfaceView.setListener(this) when you create your surface view.
Related
I seem to be stuck with a problem with an object communicating with my activity class. The object is a view object with an onClick method that when called I would like it to notify my activity class so that it can perform said action. Below is some example code of my situation (assume all conventional setup operations have already been made):
public class MainActivity extends AppCompatActivity{
//...other global methods and objects
//Does not have access to instantiated Entry object(s)
public void entryObjectWasClicked(){
//perform said action
}
}
public class Entry extends View implements View.OnClickListener{
//...other global methods and objects
//Does not have access to the MainActivity object
#Override
public void onClick(View v){
//send a message to the MainActivity to
//somehow call the entryObjectWasClicked() method
}
}
The only way (off the top of my head) that I could think about dealing with this problem is by creating a static method in MainActivity and then calling it from an anonymous MainActivity object in the onClick method of Entry. The problem with the static method approach is that any subsequent method/object/primitive usages in the static method force those methods/objects/primitives to be static. This defeats the purpose of then being able to have two different instances of the MainActivity object.
After some looking I came across using Broadcast messages, specifically using the LocalBroadcastManager to send an intent to the activity. This code example works for my model, but I want to know: is this the best way for me to go about sending messages to my MainActivity from my Entry object?
If there is a more effective way of doing all this, what would it be?
You're overcomplicating things. Don't override onClick for this. Instead, have your activity call setOnClickHandler on your view, which sets a callback that's called when the view is clicked. Then use the default implementation.
Since you extend view, i guess you want to use it inside a layout. That means you may want to create a Listener for that. Example:
public class Entry extends View implements View.OnClickListener{
private OnClickListener listener;
public void setListener(OnClickListener listener) {
this.listener = listener;
}
#Override
public void onClick(){
if (this.listener != null) this.listener.onClick(this);
}
}
How you can inflate your layout in your Activity and access your custom view.
public class MainActivity extends AppCompatActivity{
public void onCreate( ...) {
Entry entry = findViewById(R.id.entry);
entry.setListener(new OnClickListener(...));
}
}
In my Android activity I have created members which I want to access from my custom button created dynamically. Is there a mechanism to do this?
Thanks in advance.
You can create interface:
interface SomeDataProvider {
SomeData get();
}
Your activity (or activity member) should implement this interface. Then, in custom button class you will have the following:
public class CustomButton {
private SomeDataProvider mDataProvider;
public void setDataProvider(SomeDataProvider provider) {
mDataProvider = provider;
}
}
After creating custom button dynamically, you should call setDataProvider() method. But it is not safe to call CustomButton#mDataProvider.get() method after any long background action, because hosting activity could be destroyed.
Depending on how you wish to tackle this you could:
Set the current activity into your Application object (do so for onCreate, onResume) and provide a reference to your Application for every custom object constructor.
If you are creating the Custom Button from the activity, you could pass the Activity as a reference and ensure your members have proper getters/setters.
I have an activity which contains a ViewPager inside it.The ViewPager's Adapter is FragmentStatePagerAdapter. Each page is Fragment.The Fragment contains a number of Threads. My problem is, I have to stop all the threads inside the fragment when ViewPager's page is changed.How can I do this ?
you have asked about communication between activity and fragment that you achieve using interface:
Your Fragment:
public class YourFragment
extends Fragment{
private OnListener listener;
public interface OnListener
{
void onChange();
}
void initialize( OnListener listener)
{
this.listener = listener;
}
//onview pager change call your interface method that will go to the activity as it has the listener for interface.
listener.onChange();
}
Your Activity:
public class yourActivity
extends Activity
implements yourFragment.OnListener
{
// intialize the method of fragment to set listener for interface where you define fragment.
yourFragment.initialize( this );
// implement what you want to do in interface method.
#Override
public void onChange()
{
// implement what you want to do
}
}
hope it will help.
Android's philosophy with applications is to kill processes, so maybe following the same idea you could kill your Threads. Be aware though that this can lead to deadlocks if your Threads own locks, or monitors.
A more serious approach to me seems to use Thread.interrupt() from your Activity. Then your Threads in your Fragment have to check Thread.interrupted for interruption, and finish gracefully if they've been interrupted.
You can use Thread.join() if you want some synchronous behavior
In addition, you can wait for a certain amount of time for your Thread to finish gracefully using a Timer, then kill them on timeout.
Please have a look at java.lang.Thread
To let this be more easy to implement, you could use a ThreadPoolExecutor or some other helper of java.util.concurrent package.
I have a problem about setting a TextView from a class which is not a child class of Activity. This class is basically used for handling registration and REST request with 3rd party server.
After getting textfield info from 3rd Party server, it is too late to set TextView in the Main Activity.
I can't use SharedPreferences to set this info, because MainActivity has already started.
I can't pass this info with Bundle since my java class is not an activity class.
How can I pass this info and set the TextView in the MainActivity? Is there any way to do this?
The proper way of doing this this is to create a listener.
Create an interface :
public interface OperationCompletedListener{
void onOperationCompleted(String resultValue);
}
Then in your class which calls Rest services, create a variable for this listener and a method to set it.
private OperationCompletedListener mListener;
public void setOperationCompletedListener(OperationCompletedListener listener){
mListener=listener;
}
Then when the your rest service completed call like below :
if(mListener!=null){
mListener.onOperationCompleted("your value to be passed");
}
Then in your activity class which contains the TextView, create an object of OperationCompletedListener and set it to the other class using the set method that we created earlier. Then in the onOperationCompleted method, set the text view with your value and you are done.
private OperationCompletedListener mOperationCompletedListener=new OperationCompletedListener() {
#Override
public void onOperationCompleted(String resultValue) {
yourTextView.setText(resultValue);
}
};
restServiceClassObject.setOperationCompletedListener(mOperationCompletedListener);
You can create an static method which update textview in your activity class . Then call this method from your other class whenever you want.
Try to pass the Activity to the non-Activity class when you instantiate it. For example:
public class NonActivityClass {
private Activity parentActivity;
public NonActivity(Activity parentActivity) {
this.parentActivity = parentActivity;
}
}
Or you can just pass the Activity to a static method in your NonActivityClass if you don't want to instantiate it (it's abstract). Then, you can inflate the TextView or do a findViewById from the parent and set the text.
From my experience, you should never use a static non-final variable to maintain a reference across activities. When you restart the app or the phone, or when Android kills your app's process, the reference and state of the variable becomes lost and may cause your app to crash.
I have a custom gallery view in which I am overriding some methods. I would like to be able to call a function in my main activity from this class. How do I make a reference back to my main class?
I thought I'd just push the class reference into CustomGallery by creating a setter function ---> g.setBaseClass(this);
CustomGallery g = (CustomGallery) findViewById(R.id.playSelectionGallery);
g.setSpacing(10);
g.setCallbackDuringFling(false);
g.setAdapter(new ImageAdapter(this));
g.setSelection(1);
registerForContextMenu(g);
g.setBaseClass(this);
Problem is this is of type Context and someFunctionToCall() will result in a not a member of this class error. In my custom class I have:
public void setBaseClass(Context baseClass)
{
_baseClass = baseClass;
}
private void callSomeFuntionOnMyMainActivityClass()
{
_baseClass.someFunctionToCall();
}
All I want to do is call back to my main class, called ViewFlipperDemo. This would be easy in As3. Any thoughts? Hopefully I'm missing something really simple.
That's actually not a good idea... but you can do it this way:
private void callSomeFuntionOnMyMainActivityClass()
{
((ViewFlipperDemo)_baseClass).someFunctionToCall();
}
What you should do instead is implementing a simple observer which allows you to notify the Activity that something happened. That's one of the main OO principles, your custom class shouldn't know anything about your activity class.
Observer pattern example
The Observer interface:
// TheObserver.java
public interface TheObserver{
void callback();
}
Your custom view:
public class CustomGallery{
private TheObserver mObserver;
// the rest of your class
// this is to set the observer
public void setObserver(TheObserver observer){
mObserver = observer;
}
// here be the magic
private void callSomeFuntionOnMyMainActivityClass(){
if( mObserver != null ){
mObserver.callback();
}
}
// actually, callSomeFuntionOnMyMainActivityClass
// is not a good name... but it will work for the example
}
This is the activity that will benefit of the observer (notice that now you can use your custom view on different activities not just one, that's one of the key reasons to implement it this way):
public class YourActivity extends Activity{
// your normal stuff bla blah
public void someMethod(){
CustomGallery g=(CustomGallery)findViewById(R.id.playSelectionGallery);
g.setObserver(new TheObserver(){
public void callback(){
// here you call something inside your activity, for instance
methodOnYourActivity();
}
});
}
}
You will notice that this design pattern (observer) is widely used in Java and Android... almost any kind of UI event is implemented using observers (OnClickListener, OnKeyListener, etc.). By the way, I didn't test the code, but it should work.