How to refresh the view every second - android

I working with this app - https://github.com/googlesamples/android-AppUsageStatistics . I'm new in android and I'm trying to refresh the view in every second. Now the view is refreshing in onCreate() or onResume().
I'm trying to use this:
public class MainActivity extends AppCompatActivity implements UsageContract.View {
private ProgressBar progressBar;
private TextView permissionMessage;
private UsageContract.Presenter presenter;
private UsageStatAdapter adapter;
public static Context myContext;
private long getStartTime() {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
permissionMessage = (TextView) findViewById(R.id.grant_permission_message);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new UsageStatAdapter();
recyclerView.setAdapter(adapter);
permissionMessage.setOnClickListener(v -> openSettings());
presenter = new UsagePresenter(this, this);
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
presenter.retrieveUsageStats();
throw new RuntimeException(e);
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
}
private void openSettings() {
startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
}
#Override
protected void onResume() {
super.onResume();
showProgressBar(true);
presenter.retrieveUsageStats();
}
#Override
public void onUsageStatsRetrieved(List<UsageStatsWrapper> list) {
showProgressBar(false);
permissionMessage.setVisibility(GONE);
adapter.setList(list);
}
#Override
public void onUserHasNoPermission() {
showProgressBar(false);
permissionMessage.setVisibility(VISIBLE);
}
private void showProgressBar(boolean show) {
if (show) {
progressBar.setVisibility(VISIBLE);
} else {
progressBar.setVisibility(GONE);
}
} }
but is not working. What am I doing wrong? Why the view in not refreshing? Does anybody have an idea?

Ideally your view wouldn't be polling the presenter for updates, but to continue this way try using a timer to run your recurring task, eg:
private Timer updateTimer;
#Override
protected void onStart() {
super.onStart();
updateTimer = new Timer();
updateTimer.schedule(new TimerTask() {
#Override
public void run() {
presenter.retrieveUsageStats();
}
}, 0, 1000);
}
#Override
protected void onStop() {
super.onStop();
if(updateTimer != null) {
updateTimer.cancel();
updateTimer = null;
}
}

Related

How to avoid memory leak in Asyntask?

Below is my test code. I let the thread sleep on purpose. I tried to simulate the heavy IO task.
I tried to use static inner class. And also used the WeakReference. I think I must miss some very important part. I test the code is still leaking after the activity finished. Can anyone provide some hints? Thanks.
public class Main2Activity extends AppCompatActivity {
TextView textView;
MyAsyn myAsyn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
textView=findViewById(R.id.test_view);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
myAsyn=new MyAsyn(textView);
myAsyn.execute();
}
#Override
protected void onDestroy() {
super.onDestroy();
if (myAsyn!=null){
myAsyn.cancel(true);
}
}
static class MyAsyn extends AsyncTask {
WeakReference<TextView> textViewWeakReference;
public MyAsyn(TextView textView) {
this.textViewWeakReference = new WeakReference<>(textView);
}
#Override
protected Object doInBackground(Object[] objects) {
t(textViewWeakReference);
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
TextView textView= textViewWeakReference.get();
if (textView!=null) {
textView.setText("DONE");
}
}
}
public static void t( WeakReference<TextView> textViewWeakReference){
final TextView textView=textViewWeakReference.get();
new Thread(){
#Override
public void run() {
super.run();
try {
Thread.sleep(500000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (textView!=null) {
String a = textView.getText().toString();
String b = a + a;
}
}
}.run();
}
}

Thread in fragment with setRetainInstance(true)

I have a fragment with a thread inside it, starting in its onCreate method.
After thread finishes his work i need to send a message to the activity (myActivity) through the "clickButtonOperation".
This is the onCreate() method of my fragment:
public class HolderFragment extends My_Fragment{
private Thread myThread;
.
.
.
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
printf("MyActivity attached is: "+myActivity);
myThread=new Thread(new Runnable(){
#Override
public void run() {
int i=0;
while (i<3){
printf("Working...");
try {
Thread.sleep(2000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
myActivity.clickButtonOperation(new Object[]{
HolderFragment.this.toString()
});
}
});
myThread.start();
}
onCreateView returns NULL.
My question is:
Is it guaranteed that my "clickButonOperation" gets called after the new activity has been attached? or could this method be called before this process?
TEMPORARY SOLUTION:
I created a custom Thread class:
public abstract class My_Thread extends Thread {
private boolean runnable=true;
private boolean paused=false;
private Object[] arguments;
private My_ThreadHolder myHolder;
protected void onPostExecute(Object[] arguments){
while(paused);
runnable=false;
}
protected abstract void execute(Object[] arguments);
protected void notifyUpdate(){
while (paused);
}
protected boolean isRunnable(){
return runnable;
}
public void setArguments(Object[] arguments){
this.arguments=arguments;
}
public Object[] getArguments() {
return arguments;
}
public final void run(){
while (runnable){
execute(arguments);
onPostExecute(arguments);
}
}
public void attach(My_ThreadHolder holder){
myHolder=holder;
}
public My_ThreadHolder getHolder() {
return myHolder;
}
public void startThread(){
runnable=true;
start();
}
public void stopThread(){
runnable=false;
}
public void pauseThread(){
paused=true;
printf("Thread paused");
}
public void resumeThread(){
paused=false;
printf("Thread resumed");
}
}
And created these two:
public class My_ThreadHolder extends My_Fragment{
private TestThread myThread;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
printf("MyActivity attached is: "+myActivity);
myThread=new TestThread();
myThread.attach(this);
myThread.startThread();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (myThread!=null)myThread.resumeThread();
}
#Override
public void onDetach() {
super.onDetach();
myThread.pauseThread();
}
protected void onNotifyUpdateReceived(Object[] arguments){
myActivity.clickButtonOperation(arguments);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return null;}
#Override
protected void setGraphics(View view, Bundle savedInstanceState) {}
}
class TestThread extends My_Thread{
#Override
protected void onPostExecute(Object[] arguments) {
super.onPostExecute(arguments);
printf("Thread finished");
}
#Override
protected void execute(Object[] arguments) {
int i=0;
while(i<3){
printf("Working...");
try {
Thread.sleep(2000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
i++;
Object[] myArguments= new Object[2];
myArguments[0]=0;
myArguments[1]=i;
setArguments(myArguments);
notifyUpdate();
}
}
#Override
protected void notifyUpdate() {
super.notifyUpdate();
getHolder().onNotifyUpdateReceived(getArguments());
}
}
You cannot touch the UI from a background thread.. you need to use runOnUiThread method from Activity class, something like this
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
printf("MyActivity attached is: "+myActivity);
myThread = new Thread(new Runnable() {
#Override
public void run() {
int i = 0;
while (i < 3) {
printf("Working...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
myActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
myActivity.clickButtonOperation(new Object[]{
HolderFragment.this.toString()
});
}
});
}
});
myThread.start();
}

Counter in loop

How to do sample counter in Activity? This is not working.
public class MainActivity extends AppCompatActivity implements Runnable {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
run();
}
#Override
public void run() {
while (true) {
updateTv();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void updateTv() {
int counter = 100;
final TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(String.valueOf(counter));
counter--;
}
}
In onCreate() you're starting an infinite loop inside of the UI thread, blocking it completely. Alternatively you could use a Handler for periodic updates. Maybe using a bigger delay and stop it sometime.
public class MainActivity extends AppCompatActivity implements Runnable {
private final Handler mHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
run();
}
#Override
public void run() {
updateTv();
mHandler.postDelayed(this, 17);
}
public void updateTv() {
int counter = 100;
final TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(String.valueOf(counter));
counter--;
}
}
Anyway you should read What is the Android UiThread (UI thread) for sure.
Consider using Timer class which allows you to define a callback method that will be invoked at specified rate.
An example that fits your needs:
public class CounterActivity extends AppCompatActivity {
private TextView mCounterTextView;
private Timer mTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_counter);
mCounterTextView = (TextView) findViewById(R.id.counterTextView);
mTimer = new Timer();
mTimer.scheduleAtFixedRate(
new CounterTask(100), 0, TimeUnit.SECONDS.toMillis(1));
}
protected class CounterTask extends TimerTask {
protected int mCounter;
CounterTask(int initial) {
mCounter = initial;
}
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mCounterTextView.setText(String.valueOf(mCounter));
}
});
--mCounter;
}
}
}
One more thing that should be noticed. As Timer executes it's own thread - it prevents you from updating your UI from outside of the main thread. In that case
you have to register a Runnable using runOnUiThread method.
Also, calling findViewById in a loop is not the best idea.

Android Refresh TextView from Thread

I know there are already quite a number of discussions about this, but none of what I found could clear my confusion.
I'm using the Android SDK for the first time and my Java Skills are rather average.
I have the following Problem:
From my MainActivity - OnCreate() fct. I start a thread (Receiver), receiving data from a SocketStream. This thread shall refresh a TextView-Element on the GUI when new data was read from the stream.
What is a simple but proper way to do so? I read something about ASyncTask, but did not understand how to implement it.
public class MainActivity extends Activity
{
ExecutorService myExecutor;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println("this is a test"); System.out.flush();
try
{
myExecutor = Executors.newCachedThreadPool();
myExecutor.execute(Receiver.getInstance());
}
catch (IOException e)
{
e.printStackTrace();
}
}
...
public class Receiver implements Runnable
{
[...]
public void run()
{
while (true)
{
//blocking system-io-call to read data from socket..
//extract information
// *** update textView *** ??
}
}
}
You can implement handler in GUI thread to change GUI (in MainActivity in your case):
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//refresh textview
}
};
and than call it from another threads
activity.handler.sendEmptyMessage(what);
You can write your own constructor for Receiver:
public class Receiver implements Runnable
{
[...]
MainActivity activity;
public Receiver(MainActivity activity){
this.activity = activity;
}
public void run()
{
while (true)
{
//blocking system-io-call to read data from socket..
//extract information
// *** update textView *** ??
activity.handler.sendEmptyMessage(0);
}
}
}
You can use runOnUiThread
public class Receiver implements Runnable
{
[...]
public void run()
{
while (true)
{
//blocking system-io-call to read data from socket..
//extract information
runOnUiThread(new Runnable() {
public void run() {
// *** update textView *** ??
}
});
}
}
}
this is a example:
create Counter class :
public class Counter implements Runnable
{
private ICounterEvents listener;
public static Thread OBJ_THREAD = null;
public Counter()
{
OBJ_THREAD = new Thread(this);
}
public void setCountListener(ICounterEvents listener)
{
this.listener = listener;
}
public void start()
{
OBJ_THREAD.start();
}
#Override
public void run()
{
for(int i = 0; i < 100; i++)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
Message msg = Message.obtain();
msg.obj = i;
this.handler.sendMessage(msg);
}
}
private Handler handler =
new Handler()
{
#Override
public void handleMessage(Message msg)
{
if(Counter.this.listener != null)
{
int value = (Integer)msg.obj;
Counter.this.listener.countChanged(value);
}
}
};
}
and create a interface class:
public interface ICounterEvents
{
public void countChanged(int value);
}
and than in your main layout create a textview and a button,
and use this code in onCreate method in MainActivity:
public class MainActivity extends Activity implements ICounterEvents, OnClickListener
{
private TextView txtCounter;
private Button btnStart;
private Counter counter;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.setupViews();
}
private void setupViews()
{
this.counter = new Counter();
this.counter.setCountListener(this);
this.txtCounter = (TextView)findViewById(R.id.txtCount);
this.btnStart = (Button)findViewById(R.id.btnStart);
this.btnStart.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
this.counter.start();
}
public void countChanged(int value)
{
try
{
this.txtCounter.setText(value + "");
}
catch (Exception e)
{
}
}
}

Pointing to wrong UI from posted Runnable after screen orintation changes

This is my little test program. My problem is that from run() method I access to fields of wrong (old) Activity, which was destroyed after screen orientation changed. What's the way to handle this situation?
And, by the way, I must have my activity been recreated, because in real application I have different layouts for portrait and landscape modes!
public class MainActivity extends Activity {
private EditText edit;
private Button button;
private ProgressDialog progressDialog;
private boolean isLoginInProgress = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = (EditText) findViewById(R.id.edit_timer);
button = (Button) findViewById(R.id.btn_start);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
if (edit.getText().toString().length() == 0) throw new Exception();
long dTime = Long.parseLong(edit.getText().toString());
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
MainActivity.this.isLoginInProgress = false;
progressDialog.dismiss();
}
}, dTime);
progressDialog.show();
isLoginInProgress = true;
} catch (Exception e) {
Toast.makeText(MainActivity.this, "bad time value", Toast.LENGTH_SHORT).show();
}
}
});
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("loading");
if (savedInstanceState != null) { // activity is restarted
isLoginInProgress = savedInstanceState.getBoolean("fl_login");
edit.setText(savedInstanceState.getString("edit"));
}
if (isLoginInProgress) { // Show dialog again
progressDialog.show();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("fl_login", isLoginInProgress);
outState.putString("edit", edit.getText().toString());
}
#Override
public void onDestroy(){
super.onDestroy();
progressDialog.dismiss();
}
}
You Can Use Database(SQLITE) for Storing Your Values..

Categories

Resources