I have an Android App, which shows a "Splash Screen" for 3 seconds. After that, the MainActivity gets loaded.
Unfortunately the MainActivity takes additional ~4 seconds to load. On first startup even longer. However when the App is loaded, everything runs smooth.
I am using Async-Task for this, but desired result is not obtained and sometimes app crashes. Can someone help me please?
SplashScreen.java
public class SplashScreen extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
new Fetchdata().execute();
}
private class Fetchdata extends AsyncTask {
#Override
protected Void doInBackground(Void... voids) {
Intent intent = new Intent(SplashScreen.this,FetchApiService.class);
startService(intent);
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
return null;
}
#Override
protected void onPostExecute(Void result){
Intent i = new Intent(SplashScreen.this, MainActivity.class);
startActivity(i);
finish();
}
}
#Override
public void onDestroy(){
super.onDestroy();
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Some heavy processing
//starting services
Intent intent = new Intent(this,FetchApiService.class);
startService(intent);
}
}
Related
I am working on Firebase Push Notification and i want to close MainActivity. Application should finish when onMessageReceived() is called. I am also passing the Context but its not working. In this case, I'll send notification when application is opend. My code:
MainActivity.java
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new FirebaseMessagingService(MainActivity.this);
}
}
FirebaseMessagingService.java
public class FirebaseMessagingService extends
com.google.firebase.messaging.FirebaseMessagingService {
Context context;
public FirebaseMessagingService(Context ctx) {
this.context = ctx;
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
context.finish();
}
}
You could define a BroadcastReceiver in MainActivity, that calls finish() when triggered:
private final BroadcastReceiver finishReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
Register/unregister it when appropriate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ...
LocalBroadcastManager.getInstance(getApplicationContext())
.registerReceiver(finishReceiver,
new IntentFilter(FirebaseMessagingService.ACTION_FINISH));
}
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(getApplicationContext())
.unregisterReceiver(finishReceiver);
super.onDestroy();
}
And then you just simply have to send a local broadcast from onMessageReceived():
public static final String ACTION_FINISH = "yourpackagename.ACTION_FINISH";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
LocalBroadcastManager.getInstance(getApplicationContext())
.sendBroadcast(new Intent(ACTION_FINISH));
}
(FirebaseMessagingService is a Context subclass, there is no need to pass another Context instance to it)
In my application i want to close it after 5 seconds using Timer() function.It works when i am in MainActivity but when i go to another activity then the application do not close.Now how to run this Timer() function in background if i switch activity.What to do in this case?
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
finish();
}
}, 5000); // Application will be closed after 5 seconds
You achieve this using broadcast receiver. in your activity which you want to finish you need to create broadcast receiver.
public class TestActivity extends Activity {
public static String intent_filter_finish = "com.test.finish";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
registerReceiver(finishReceiver,
new IntentFilter(intent_filter_finish));
}
#Override
protected void onDestroy() {
unregisterReceiver(finishReceiver);
super.onDestroy();
}
BroadcastReceiver finishReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
}
now in your second activity you need to send broadcast after 5 second e.g.
public class SecondActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
sendBroadcast(new Intent(TestActivity.intent_filter_finish));
}
}, 5000);
}
}
or other possible way is directly use postDelayed() method in your test activity e.g.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
finish();
}
}, 5000);
I have a MainActivity class which has a NotificationsListener (seperate class). When a notification appears, it calls my gethtml class. They both extend Activity but the startActivity in my gethtml class doesn't work... (If I copy and test this code in my MainActivity, it works fine)... Anyone have an idea why it isn't working?
This is the main class:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter();
filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE");
startService(new Intent(MainActivity.this, NLService.class));
Intent intent=new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
startActivity(intent);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
This is the notification listener:
public class NLService extends NotificationListenerService {
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE");
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
new Thread(new Runnable() {
public void run(){
Looper.prepare();
int cangethtml = 1;
try{
if(cangethtml==1){
cangethtml = 0; //only runs once
new html();
}
}finally{Looper.loop();}
};
}).start();
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn) {}
}
This is the final class which doesn't open the website through the startActivity:
public class html extends Activity{
public html() {
try {
Intent i2 = new Intent("android.intent.action.MAIN");
i2.setComponent(ComponentName.unflattenFromString("com.android.chrome/com.android.chrome.Main"));
i2.addCategory("android.intent.category.LAUNCHER");
i2.setData(Uri.parse("https://wwww.google.com"));
startActivity(i2);
} finally{}
}
}
With reference to the developer's forum:
You should write
Context.startActivity(i2);
instead of
startActivity(i2);
Plus, make sure you don't forget to have a corresponding <activity> declaration in your package's AndroidManifest.xml.
For instance:
Check in AndroidManifest.xml for all the classes defined by you. You have:
<activity android:name="packageName.className"/>
If your html class is not defined in AndroidManifest.xml, you can not access the methods and layouts defined in it.
You need the context of the Activity. startActivity will be called in the context of Activity.
In my Activity1, I have an AsyncTask that uploads to the server. Once this task is started, I want to start Activity, without waiting for the completion of AsyncTask. When the AsyncTask from Activity1 is completed, I want to update something in Activity2. After doing some searching, I've found multiple references/examples of using interfaces. But I ran into the following problem:
OnUploadCompleted Interface
public interface OnUploadCompleted {
void on UploadCompleted();
}
Activity2
public class Activity2 extends Activity implements OnUploadCompleted {
// all the usual activity code
#Override
public void onUploadCompleted() {
Toast.makeText(this, "Upload Done", ....
}
}
Activity1
public class Activity1 extends Activity {
// all the usual activity code
private class Upload extends AsyncTask<...> {
OnUploadCompleted listener;
public Upload(OnUploadCompleted listener) {
this.listener = listener;
}
// skipping doInBackground task
#Override
protected void onPostExecute(...) {
super.onPostExecute();
listener.onUploadCompleted();
}
}
void foo (...) {
OnUploadCompleted listener = new Activity2();
Upload upload = new Upload(listener);
upload.execute();
finish();
}
}
The problem I have is in the foo() function. the listener is a new instance of Activity2 class, but Activity2 hasn't been created yet. It will be created by the parent activity of Activity1, after the finish(). So, when the listener is actually called, the activity that it's "connected" to is null. In the onUploadCompleted(), when Toast is called, the "this" is null.
try sending Broadcasts to ACtivity2 from Activity1 when Activity1's AsyncTask completed...
public class MainActivity extends Activity {
public static final String ACTION_TASK_COMPLETED = "com.sample.project.action.ACTION_TASK_COMPLETED";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class DoTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
// please wait. I am doing work
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// yay... work completed...
Intent intent = new Intent(ACTION_TASK_COMPLETED);
LocalBroadcastManager.getInstance(MainActivity.this).sendBroadcast(intent);
}
}
}
public class SecondActivity extends Activity {
private TaskReceiver taskReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter intentFilter = new IntentFilter(MainActivity.ACTION_TASK_COMPLETED);
taskReceiver = new TaskReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(taskReceiver, intentFilter);
}
#Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(taskReceiver);
}
private void onUploadImage() {
// uploading completed...
}
private class TaskReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
onUploadImage();
}
}
}
I have an AsyncTask which shows a ProgressDialog. The AsyncTask is started when the activity is started:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_layout);
new MyTask().execute();
}
// ... other code
private class MyTask extends AsyncTask<Void, Void, Void>{
private ProgressDialog dialog = new ProgressDialog(MyActivity.this);
#Override
protected void onPreExecute() {
dialog.show();
}
#Override
protected Void doInBackground(Void... voids) {
// get data from a server
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
// call to a method in MyActivity which updates the UI.
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
}
This code works perfectly, untill I rotate my screen. Which makes sense, because the context that was used to create the dialog doesn't exist anymore (because the activity is re-created when rotating), and a window leak is caused.
The only solution I could think of isn't a really nice one: create a static instance of the task and dialog, and simply dismiss the dialog when the activity is destroyed, and recreate the dialog in the oncreate method if the task is still running.
So how would I solve something like this without losing functionality (so the dialog must always be shown when the task is running, and rotating the device should be allowed)?
As Raghunandan suggested in his comment, I looked into Fragments and solved my problem.
I created a Fragment which starts my AsyncTask, as explained in the blogpost that Raghunandan provided.
And to make sure that my Dialog didn't get leaked, I created a DialogFragment, as described here (Basic Dialog).
Here's my working code:
My Activity:
public class MyActivity extends Activity implements MyTaskFragment.TaskCallbacks {
private MyTaskFragment task;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_layout);
FragmentManager fm = getFragmentManager();
task = (MyTaskFragment) fm.findFragmentByTag("myTask");
if (task == null) {
task = new MyTaskFragment();
fm.beginTransaction().add(task, "myTask").commit();
}
}
#Override
public void onPreExecute() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("myDialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
StringProgressDialogFragment dialog = StringProgressDialogFragment.newInstance("My message");
dialog.show(ft, "myDialog");
}
#Override
public void onPostExecute() {
StringProgressDialogFragment dialog = (StringProgressDialogFragment) getFragmentManager().findFragmentByTag("myDialog");
if (dialog!=null) {
dialog.dismiss();
}
// update UI
}
// ... other code
}
My Task fragment:
public class MyTaskFragment extends Fragment {
private TaskCallbacks mCallbacks;
private Task mTask;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (TaskCallbacks) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Retain this fragment across configuration changes.
setRetainInstance(true);
// Create and execute the background task.
mTask = new Task();
mTask.execute();
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class Task extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
mCallbacks.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
// do stuff
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
mCallbacks.onPostExecute();
}
}
public static interface TaskCallbacks {
void onPreExecute();
void onPostExecute();
}
}
My Dialog fragment:
public class StringProgressDialogFragment extends DialogFragment {
private String message;
public static StringProgressDialogFragment newInstance(String message) {
StringProgressDialogFragment dialog = new StringProgressDialogFragment();
Bundle args = new Bundle();
args.putString("message", message);
dialog.setArguments(args);
return dialog;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
ProgressDialog dialog = new ProgressDialog(getActivity());
message = getArguments().getString("message");
dialog.setMessage(message);
return dialog;
}
}
New Loaders API can help you (available via support package) - man. They will solve problem with rotation, but not a mem. leak. To solve mem. leaks write your own "AsyncTask" (with a "clearContext" routine) and clear it's context in activity's onDestroy (or onPause, depends on your architecture). It may looks like a bicycle, but the task takes max 1 day, and you will have a full control on all the resources you background worker use.
By the way: consider using dialogs through fragments, because it solves dialog kill on screen rotation.
try with sample. it will work. basically just restrict the oncreate call by handling the config change. this solution may help you.
public class MainActivity extends Activity {
LoadProgrssdata task = new LoadProgrssdata();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, "oncreate called", Toast.LENGTH_SHORT).show();
task.execute();
}
public class LoadProgrssdata extends AsyncTask<Void, Void, Void> {
ProgressDialog progressDialog;
//declare other objects as per your need
#Override
protected void onPreExecute()
{
progressDialog= ProgressDialog.show(MainActivity.this, "Progress Dialog Title Text","Process Description Text", true);
//do initialization of required objects objects here
};
#Override
protected Void doInBackground(Void... params)
{
//do loading operation here
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
progressDialog.dismiss();
};
}
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.e("orientation ", "landscape");
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Log.e("orientation ", "portrait");
}
}
}
and in android manifest file:
<activity
android:name="com.example.MainActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden|screenSize" />
I managed to fix this problem by trying to catch any crash that, may occurs, in doInBackground.