how to make a textview that change automatically after some seconds - java

I want to make a text view that will update the text after 12 seconds randomly from an array list, automatically.
My code is not working well, it just changes the text one time but I want it to change it every 12 sec.
Here is is the onCreate method of my fragment:
#SuppressLint("SetTextI18n")
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
TextView topStatus_tv = root.findViewById(R.id.TopStatus);
String[] topStatus = {
"Hello ", //0
"Welcome to your PERSONAL DICTIONARY",//1
"Hi Whats up beauty?",//2
"Good Evening, sir",//3
"how is the Weather",//4
"Get Motivated, go on",//5
"By upgrading your second language, open your mind and be more clever",//6
"Practice everyday!",//7
"Make good habits",//8
"Your HABITS will make a good person from you,\nnot just your Believes",//9
"Knock knock! who is it?\nits the programmer needs your donation",//10
"First make a good Believe, then make good habits\n(Good does not mean perfect)",//11
"Decrease blaming, increase accepting",//12
"You know? sometimes im tired from everything. ",//13
"Music is strange, isn't it?",//14
"you wanna see someone weird? goto setting, press donate button and choose 1000$.\nthen go look at the mirror",//15
"Spotify, IM COMING FOR YOU!!!",//16
"Don't work too much.\ngo hangout with your friends, their idiots",//17
"you know? In parallel worlds you are coding and I am using your app",//18
"When you are in a good mood, the world has to give you what you want",//19
"make a wall from others goodness.\nwhen they make a mistake, take one brick from wall, don't break it."//20
};
Handler handler = new Handler();
for (int i = 0; i < 100; i++) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
int random = new Random().nextInt(20);
topStatus_tv.setText(topStatus[random]);
}
}, 12000);
}
return root;
}

Assign your Runnable to a variable. Then use the variable in postDelayed. At the end of your run() function call postDelayed with the Runnable-variable again with 12 seconds.
Remove your for loop and use a counter variable to limit the number of repetitions.
Something like this (without the counter):
class YourActivity {
// ...
private Handler handler = new Handler();
private Runnable runnable;
public View onCreateView() {
// ...
runnable = new Runnable() {
#Override
public void run() {
int random = new Random().nextInt(20);
topStatus_tv.setText(topStatus[random]);
handler.postDelayed(runnable, 12000);
}
};
handler.postDelayed(runnable, 12000);
// ...
}
}

You can give id to the textView and use onClickListener in your java code and setTime

Related

Trying to make a basic counter using scheduled executor service

I'm new to java and was trying to make a simple android app that does the following:
display a window in the main activity
every second the value of integer i is increased by 1
update the window content to display the value of i every second
for example the window should display the following text:
1st second: "update 1"
2nd second: "update 2"
3rd second: "update 3"
...
etc
I learned that using java's ScheduledExecutorService with ScheduleAtFixedRate is better than implementing an infinite loop, so I attempted the following code:
public class MainActivity extends AppCompatActivity {
public FrameLayout mLayout;
public WindowManager wm;
public WindowManager.LayoutParams lp;
public int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// display a window saying "hello"
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
lp = new WindowManager.LayoutParams();
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.text_bubble, mLayout);
((TextView) mLayout.findViewById(R.id.text)).setText("hello");
wm.addView(mLayout, lp);
//creating a scheduled executor service, it runs the method "myTask" at fixed rate of 1 second
final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
myTask();
}
}, 0, 1, TimeUnit.SECONDS);
}
private void myTask() {
Log.v(TAG,"Running");
//Increment i by 1 and update the window layout
i = i + 1;
((TextView) mLayout.findViewById(R.id.text)).setText("update " + i);
wm.updateViewLayout(mLayout, lp);
}
}
When I start the app it does display the window as intended, but it doesn't update the number every second, instead it only shows "update 1". I can't tell why as I didn't get any errors. After some trial and error I found that when I remove the last two lines from the myTask method (the lines responsible for updating the text of the window layout):
((TextView) mLayout.findViewById(R.id.text)).setText("update " + i);
wm.updateViewLayout(mLayout, lp);
when I remove these two lines the executor service will function just fine, and I can see that by watching the logged text message "running" popping every second. but when I add those two lines again, it doesn't pop these messages anymore(except for the first second).
so what am I doing wrong here? I thought the problem could be about the the way I update the layout maybe. what am I missing here?
Try this:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
//Your stuff
}
}, 0, 1000);
Or this using the scheuldedServiceExecutor:
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
//Your stuff
}, 1, 5, TimeUnit.SECONDS);

Boolean in Retrofit from a json object

I have a status in my json object that was set to boolean. My main problem is that in every handled time let's say 5 secs it will add another set of status which is the previous status displayed and it has no end. I'm not sure what triggered this can anyone help me with this I'm just starting to learn android.
Update 2
You need to clear the old content of the TextView before appending any new content
//hardware
hardwareStatus.setText("") // Clear old response data from TextView
for (int i = 0; i < response.body().getHardware().length; i++){
// Your logic
}
//software
softwareStatus.setText("") // Clear old response data from TextView
for (int i = 0; i < response.body().getSoftware().length; i++){
// Your logic
}
Update 1
You're seeing the old results because your appending to the results TextView
hardwareStatus.append(spannable);
hardwareStatus.append("\n\n");
Just use
hardwareStatus.setText(spannable);
Old
From my understanding you are running into an infinite loop of api calls that is triggered every 5 seconds, if that is the case It's because you are calling the postDelayed function again inside the runnable, if you're looking to call the endpoint just one time then remove this line
handler.postDelayed(runnable = new Runnable() {
public void run() {
//do your function;
getSystemObject();
handler.postDelayed(runnable, apiDelayed); // Remove this
}
}, apiDelayed);
Another thing to note here is that you should be initializing the views in the
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
hardwareName = view.findViewById(R.id.hardware_name);
hardwareStatus = view.findViewById(R.id.hardware_status);
softwareName = view.findViewById(R.id.software_name);
softwareStatus = view.findViewById(R.id.software_status);
flagName = view.findViewById(R.id.flagreport_name);
}
Also you're building the retrofit instance every time you call the api, it's better to create a singleton for retrofit and call the create method to initialize a global variable in your fragment or activity, then use this variable in your function like this
// Global variable
private WebApi api = Retrofit.getInstance().create(WebApi.class);
then in any function call
api.getNameStatus();
Call getSystemObject from onViewCreated instead of from onResume.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
handler.postDelayed(runnable = new Runnable() {
public void run() {
//do your function;
getSystemObject();
handler.postDelayed(runnable, apiDelayed);
}
}, apiDelayed);
}

android - set intent extra from inside runnable

I'm still new to android development. I've been at this problem for some time but am still unable to figure out what to do on my own. In an Activity I set up a series of Runnables containing CountDownTimers. One executes after the next, but depending on which CountDownTimer is active, I need to pass a different Intent.extra to a fragment. I've tried setting my extra from inside Runnable, inside Run, and inside of the CountDownTimer onTick, and onFinish.
I fear I have way too much going on in my original Activity to post it, but here is the problem in essence.
public class MatchUpActivity extends Activity implements OpponentFragment.OnFragmentInteractionListener{
List mTotalDrafts;
Bundle mBundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_match_up);
mBundle = new Bundle();
mDraftUsernames = extras.getStringArrayList("DRAFT_LIST");
for (int i = 0; i < totalDrafts; i++) {
Handler delayhandler = new Handler();
delayhandler.postDelayed(new Runnable() {
//bundle.put("extra", totalDrafts.get(0))
public void run() {
//bundle.put("extra", totalDrafts.get(0))
getTimer();
}
}, mTodaysDraftTime + (i * singleDraftDuration) - Calendar.getInstance().getTimeInMillis());
}
}
CountDownTimer
private void getTimer() {
new CountDownTimer(singleDraftDuration, 1000) {
public void onTick(long millisUntilFinished) {
//bundle.put("extra", totalDrafts.get(0))
}
public void onFinish() {
//bundle.put("extra", totalDrafts.get(0))
list.remove(0)
}
}.start();
}
}
I am able to remove items from my list in onFinish, but after I do so I need to send the next element in the list as an extra.
I hope this is enough code to get my question across. I tried to change some things from my original code for simplicity. If there is something I am missing or a better way to do this, please, anybody let me know.
Define the Bundle as global variable in your Activity and not in a Method implementation.

Updating Fragments - FrameStatePagerAdapter and HTTP Calls

I have been searching for an answer to my problem, but I seem to get none, despite of how many tutorials I followed, how many questions I've gone through and how many things I've tried to do what I want. Basically, I stumbled upon some good tips, and still couldn't manage to do what wanted.
THE PROBLEM
I am creating an Android Application that will use Fragments (alongside with tabs). In these fragments, I have crucial information relating the application, such as text boxes, and buttons. However, I want to do something really simple, which is updating one of my fragments as I come back to it (imagine I swipe back to a fragment, and I update it with the relevant information). Where is the information stored? On a node.js server, to which I call every time I want information. So for that, I created the following structure.
THE STRUCTURE
First of all, I started off creating my Activity.
public class CentralActivity extends FragmentActivity {
CentralPagerAdapter mCentralActivity;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_central);
tabHandler();
}
public void tabHandler() {
mCentralActivity = new CentralPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.CentralPager);
mViewPager.setAdapter(mCentralActivity);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
getActionBar().setSelectedNavigationItem(position);
}
});
//Action Bar Stuff
}
}
With this said, I need my CentralPagerAdapter, which I created as follows.
public class CentralPagerAdapter extends FragmentStatePagerAdapter {
private int nSwipes = 3;
public CentralPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new CentralFragment();
Bundle args = new Bundle();
args.putInt(CentralFragment.ARG_OBJECT, i + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
return nSwipes;
}
}
And now, my fragment, which is only a class that contains all of my views, and options and so on.
public class CentralFragment extends Fragment {
public static final String ARG_OBJECT = "object";
private View rootView;
private RESTFunction currentFunction;
//Has the info I want
private ArrayList<Integer> tickets = new ArrayList<Integer>();
#SuppressLint("HandlerLeak")
private Handler threadConnectionHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (currentFunction) {
case GET_CLIENT_TICKETS:
handleGetTickets(msg);
break;
case BUY_CLIENT_TICKETS:
break;
default:
break;
}
}
};
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
final Bundle args = getArguments();
handleFragments(inflater, container);
getTicketInfo(null);
return rootView;
}
private void handleFragments(LayoutInflater inflater, ViewGroup container) {
Bundle args = getArguments();
if (args.getInt(ARG_OBJECT) == 1) {
rootView = inflater.inflate(R.layout.fragment_show_tickets,
container, false);
showTicketsHandler();
} else if (args.getInt(ARG_OBJECT) == 2) {
rootView = inflater.inflate(R.layout.fragment_buy_tickets,
container, false);
buyTicketsHandler();
} else {
rootView = inflater.inflate(R.layout.fragment_history_tickets,
container, false);
}
}
public void showTicketsHandler() {
//Get stuff from the tickets array that the REST call will handle
//And set them to boxes or radio buttons
}
public void buyTicketsHandler() {
//Get stuff from the tickets array that the REST call will handle
//And set them to boxes or radio buttons
//As well as button click listeners
}
public void getTicketInfo(ProgressDialog progDialog) {
//Connect to the thread to get the information
//In this case, I have no parameters
ConnectionThread dataThread = new ConnectionThread("myLink", Method.GET, null, threadConnectionHandler, progDialog);
dataThread.start();
}
//Get stuff from the resulting JSON and store it in the tickets ArrayList
private void handleGetTickets(Message msg) {
JSONObject ticketListing = (JSONObject) msg.obj;
try {
tickets.add(ticketListing.getInt("t1"));
tickets.add(ticketListing.getInt("t2"));
tickets.add(ticketListing.getInt("t3"));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
And then, I have my thread..
public class ConnectionThread extends Thread {
private ConnectionRunnable runConnection;
private Handler mHandler;
private ProgressDialog progDialog;
public ConnectionThread(String link, Method method, ArrayList<NameValuePair> payload, Handler handler, ProgressDialog progDialog) {
runConnection = new ConnectionRunnable(link, method.toString(), payload);
mHandler = handler;
this.progDialog = progDialog;
}
#Override
public void run() {
runConnection.run();
threadMsg();
if(progDialog != null)
progDialog.dismiss();
}
public JSONObject getJSON() {
return runConnection.getResultObject();
}
private void threadMsg() {
Message msgObj = mHandler.obtainMessage();
msgObj.obj = getJSON();
mHandler.sendMessage(msgObj);
}
}
And ConnectionRunnable is where I run my HttpURLConnection.
SO WHAT DO I NEED?
Basically, what I'm trying to do, is to get the ticket information from the ConnectionThread BEFORE I load all my view and update them. Plus, I want to be able to swipe back and forth, and update my information on the array as I swipe through the screens (if I go to the second screen, the tickets will update, and if I come back to the first, they will re-update). So basically, call the ConnectionThread everytime I swipe around. If that is possible that, is.
WHAT HAVE I TRIED?
I've tried several things already, and all of them didn't actually help..
The usage of ProgressDialogs to stop the UI Thread on the onCreateView method of the fragment (no use, because it returns the rootView before it handles everything);
Making the UI Thread sleep for 1 second (I don't know why, it blocks all of them);
Overriding the instantiateMethod() of the Adapter, although I think I didn't do it correctly;
Overriding the saveState() of the Adapter, in order to prevent its saved states, and to then get new ticket information;
Giving the fragments tags to update their rootViews on the Adapter, but to no avail;
Getting the information in the activity, and everytime I make a purchase (second fragment), restart the whole activity to get the tickets, which I believe is a really, really bad solution.
I've read several articles, and I still couldn't find my answers.. It's really frustrating. Because it's something so simple, however, the fact that I have to run the HTTP calls on a different thread delays the whole UI updating process.
I've also read the AsyncTask's method. However, I feel like both Threads and AsyncTasks end up in the same.
WHAT TO DO NOW?
Well, that's what I was hoping to find. Because it ends up being annoying as it is.
POSSIBLE REASONS
Is it because I'm separating all classes into spread files, therefore making my work difficult?
Thank you for your time, guys, hope we can find a solution or something.
THE EDIT
So basically, after 4 hours of reading documents and tutorials, I figured that what I needed was setOffscreenPageLimit(int). However, it can't be set to 0, so I will have to do with a setOnPageChangeListener. Now, to figure how to refresh the fragment, and I'll be as good as new.
Alright, it works perfectly! Basically, I did this:
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
((CentralFragment)((CentralPagerAdapter) mViewPager.getAdapter()).instantiateItem(mViewPager, position)).refresh();
getActionBar().setSelectedNavigationItem(position);
}
});
Where my .refresh is:
public void refresh() {
Bundle args = getArguments();
if (args.getInt(ARG_OBJECT) == 0) {
getTicketInfo(0);
} else if (args.getInt(ARG_OBJECT) == 1) {
getTicketInfo(1);
buyTicketsHandler();
} else {
//To Handle Later
}
}
It's as simple as refreshing the page before you go to it. Why didn't I remember this before..? So, here's the reference for those who ever need this!

How to pause/delay on Android?

I am currently learning how to develop applications for Android mobile devices.
I wrote a test application to display numbers 0-9 on the device screen. I created a simple function to delay the number change.
However, upon running the application, only the final number is displayed. There is also a delay before this final number shows. I'm assuming that the length of the pause is my defined delay multiplied by the number of digits to be shown.
How do I create an app that changes the numbers with a delay?
public class AndroidProjectActivity extends Activity {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Main();
}
void Delay(int Seconds){
long Time = 0;
Time = System.currentTimeMillis();
while(System.currentTimeMillis() < Time+(Seconds*1000));
}
void Main() {
String ConvertedInt;
TextView tv = new TextView(this);
setContentView(tv);
for(int NewInt = 0; NewInt!= 9; NewInt++){
ConvertedInt = Character.toString((char)(NewInt+48));
tv.setText(ConvertedInt);
Delay(5);
}
}
One way of doing this is to create a runnable that updates your view. This will still update on the UI thread, but wait in the background. There might be mistakes in the below code, but it should run with minor tweaks..
Blocking in any of the system calls into your activity is not good, since you're blocking the UI thread. Your app will be force closed, with an Application Not Responding message. Here is another good example.
public class AndroidProjectActivity extends Activity {
private Handler mHandler;
private TextView mTextView;
private Runnable mCountUpdater = new Runnable() {
private int mCount = 0;
run() {
if(mCount > 9)
return;
mTextView.setText(String.valueOF(mCount+48));
mCount++;
// Reschedule ourselves.
mHandler.postDelayed(this, 5000);
}
}
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// Cleaner to load a view from a layout..
TextView tv = new TextView(this);
setContentView(tv);
mTextView = tv;
// Create handler on UI thread.
mHandler = new Handler();
mHandler.post(mCountUpdater);
}
}
Try creating a thread, which sleeps for certain interval of time, and then increment the value by 1 till 9. And use Handler to update the UI.
You can also use AsyncTask
The call to main() i blocking the UI so it can not display nay numbers until the call is finished.

Categories