I am developing an augmented-reality app in Android. I have one class which called AugmentedView, extends view and it is responsible to draw the markers. In the onDraw method when it detects collisions i want to notify the parent class which is the main class and contains the main gui to enable one button in the screen. I call the AugmentedView class in the onCreate of Main class with the following code:
AugmentedView augmentedView = new AugmentedView(this);
augmentedView.setOnTouchListener(this);
augmentedView.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
liveLayout.addView(augmentedView);
How can i notify the main class for the changes and pass the List of markers to it?
If I'm understanding your problem correctly , you want to notify the Activity/Fragment that contains your AugmentedView.
A simple way to do that is by using java callbacks.
// in Activity
//onCreate() ..
AugmentedView augmentedView = new AugmentedView(this);
augmentedView.setOnTouchListener(this);
augmentedView.setCollisionlistener(new Collisionlistener());
augmentedView.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
liveLayout.addView(augmentedView);
}
..
public class Collisionlistener {
public void onCollosion (){
// write code to handle collosion
}
}
// in your AugmentedView
private Collisionlistener mListener;
public void setCollisionlistener(Collisionlistener listener){
mListener = listener;
}
public void onDraw(Canvas canvas){
// your code
if (collosionDetected && mListener != null) {
mListener.onCollosion();
}
}
Related
Update
My small showcase is stored on Bitbucket
https://bitbucket.org/solvapps/animationtest
I have an Activity with a view in it. Contentview is set to this view.
public class MainActivity extends AppCompatActivity {
private MyView myView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView = new MyView(this);
setContentView(myView);
startMovie();
}
public void startMovie(){
MovieTask movieTask = new MovieTask(myView, this);
movieTask.doInBackground(null);
}
}
A MovieTask is an Asynctask and refreshes the view periodically.
But invalidate() doesn't refresh the view.
public class MovieTask extends AsyncTask<String, String, String> {
MyView drawingView;
MainActivity mainActivity;
public MovieTask(MyView view, MainActivity mainActivity){
this.mainActivity = mainActivity;
this.drawingView =view;
}
#Override
protected String doInBackground(String... strings) {
for(int i=20;i<100;i++){
drawingView.myBall.goTo(i,i);
publishProgress();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
mainActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("DEBUG_DRAW","in onProgressUpdate()");
drawingView.invalidate();
}
});
}
}
Can someone help ?
See how you are launching the AsyncTask:
public void startMovie() {
MovieTask movieTask = new MovieTask(myView, this);
movieTask.doInBackground(null);
}
You are manually calling a method inside some class called MovieTask, thus you are running a code on the same thread. Obviously, that is not your intention, you intended to run the computation code on a background thread.
Correct way to launch AsyncTask is using execute(Params...):
public void startMovie() {
MovieTask movieTask = new MovieTask(myView, this);
movieTask.execute("");
}
Now you will get the desired effect.
P.S.
Please, do not use that code: you do not need to launch a background thread in order to do that kind of stuff. As an alternative consider Animators API.
Declare setBall(int pos) method inside MyBall class:
public class MyView extends View {
...
public void setBall(int pos) {
myBall.setX(pos);
myBall.setY(pos);
invalidate();
}
}
Then change startMovie() to following:
public void startMovie() {
// "ball" means, that Animators API will search for `public setBall(int)` method inside MyView.java and call that method
ObjectAnimator ball = ObjectAnimator.ofInt(myView, "ball", 20, 100);
ball.setDuration(1000);
ball.start();
}
You'll get the same animation without a nasty code.
There is two possible case, first as described in documents:
void invalidate ()
Invalidate the whole view. If the view is visible,
onDraw(android.graphics.Canvas) will be called at some point in the
future.
So try to run your code in onResume, there is a chance that View is not visible yet.
Secondly View#invalidate tells the system to redraw the view as soon as the main UI thread goes idle. That is, calling invalidate schedules your view to be redrawn after all other immediate work has finished.
If you'd like to have your view updated periodically use Handler#postDelay or run it in a separate thread and use View#postInvalidate to update the View and trigger the call to onDraw.
I have a method inside MainActivity named PlaySong(), and from MainActivity, I'm calling a custom AlertDialog class like this
SongListDialog songlistDialog = new SongListDialog(this, songsList);
songlistDialog.show();
how can I call PlaySong() from songlist which is inside the SonglistDialog. Currently I have this ListView and I can track the click on any song using the following code:
#OnClick(R.id.card_view)
void onClick() {
Song song = songs.get(getAdapterPosition());
dialog.dismiss();
// here I want to call PlaySong() method which is inside MainActivity
}
Any idea how to do this?
the best way to avoid leaks is to create a listener interface
public interface SongListListener {
void playSong(Song song);
}
then on your SongListDialog constructor
private final SongListListener mListener;
public SongListDialog(SongListListener listener, ...) {
mListener = listener;
}
#OnClick(R.id.card_view)
void onClick() {
Song song = songs.get(getAdapterPosition());
dialog.dismiss();
// notify listener
mListener.PlaySong(song);
}
Finally implements SongListListener in your MainActivity
public class MainActivity extends Activity implements SongListListener {
//...
#Override
void playSong(Song song){
//do whatever you want with the song here
}
//...
}
You can use a callback.
public interface OnSongSelectedListener{
void onSongSelected(Song song);
}
// Then in your Activity
SongListDialog songlistDialog = new SongListDialog(this, songsList, songSelectedListener);
songlistDialog.show();
Ideally, the Activity itself should implement the interface. So songSelectedListener will be MainActivity.this.
Then in the onClick you do:
void onClick() {
Song song = songs.get(getAdapterPosition());
listener.onSongSelected(song); // Return the selected song
dialog.dismiss();
// here I want to call PlaySong() method which is inside MainActivity
}
Since you are passing the MainActivity in new SongListDialog(this, songsList) you can directly call playSong on it by casting e.g.
public SongListDialog(Context ctx, ...) {
((MainActivity) ctx).playSong();
}
you want to pass context in adapter from your activity and use that context
((MainActivity)context).playSong();
I created an unity project and I'm trying to send data from c# to unity. on my c# code I implemented this code :
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("shareText","test","test");
It works on android on my activity :
public class UnityActivity extends AppCompatActivity {
public void shareText(String AppId,String PublisherID) {
Log.e("test","test");
Log.e("test",AppId);
Log.e("test",PublisherID);
}
}
but in another case I created a custom view containing unityPlayer.
So now I have UnityActivity containing UnityView (which is a java class) and the last one contain my custom view (extend linearLayout) with unityPlayer and with the same code it didn't work :
public class CstUnityView extends LinearLayout {
private UnityPlayer mUnityPlayer;
public void shareText(String AppId,String PublisherID) {
Log.e("test","test");
Log.e("test",AppId);
Log.e("test",PublisherID);
}
}
Anyone have an idea why it didn't work ?!
So your problem is that the shareText() in your custom linearlayout cannot be called by unity unless it is declared in activity. It needs to be declared in your activity in order for your unity Call to ignite the function.
You can check the console log first to make sure it has been called.
After, you can use those that you have received from your activity to your custom layout view.
in your activity
protected UnityPlayer mUnityPlayer;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//this creates unityplayer with context to your activity
mUnityPlayer = new UnityPlayer(this);
//this requests focus so that the currentactivity is set to your activity
//that is why shareText() can be called from your Unity
mUnityPlayer.requestFocus();
//call layout here
yourLinearlayout customlayout = new yourLinearLayout();
//do what you want to do with this customlayout
//....
}
public void shareText(String AppId,String PublisherID) {
Log.e("test","test");
Log.e("test",AppId);
Log.e("test",PublisherID);
}
I am struggling to figure out how to simply call and run a method from a class (that is not an activity) on my current activity.
my current code:
CustomListViewAdapter.java (other class)
public void onClick(View v) {
int position = Photos.listView.getPositionForView(v);
Log.v("value ", "tada" + position);
Photos photos = new Photos();
photos.deletePhoto(position);
}
});
Photos.java (my current activity class)
public void deletePhoto(int pos){
Toast.makeText(thisActivity, "delete index:"+pos , Toast.LENGTH_SHORT).show();
mylist.remove(pos);
setupListView();
}
Problem is, this way of doing it makes a new instance of mylist which gives me a outofbounds error. How can I do this correctly so I get the current activity and update it accordingly?
If you don't want a static method, you could create in interface.
public interface DeleteInterface {
public void deletePhoto(int position);
}
And then in your adapter's constructor...
private DeleteInterface mInterface;
public CustomListAdapter(/* other paramaters */ DeleteInterface interface) {
// other assignments
mInterface = interface;
}
And then in your Activity...
public class Photos extends Activity implements DeleteInterface {
// your code here
public void deletePhoto(int pos) {
// your method here
}
}
But make sure that when you create your Adapter, you have a pointer to the current Activity and pass it through the Adapter's constructor.
Last but not least...
In your adapter, call mInterface.deletePhoto(position); to call your Activity's method.
I wonder how I can best create a progress bar fragment. It must be usable by every other class of course.
At the moment I have just a ProgressBarFragment, which has public setVisible method. Getting the Fragment through FragmentManager I can set it visible or not. But is this the right way to do these sort of actions?
public class MyActivity exetends FragmentActivity {
void setVisibility(int visible) {
ProgressBarFragment fragment = (ProgressBarFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_progress_bar);
fragment.setProgressBar(visible);
}
}
And of course I have several other Fragments which uses this code too, to trigger the progress bar.
public class ProgressBarFragment extends Fragment {
public void setProgressBar(int visible) {
progressBar = (ProgressBar) getActivity().findViewById(R.id.progress_bar);
progressBar.setVisibility(visible);
}
}
You can refactor this code into a static method of your ProgressBarFragment
class ProgressBarFragment {
//...
static void setVisibility(Activity parent, int visible) {
ProgressBarFragment progressBar =
(ProgressBarFragment)parent.getSupportFragmentManager()
.findFragmentById(R.id.fragment_progress_bar);
progressBar.setProgressBar(visible);
//...
}
So then you will be using ProgressBarFragment.setVisibility(yourActivity, 1) everywhere.