How to use context inside listener? - java

I have code like this:
else if (v == mSettings)
{
if (disappearView.getVisibility() == View.VISIBLE)
{
AlphaAnimation fadeOutAnimation = new AlphaAnimation(1, 0); // start alpha, end alpha
fadeOutAnimation.setDuration(1000); // time for animation in milliseconds
fadeOutAnimation.setFillAfter(true); // make the transformation persist
Animation out = AnimationUtils.makeOutAnimation(this, true);
disappearView.startAnimation(out);
disappearView.setVisibility(View.INVISIBLE);
out.setAnimationListener(new Animation.AnimationListener()
{
public void onAnimationEnd(Animation animation)
{
disappearView.setVisibility(View.GONE);
Animation in = AnimationUtils.loadAnimation(this, android.R.anim.fade_in);
bannerView.startAnimation(in);
bannerView.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) { }
#Override
public void onAnimationStart(Animation animation) { }
});
}
else {
Animation in = AnimationUtils.loadAnimation(this, android.R.anim.fade_in);
disappearView.startAnimation(in);
disappearView.setVisibility(View.VISIBLE);
bannerView.setVisibility(View.INVISIBLE);
bannerView.setVisibility(View.GONE);
}
}
It all works apart from this section in the animationListener:
Animation in = AnimationUtils.loadAnimation(this, android.R.anim.fade_in);
It wants a valid context but it is receiving an animationListener, what context do I give it, context really confuses me here.

Change it to:
Animation in = AnimationUtils.loadAnimation(MyActivityName.this, android.R.anim.fade_in);
It wants an instance of any class that extends Context. Since it is inside an anonymous inner class, when you use this you are referring to the inner class instance, and not to your Activity. My snippet refers to the Activity class that wraps the anonymous inner class. Since Activity extends Context, this is a valid argument.

Inside the listener, this is referring to the Listener. Try using ActivityName.this

Related

How can you change ViewPager2 position inside the ViewPager2Adapter?

I programmed a Vocabulary Trainer with Vocabulary Cards. The Vocabulary Cards are Entries in a Room Database created from an asset. I am displaying these Vocabulary Cards with ViewPager2 in an Activity. I have a 'correct' and a 'false' button and when the user clicks on either, I want to update the Vocabulary Card (-> The entry in the sqlite database) and automatically swipe to the next item of the ViewPager2.
If I implement the buttons in the ViewPager2Adapter, I can't find a way to change the position of the ViewPager2. If I implement the buttons in the activity the sqlite entry does not update properly (After it updates the entry, the activity is constantly refreshed, it seems like it never the leaves the OnClick methode of the button).
So is it possible to change the position of ViewPager2 from inside the ViewPager2Adpater?
Thanks for your help!
That is the relevant code if I have the buttons in my ViewPager2Adapter. Here I don't know how to change the position of the ViewPager2
public void onBindViewHolder(#NonNull #NotNull ViewHolder holder, int position) {
VocabularyCard vocabularyCard = currentCards.get(position);
holder.btn_correct.setOnClickListener(view -> {
vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard);
});
holder.btn_false.setOnClickListener(v15 -> {
vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard);
});
That is the relevant code if I have the buttons in the Activity. Here the update function triggers an infinite updating of the Activity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initAll();
btn_correct_2.setOnClickListener(view -> {
int currentPos = viewpager2.getCurrentItem();
vocabularyViewModel.getCurrentCards().observe(this, vocabularyCards -> {
if (vocabularyCards.size() == currentPos){
Intent intent = new Intent(TestActivity.this, MainActivity.class);
startActivity(intent);
}else {
viewpager2.setCurrentItem(currentPos + 1);
}
VocabularyCard vocabularyCard = vocabularyCards.get(currentPos);
vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard);
});
});
btn_false_2.setOnClickListener(view -> {
int currentPos = viewpager2.getCurrentItem();
vocabularyViewModel.getCurrentCards().observe(this, vocabularyCards -> {
if (vocabularyCards.size() == currentPos){
Intent intent = new Intent(TestActivity.this, MainActivity.class);
startActivity(intent);
}else {
viewpager2.setCurrentItem(currentPos + 1);
}
VocabularyCard vocabularyCard = vocabularyCards.get(currentPos);
vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard);
});
});
Objects.requireNonNull(getSupportActionBar()).setTitle(getResources().getString(R.string.learn_new_words));
LiveData<List<VocabularyCard>> allNewCards = vocabularyViewModel.getAllNewCards(goal);
allNewCards.observe(this, vocabularyCards -> vocabularyViewModel.setCurrentCards(vocabularyCards));
vocabularyViewModel.getCurrentCards().observe(this, vocabularyCards -> {
viewPager2Adapter.setCurrentCards(vocabularyCards);
viewpager2.setAdapter(viewPager2Adapter);
viewpager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
}
#Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
}
});
});
The update function in the Room DAO is straightforward:
#Update
void updateSingleVocabularyCard(VocabularyCard vocabularyCard);
I left out all the code that is not relevant.
There are several ways to propagate an event from the adapter to the activity where you manage your cards using ViewPager2. Let's have a look how it can be done either using an interface or using the same view model. But in any case I strongly recommend you to update your database in a background thread to prevent any possible UI lags.
1. Using an interface
This option is more flexible since you can propagate events as well as pass data as parameters. You can also reuse this interface for other cases. As far as I See you have a holder that has 2 buttons for the users to make choices. So our event here would be something like ChoiceEventListener, let's call this interface like so. Then you'd have to add a method to handle this event from within anywhere you wanna hear this event, and let's call its handle method onChoice(). Finally we would need a variable to indicate what the choice is. Now that ready to implement, let's write the new interface...
ChoiceEventListener.java
public interface ChoiceEventListener {
void onChoice(VocabularyCard vocabularyCard, boolean choice);
}
The next thing to do is to implement this interface where you want to listen to this event. In this case it is in your activity. There are 2 ways to do this:
You make your activity to inherit its methods using the implements keyword
YourActivity.java
public class YourActivity extends AppCompatActivity implements ChoiceEventListener {
// Use a background thread for database operations
private Executor executor = Executors.newSingleThreadExecutor();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initAll();
// You must construct your adapter class with the listener
ViewPager2Adapter adapter = new ViewPager2Adapter(/* Other params... */, this);
}
#Override
public void onChoice(VocabularyCard vocabularyCard, boolean choice) {
if(choice) {
// User pressed the correct button
}
else {
// User pressed the false button
}
// Update card in the background
executor.execute(()-> vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard));
}
}
You can implement it as an anonymous function
YourActivity.java
public class YourActivity extends AppCompatActivity {
// Use a background thread for database operations
private Executor executor = Executors.newSingleThreadExecutor();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initAll();
// You must construct your adapter class with the listener
ViewPager2Adapter adapter = new ViewPager2Adapter(/* Other params... */, (vocabularyCard, choice) -> {
if(choice) {
// User pressed the correct button
}
else {
// User pressed the false button
}
// Update card in the background
executor.execute(()-> vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard));
});
}
}
Finally the ViewPager2Adapter class implementation would be something like this:
ViewPager2Adapter.java
public class ViewPager2Adapter extends RecyclerView.Adapter<ViewPager2ViewHolder> {
// Here is your listener to deliver the choice event to it
private final ChoiceEventListener listener;
// Constructor
public ViewPager2Adapter(/* Other params... */, ChoiceEventListener listener) {
/* Other inits */
this.listener = listener;
}
public void onBindViewHolder(#NonNull #NotNull ViewHolder holder, int position) {
VocabularyCard vocabularyCard = currentCards.get(position);
holder.btn_correct.setOnClickListener(view -> {
listener.onChoice(vocabularyCard, true); // true for correct
});
holder.btn_false.setOnClickListener(v15 -> {
listener.onChoice(vocabularyCard, false); // false for false :)
});
}
}
2. Use the ViewModel for inter-communication
In this option we use a LiveData object to make page switching. The only thing you need to know in your activity is the current position which you get it from the adapter class. Once you update it in the adapter, set the current position value in live data so that you can switch the page in your activity.
VocabularyViewModel.java
public class VocabularyViewModel extends ViewModel {
public MutableLiveData<Integer> mldCurrentPosition = new MutableLiveData<>(0);
}
YourActivity.java
public class YourActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initAll();
vocabularyViewModel.mldCurrentPosition().observe(this, currentPosition -> {
if(currenPosition == null) return; // ignore when null
viewpager2.setCurrentItem(currentPosition + 1);
}
}
}
Finally the ViewPager2Adapter class implementation would be something like this:
ViewPager2Adapter.java
public class ViewPager2Adapter extends RecyclerView.Adapter<ViewPager2ViewHolder> {
// Use a background thread for database operations
private Executor executor = Executors.newSingleThreadExecutor();
public void onBindViewHolder(#NonNull #NotNull ViewHolder holder, int position) {
VocabularyCard vocabularyCard = currentCards.get(position);
holder.btn_correct.setOnClickListener(view -> {
// Update card in the background
executor.execute(()-> vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard));
// Then invoke switching to the next card
vocabularyViewModel.mldCurrentPosition.setValue(position + 1);
});
holder.btn_false.setOnClickListener(v15 -> {
// Update card in the background
executor.execute(()-> vocabularyViewModel.updateSingleVocabularyCard(vocabularyCard));
// Then invoke switching to the next card
vocabularyViewModel.mldCurrentPosition.setValue(position + 1);
});
}
}

Text appear after Splash screen

I want the Layout"authentification" to appear after the Splash screen, in my application it's appear by default please some one help me!!!!!
pleaaase i need help
public class Splash extends Activity {
LinearLayout ln;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splashh);
ln = (LinearLayout) findViewById(R.id.LinLaySpalScrenLogin);
final ImageView iv = (ImageView) findViewById(R.id.imageView);
final Animation an = AnimationUtils.loadAnimation(getBaseContext(),R.anim.rotate);
final Animation an2 = AnimationUtils.loadAnimation(getBaseContext(),R.anim.abc_fade_out);
iv.startAnimation(an);
an.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
iv.startAnimation(an2);
finish();
ln.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
}
You can set android:visibility="gone" in your LinearLayout xml file that contains your Splash Screen and then call yourlayout.setVisibility(View.VISIBLE); after you finish your animation.
Also your activity will end as soon as your animation finishes since you have called finish() before ln.setVisibility(View.VISIBLE); Try to remove finish() and only call it on some event such as Button click or something like that
You have ln.setVisibility(View.VISIBLE); after finish();. Try changing to :-
ln.setVisibility(View.VISIBLE);
finish();
However, this will probably not work as because as soon as the make the layout visible. The activity would finish. You probably want to display the authentication in another activity after the splash has completed.

Two animations one after another

I want to make 2 animation on activity for 2 images, and I want to do it with 2 conditions:
1. I want to start the animation after the activity finished to load to page, so instead of putting animation code under onCreate i put it under onResume is that OK? There is a better way to do it?
2. I want the second animation will start only after the first animation is finished...
Thanks
You'll want to use an Animation.AnimationListner You can set one on your first animation that will get a callback when the animation is complete. Inside that callback you can add the code that will start the second animation.
Depending on the API level you are coding for you can use AnimationSet or AnimatorSet. Also if you are extending View or one of its subclasses you can override View.onAnimationStart() and View.onAnimationFinish(). Or use the listener Tim mentions.
public class SplashActivity extends Activity{
Animation FadeInanimation, FadeOutanimation;
ImageView img;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
img= (ImageView) findViewById(R.id.img);
//Your Code Block....
FadeInanimation = AnimationUtils.loadAnimation(this,R.anim.image_fadein);
//FadeInanimation.setRepeatCount(Animation.INFINITE);
//FadeInanimation.setRepeatMode(Animation.RESTART);
FadeInanimation.setAnimationListener(FadeInAnimationListener);
FadeOutanimation = AnimationUtils.loadAnimation(this,R.anim.image_fadeout);
//FadeOutanimation.setRepeatCount(Animation.INFINITE);
//FadeOutanimation.setRepeatMode(Animation.RESTART);
FadeOutanimation.setAnimationListener(fadeOutAnimationListener);
img.startAnimation(FadeInanimation);
}
AnimationListener FadeInAnimationListener = new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
plane.startAnimation(FadeOutanimation);
}
};
}

How can I run a sequence of Animations? AnimationSet is failing me

I have a custom view Dial. This view has a custom animation DialAnimation that was written as a nested class of Dial. Below is the code from my Activity that instantiates Dial and attempts to perform a sequence of animations on it. When the code is run, only one of the animations is seen onscreen. What am I missing here?
Dial dial = (Dial) findViewById(R.id.dial);
DialAnimation anim1 = dial.new DialAnimation(0, 90, 3000);
DialAnimation anim2 = dial.new DialAnimation(180, 360, 3000);
anim2.setStartOffset(3500);
AnimationSet set = new AnimationSet(false);
set.addAnimation(anim1);
set.addAnimation(anim2);
dial.startAnimation(set);
one way to do it would be to set an AnimationListener on the first animation and override the onAnimationEnd() to make it start the next animation in the sequence. That would look something like this:
animation1Listener = new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationEnd(Animation animation) {
dial.startAnimation(animation2)
}
}
animation1.setAnimationListener(animation1Listener);
dial.startAnimation(animation1);
try animation listner in doinbackground() method this will update your animation in sequence
..OR u can use simple thread in you application .
Add a .setDuration(3500) method to each animation and ensure that the time for the duration and the time for the .setStartOffset(3500) method for the secondanimation match.

Why does my app force close when I setText in an update method?

I have an android app I am just experimenting things on and I cannot seem to figure out why my app force closes when I update a TextView via a while loop. When I comment out the updateText method it runs fine.
public class GameThread extends Thread {
Thread t;
private int i;
private boolean running;
private long sleepTime;
GameView gv;
public GameThread() {
t = new Thread(this);
t.start();
i = 0;
sleepTime = 1000;
}
public void initView(GameView v) {
this.gv = v;
}
public void setRunning(boolean b) {
this.running = b;
}
public boolean getRunning() {
return running;
}
public void run() {
while(running) {
i++;
update();
try {
t.sleep(sleepTime);
} catch(InterruptedException e) {
}
}
}
public void update() {
gv.setText(i); // when this is uncommented, it causes force close
Log.v("Semajhan", "i = " + i);
}
public class GameView extends LinearLayout {
public TextView tv;
public GameView(Context c) {
super(c);
this.setBackgroundColor(Color.WHITE);
tv = new TextView(c);
tv.setTextColor(Color.BLACK);
tv.setTextSize(20);
this.addView(tv);
}
public void setText(int i) {
tv.setText("i count: " + i);
}
public class Exp extends Activity {
GameThread t;
GameView v;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
v = new GameView(this);
setContentView(v);
t = new GameThread();
t.setRunning(true);
t.initView(v);
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (t.getRunning() == true) {
t.setRunning(false);
Log.v("Semajhan", "STOPPED");
} else {
t.setRunning(true);
Log.v("Semajhan", "RESTART");
}
}
return true;
}
protected void onDestroy() {
Log.v("Semajhan", "DESTROYING");
super.onDestroy();
}
protected void onStop() {
Log.v("Semajhan", "Stopping");
super.onStop();
}
I though i'd post the whole app since it is relatively small and so that I could get some help without confusion.
First, when you get a Force Close dialog, use adb logcat, DDMS, or the DDMS perspective in Eclipse to examine LogCat and look at the stack trace associated with your crash.
In this case, your exception will be something to the effect of "Cannot modify the user interface from a non-UI thread". You are attempting to call setText() from a background thread, which is not supported.
Using a GameThread makes sense if you are using 2D/3D graphics. It is not an appropriate pattern for widget-based applications. There are many, many, many, many examples that demonstrate how to create widget-based applications without the use of a GameThread.
You have to call it from the UI thread.
For more info check: Painless Threading .
If you decide to use a Handler, the easiest solution for you will be to:
Extend a View, override it's onDraw , in it draw the game objects, after you have calculated the game data for them first of course
The Handler: (in your Activity)
private Handler playHandler = new Handler() {
public void handleMessage(Message msg) {
gameView.postInvalidate(); // gameView is the View that you extended
}
};
The game thread has a simple
Message.obtain(playHandler).sendToTarget();
In 2 words, the View is responsible for the drawing (you can move the calculations in a separate class, and call it before the onDraw), the thread is responsible only for scheduled calls to the Handler, and the Handler is responsible only to tell the View to redraw itself.
You cannot update the UI of your app outside of the UI Thread, which is the 'main' thread you start in. In onCreate(Context) of you app, you are creating the game thread object, which is what is doing the updating of your UI.
You should use a Handler:
http://developer.android.com/reference/android/os/Handler.html

Categories

Resources