Splash screen leaking memory how to fix it? - java

My Splash screen leaking memory can anyone tell me how to fix that issue ?
public class SplashActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
new InnerClass(SplashActivity.this).loadNext();
}
private static class InnerClass {
private final WeakReference<Activity> weakReference;
private InnerClass(Activity activity) {
this.weakReference = new WeakReference<>(activity);
}
private void loadNext() {
Activity context = weakReference.get();
if (context != null) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
context.startActivity(new Intent(context, NavigationActivity.class));
context.finish();
}
}, 2000);
}
}
}
}
Here is the leak canary library report showing your activity leaking memory

Move the weakReference.get() method inside the run() method. Please try below:
private void loadNext() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
Activity context = weakReference.get();
if (context != null) {
context.startActivity(new Intent(context, NavigationActivity.class));
context.finish();
}
}
}, 2000);
}

Related

android studio activity starts before finishing prev one

I m calling prog() function in the Mainactivity which performs loading page using progress bar and I call just after the prog function LoginActivity. BUT, it calls login activity before exciting prog function, I am new at the android studio and need your help. here is my code
public class MainActivity extends AppCompatActivity {
ProgressBar pb;
int counter = 0;
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
prog();//loading page
Intent intentLoginPage = new Intent(MainActivity.this,LoginActivity.class);
startActivity(intentLoginPage);
}
public boolean prog(){// to dispay progress bar as loading bar in loading page
pb = findViewById(R.id.progressBar);
final Timer t = new Timer();
TimerTask tt = new TimerTask() {
#Override
public void run(){
counter++;
textView.setText(counter + "%");//0 to 100%
pb.setProgress(counter);
if(counter == 100)
t.cancel();
}
};
t.schedule(tt,0,60);
return true;
}
}
May be you need call startActivity in run()?:
TimerTask tt = new TimerTask() {
#Override
public void run(){
counter++;
textView.setText(counter + "%");//0 to 100%
pb.setProgress(counter);
if(counter == 100) {
t.cancel();
Intent intentLoginPage = new Intent(MainActivity.this,LoginActivity.class);
startActivity(intentLoginPage);
}
}
};

Timer in android java

I have 2 activity in activity2 i have a timer when activity create timer is started in activity on_Destroy i put timer_task.cancel(); but When opened the activity2 for the second time is create new timer task and not Canceled or destroyed the last timer and 2 timer is while be run in one activity
my code
private TimerTask mTimerTask;
private void doTimerTask(){
nCounter = 4;
qtimer.setMax(20);
if(mTimerTask!=null) {
mTimerTask.cancel();
}
mTimerTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
Log.d("Timerrrr",nCounter+"");
if(nCounter<1){
Finished();
}else {
qtimer.setProgress(nCounter);
nCounter--;
}
}
});
}};
// public void schedule (TimerTask task, long delay, long period)
t.schedule(mTimerTask, 0, 1000); //
}
private void stopTask() {
if (mTimerTask != null) {
Log.d("nCounter canceled",nCounter+"");
mTimerTask.cancel();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
mTimerTask.cancel();
MainActivity.this.finish();
}
Try This...
public void stopTimerTask(View v) {
//stop the timer, if it's not already null
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
}
And Where do u call your stopTask() method?
And I suggest don't put mTimerTask.cancel(); in onDestroy(), but put it in onStop().
I hope this helps you.

Start and stop timer service on click

I have a service that runs in the background and every 15 minutes, it will show a notification or dialog. But how can I get it to start and stop OnClick of a FAB?
The button shows a Snack Bar OnClick, currently. I want to add If/Else code to start and stop the service. How can I do this?
Here is the service:
public class SafeService extends Service {
private Handler mHandler = new Handler();
private Timer mTimer = null;
public static final int NOTIFICATION_ID = 1;
public static final long NOTIFY_INTERVAL = 900 * 1000; // 15 Minutes
/*^TODO - TEST NOTIFY_INTERVAL FOR ACCURACY^*/
/*^Those are for the timer and handler so the code
can recognise it^ The last one gives how long the timer runs */
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// Cancels the timer if it already existed.
if (mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
}
class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
// Lollipop or Above
if (Build.VERSION.SDK_INT >= 21) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(SafeService.this);
new NotificationCompat.Builder(SafeService.this);
builder.setSmallIcon(R.drawable.smallplaceholder);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
builder.setContentTitle("Safeguard");
builder.setContentText("Be careful, Trainer! Remember to look up and stay aware of your surroundings!!");
builder.setStyle(new NotificationCompat.BigTextStyle().bigText("Be careful, Trainer! Remember to look up and stay aware of your surroundings!!"));
builder.setPriority(Notification.PRIORITY_HIGH);
builder.setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 });
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, builder.build());
//Below Lollipop
} else {
new MaterialDialog.Builder(SafeService.this)
.title(R.string.warning_title)
.content(R.string.warning)
.positiveText(R.string.button_ok)
.show();
}
}
});
}
};
}
Here is the button I want to start and stop the service:
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Safeguard is now on!", Snackbar.LENGTH_LONG).show();
//Start service after showing SnackBar
}
});
You can use a Singleton instance which will bind/unbind from your service, this way, the service will not be unbound if your activity is destroyed by Android :
ServiceSingleton.java :
public class ServiceSingleton {
private String TAG = ServiceSingleton.class.getSimpleName();
private static ServiceSingleton mInstance;
private Context mContext;
private boolean mBound = false;
private SafeService mService;
private ServiceConnection mServiceConnection = null;
public static ServiceSingleton getInstance(Context context) {
if (mInstance == null)
mInstance = new ServiceSingleton(context);
return mInstance;
}
private ServiceSingleton(Context context) {
this.mContext = context.getApplicationContext();
}
public boolean startNotification() {
if (!mBound) {
mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
Log.i(TAG, "onServiceConnected");
mService = ((SafeService.LocalBinder) service).getService();
mService.startNotification();
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
Intent intent = new Intent(this, SafeService.class);
mBound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
if (!mBound) {
Log.e(TAG, "Error cant bind to service !");
}
} else {
if (mService != null) {
mService.startNotification();
}
}
return mBound;
}
public void stopNotification() {
if (mBound && mService != null) {
mService.stopNotification();
}
}
public boolean isNotificationStarted() {
if (mBound && mService != null) {
return mService.isNotificationStarted();
}
return false;
}
public void close() {
try {
if (mBound) {
if (mService!=null){
mService.stopNotification();
}
mContext.unbindService(mServiceConnection);
mBound = false;
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
public boolean isBound() {
return mBound;
}
}
In your onCreate()
mSingleton = ServiceSingleton.getInstance();
For your click listener :
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mSingleton.isNotificationStarted()){
mSingleton.startNotification();
}
else {
mSingleton.stopNotification();
}
}
});
stopNotification() wont unbind service if you want to reuse it, if you want to shut it down call close()

Android Callback Error

I want to make a callback function in the ShipInfoManager to inform the MainActivity to do some action.
If I put onEvent() into Runnable, it runs.
However If I put it like this, it shows an error.
Is there any way to fire the callback after loading data?
Or, is there any way to do the callback like Android's API's LocatioManger's requestLocationUpdates, giving a callback when the data/variables is changed?
Thank you for any replies!
MyCallback Interface:
interface MyCallback {
void callbackCall();
}
ShipInfoManager class:
public class ShipInfoManager {
Context mContext;
public ShipInfoManager(Context _mContext) {
this.mContext = _mContext;
reloadData();
startTimer();
}
MyCallback callback;
void onEvent() {
callback.callbackCall();
}
private void startTimer() {
/* RUN EVERY MIN */
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#SuppressWarnings("unchecked")
public void run() {
try {
reloadData();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
};
// TEMP SUSPEND FROM PREVENTING RELOAD //
timer.schedule(doAsynchronousTask, 0, 5000);
}
/* JSON handling and extraction */
private void reloadData() {
//Do sth to reload the data
//After reload, I want to fire the callback
onEvent();
}
}
It looks like you haven't any listeners to your callback and you're not checking for this.
You should replace your ShipInfoManager with this:
public class ShipInfoManager {
public interface MyCallback {
void callbackCall();
}
public void setCustomEventListener(MyCallback eventListener) {
callback = eventListener;
}
Context mContext;
public ShipInfoManager(Context _mContext) {
this.mContext = _mContext;
reloadData();
startTimer();
}
MyCallback callback;
void onEvent() {
// Check if we have listeners
if (callback != null)
callback.callbackCall();
}
private void startTimer() {
/* RUN EVERY MIN */
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#SuppressWarnings("unchecked")
public void run() {
try {
reloadData();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
};
// TEMP SUSPEND FROM PREVENTING RELOAD //
timer.schedule(doAsynchronousTask, 0, 5000);
}
/* JSON handling and extraction */
private void reloadData() {
//Do sth to reload the data
//After reload, I want to fire the callback
onEvent();
}
}
Inside your Activity or Fragment you should have something like:
public class MainActivity extends ActionBarActivity implements ShipInfoManager.MyCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ShipInfoManager s = new ShipInfoManager(this);
s.setCustomEventListener(this);
}
#Override
public void callbackCall() {
}
}
I changed my MainActivity like this. It works now.
Thank you for your suggestion and reply!!!!!
public class MainActivity extends ActionBarActivity {
ShipInfoManager mShipInfo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mShipInfo = new ShipInfoManager(this);
Log.i("Show Ship List Size", String.valueOf(mShipInfo.get_shipsList().size()));
Log.i("Show Ship - 6", String.valueOf(mShipInfo.getShip(6).getShip_name()));
mShipInfo.callback = new ShipInfoManager.MyCallback() {
#Override
public void callbackCall() {
Log.i("Call Back", "it is called");
}
};
}

passing and setting TextView from another class

I have a text view in my android activity, and I want to pass it to a function in another java class and modify its text. But it throws me an exception. I read that I need to run it on a UI thread or send to context variable, but I'm a bit confused and I couldn't manage to do it. That's my code:
Java timer class
public class CountdownTimer {
static int duration;
static Timer timer;
public static void startTimer(final TextView TVtime) {
duration = 10;
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
TVtime.setText(setDuration());
}
}, 1000, 1000);
}
private static String setDuration(){
if(duration == 1)
timer.cancel();
return String.valueOf(--duration);
}
}
Android activity:
TVtime = (TextView) findViewById(R.id.textView_displayTime);
CountdownTimer.startTimer(TVtime);
You cannot update the UI from a non-UI Thread. Pass the activity Context to the startTimer() method.
public static void startTimer(final TextView TVtime,final Context activityContext) {
duration = 10;
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
((Activity) activityContext).runOnUiThread(new Runnable() {
public void run()
{
TVtime.setText(setDuration());
}
});
..........................
.......................
Android activity:
TVtime = (TextView) findViewById(R.id.textView_displayTime);
CountdownTimer.startTimer(TVtime, YourActivity.this);
You can use android.os.Handler for that :
public static void startTimer(final TextView TVtime) {
duration = 10;
final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
TVtime.setText((String) msg.obj);
}
};
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
Message msg = new Message();
msg.obj = setDuration();
handler.sendMessage(msg);
}
}, 1000, 1000);
}

Categories