I have a SplashScreen Activity which call Asynctask Class to get information in internet.
I want to wait while my Asynctask is not finish (time during on internet speed connection)
My activity:
public static boolean test = true;
[...]
final Liste en_ce_moment = new Liste("En ce moment au cinéma", nowMovie);
mesListes.add(en_ce_moment);
//call my Asynctask file
fetchNowMovie process = new fetchNowMovie();
process.execute();
while(test)
{
}
Intent i = new Intent(SplashScreenActivity.this, MainActivity.class);
startActivity(i);
My Asynctask:
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
SplashScreenActivity.test = false;
SplashScreenActivity.nowMovie.clear();
SplashScreenActivity.nowMovie.addAll(list);
}
Logically, the boolean became false in onPostExecute so the while loop stop and the intent have to start but the while loop never stop...
Let's do what you want to do in a safe way by using simple interface logic:
So we added our simple interface and we re-define your MyAsnycTask class's constructor like so:
public class MyAsnycTask extends AsyncTask
{
OnTaskFinished listener;
// Our simple interface
public interface OnTaskFinished {
void TimeToNextActivity();
}
// Your MyAsnycTask class constructor
public MyAsnycTask(OnTaskFinished l) {
listener = l;
}
. . .
As a last line of code in onPostExecute(), we're done whatever we're doing. So tell this via our listener:
listener.TimeToNextActivity();
To use our interface that we added earlier, your Activity must implements it. So we implements it. And in implemented method, we go to next Activity with Intent:
public class MyActivity extends Activity
implements MyAsnycTask.OnTaskFinished
{
#Override
public void TimeToNextActivity()
{
// Here go to next activity
Intent i = new Intent(this, MainActivity.class);
startActivity(i);
}
As we modified our MyAsnycTask class's constructor, we must initialize it like this:
MyAsnycTask process = new MyAsnycTask(this);
process.execute();
This looks like a problem hiding inside another problem, but to get through the first-level issue you could try using CountDownLatch instead of a static boolean:
CountDownLatch latch = new CountDownLatch(1);
fetchNowMovie process = new fetchNowMovie(latch);
process.execute();
latch.await();
Intent i = new Intent(SplashScreenActivity.this, MainActivity.class);
startActivity(i);
You'll have to accept the latch as part of your AsyncTask's constructor:
private final CountDownLatch latch;
public fetchNowMovie(CountDownLatch latch) {
this.latch = latch;
}
// ...
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
latch.countDown();
SplashScreenActivity.nowMovie.clear();
SplashScreenActivity.nowMovie.addAll(list);
}
Try to use very simple library:
https://github.com/Arasthel/AsyncJobLibrary
Just start your Splash activity:
Intent i = new Intent(context, SplashScreenActivity.class);
startActivity(i);
In "onCreate" method of Splash activity do, what you need in background and after mission complete, do on main thread (update list):
AsyncJob.doInBackground(new AsyncJob.OnBackgroundJob() {
#Override
public void doOnBackground() {
//load from local DB or http-request:
List<Movie> movieList = fetchNowMovie();
//You can convert movieList to Json string, for example and save in SharedPreferences. Or you can use local DB for saving new movies.
// Send the result to the UI thread and show it
AsyncJob.doOnMainThread(new AsyncJob.OnMainThreadJob() {
#Override
public void doInUIThread() {
Intent i = new Intent(splashScreenContext, MainActivity.class);
startActivity(i);
//load movies from shared preferences or local Database in MainActivity (onCreate)
}
});
}
});
Connect library (build.gradle in app-project directory):
dependencies {
...
implementation 'com.arasthel:asyncjob-library:1.0.3'
...
}
Related
I have an Activity with a Recycler view handling cards. I have a SwipeRefreshLayout so when I swipe it updates the RecyclerView with new content. So far, so good.
Howerver, I want to update the RecyclerView every X seconds so if, for instance, I leave the activity with the recylcerview opened and I forgot to swipe it, it would as well update by itself.
To do that, I thought something like this:
( I ommitted necessary code ).
My main Activity which contains the recyclerview schedules a Job like this:
private void scheduleJob() {
ComponentName serviceName = new ComponentName(this, MyJobService.class);
JobInfo jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setRequiresDeviceIdle(false)
.setRequiresCharging(false)
.setPeriodic(3000)
//.setOverrideDeadline(400) // Remove comment for faster testing.
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
int result = scheduler.schedule(jobInfo);
if (result == JobScheduler.RESULT_SUCCESS) {
Toast.makeText(this,"Start", Toast.LENGTH_LONG).show();
} } }
Inside MyJobService I through a Broadcast to my Activity, to let it know it has to update the content of the RecylcerView.
The responsable of receiving the broadcast is an inner class like this:
public static class MyReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
DataSource dataSource = new DataSource(context);
items = dataSource.getItems(); // can't do this due to outter class variable
adapter.refresh(ítems); // can't do this due to outter class variable
Toast.makeText(context,"event",Toast.LENGTH_SHORT).show();
}
}
Problem is on my main Activity I hold two private variable called items (which is the ArrayList ) and adapter ( which is the adapter of the recylcerview) I pass items to the adapter to update the recyclerView content.However, as I am in a static inner class I can’t access outter class variables.
Whats the correct way to do something like this? I think I am messing too much and I guess there must be an easiest and more straight forward way to accomplish what I want.
Thank you very much
Well, turns out I was complicating things too much. It can be done with a simple Handler like this:
// Create the Handler object (on the main thread by default)
Handler handler = new Handler();
// Define the code block to be executed
private Runnable runnableCode = new Runnable() {
#Override
public void run() {
// Do something here on the main thread
Toast.makeText(getApplicationContext(),"Update",Toast.LENGTH_SHORT).show();
ItemsDS itemsDS = new ItempsDS(getApplicationContext());
items = itemsDS.getItems();
adapter.clear();
adapter.addAll(items);
handler.postDelayed(runnableCode, 1000);
}
};
There are Two ways to do this thing:
First is as mentioned by #akshayBhat, you can do it by removing static keyword from BroadcastReceiver class:
ArrayList<String> items;
Adapter adapter;
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
DataSource dataSource = new DataSource(context);
items = dataSource.getItems(); // can't do this due to outter class variable
adapter.refresh(ítems); // can't do this due to outter class variable
Toast.makeText(context, "event", Toast.LENGTH_SHORT).show();
}
}
Second is to pass the reference of current activity state to the BroadCast Receiver and access ClassVariables there using that refernce;
ArrayList<String> items;
Adapter adapter;
public static class MyReceiver extends BroadcastReceiver {
AboutUs mContext;
#Override
public void onReceive(Context context, Intent intent) {
mContext = (AboutUs)context;
DataSource dataSource = new DataSource(context);
mContext.items = dataSource.getItems(); // can't do this due to outter class variable
mContext.adapter.refresh(ítems); // can't do this due to outter class variable
Toast.makeText(context, "event", Toast.LENGTH_SHORT).show();
}
}
Im using a webservice that get a data and stores in a String. I need to use this String but I cant take it. Global variables don't work in Threads. I'm using a traditional Thread new Thread() { public void run() {.
Example of AsyncTask:
public class Task extends AsyncTask<Params, Progress, String> {
// are you know how to use generic types?
protected String doInBackground(Params[] params){
// this code will run in seperate thread
String resultString;
return resultString;
}
protected void onPostExecute(String resultString){
// this code will call on main thread (UI Thread) in this thread you can update UI e.g. textView.setText(resultString);
}
}
Use LocalBroadcastManager to send and receive data.
This way you can avoid memory leak issues.
Here is code for activity
public class YourActivity extends Activity {
private void signal(){
LocalBroadcastManager.getInstance(YourActivity.this).registerReceiver(receiver, new IntentFilter("Your action name"));
Intent yourAction = new Intent(YourActivity.this, YourIntentService.class);
String string = "someData";
yourAction .putExtra("KEY_WITH_URL", string);
startService(yourAction);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String string = intent.getStringExtra("KEY_WITH_ANSWER");
//Do your code
}
};
}
Here code for thread which download String or whatever
public class YourIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
// Download here
Intent complete = new Intent ("Your action name");
complete.putExtra("KEY_WITH_ANSWER", stringToReturn);
LocalBroadcastManager.getInstance(YourIntentService.this).sendBroadcast(complete);
}
}
You can use Thread instead of IntentService.
use a Handler created from the main thread. Then pass your data throuh it
use a weak reference of your activity in your thread; this way you can call directly the main thread - Activity.runOnUiThread(Runnable)
...
Activity activity = activityWeakReference.get();
if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
activity.runOnUiThread(new Runnable() {
#Override
public void run()
{
// you are in main thread, pass your data
}
});
}
You can use Async task:
private class Whatever extends AsyncTask<Void, Void, String> {
protected String doInBackground(Void... void) {
// do your webservice processing
return your_string;
}
protected void onPostExecute(String result) {
// Retrieves the string in the UI thread
}
}
I have a Main activity and after click on button I start thread (but the thread is hidden in library and I have only callback in Main activity.
Now I want to start another activity (call A) where I want to put results from the thread.
Below is simplified code:
public class Main extends Activity {
XManager.ResultsCallback xResultsCallback = new XManager.ResultsCallback() {
// the method is called every 10 sec.
#Override
public void onResult(ArrayList<String> texts) {
}
};
XManager xManager = new xManager(xResultsCallback);
View.OnClickListener onClick = new View.OnClickListener() {
#Override
public void onClick(View arg0) {
XManager.start();
Intent i = new Intent(Main.this, A.class);
startActivity(i);
}
};
}
I want to update the content of A activity each time when onResult() method is called. How to do that?
Use LocalBroadcastManager,
In your Main Activity create function :
private void sendResult() {
Log.d("sender", "Broadcasting message");
Intent intent = new Intent("custom-event-name");
// You can also include some extra data.
intent.putExtra("message", "This is my result!");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
and add BroadcastReceiver in your A Activity
private BroadcastReceiver onResult= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("jazzy","onReceive called");
}
};
add on OnCreate
#Override
public void onCreate(Bundle savedInstanceState) {
// Register to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("custom-event-name"));
}
add onDestroy
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onDestroy();
}
I have a suggestion that you should do as follows:
Start Your Activity A on button click
Inside Activity A declare your XManager instance with a callback present in A itself
Then start your XManager as XManager.start(); that way you would be getting all the callbacks in your desired activity.
Have a great day!
I think if you want to decouple the logic, beside you can use the Android BroadcastReceiver, the another flexible choice is to use the Bus
And you can integrate it with gradle easily
dependencies {
compile 'com.squareup:otto:+'
}
I faced a major problem when I need to call another activity when the button is clicked after the Game is started. The Game is called via initiate(game, ) method from AndroidApplication interface.
In normal Activity, I can easily call the another Activity but it seems to be difficult to call another Activity from Libgdx class that implements AndroidApplication.
Could anyone suggest a proper method to call the Activity from Libgdx class that implements AndroidApplication interface?
I tried to do this for a week but it seems that my method is totally wrong..
Thanks in advance.
Define a callback interface in you LibGdx class, and use it to notify your AndroidLauncher to start the new activity.
For example in your LibGdx game class:
// Your Game class in the core package
public class MyGame extends Game {
// Define an interface for your various callbacks to the android launcher
public interface MyGameCallback {
public void onStartActivityA();
public void onStartActivityB();
public void onStartSomeActivity(int someParameter, String someOtherParameter);
}
// Local variable to hold the callback implementation
private MyGameCallback myGameCallback;
// ** Additional **
// Setter for the callback
public void setMyGameCallback(MyGameCallback callback) {
myGameCallback = callback;
}
#Override
public void create () {
...
}
...
private void someMethod() {
...
// check the calling class has actually implemented MyGameCallback
if (myGameCallback != null) {
// initiate which ever callback method you need.
if (someCondition) {
myGameCallback.onStartActivityA();
} else if (someOtherCondition) {
myGameCallback.onStartActivityB();
} else {
myGameCallback.onStartSomeActivity(someInteger, someString);
}
} else {
Log.e("MyGame", "To use this class you must implement MyGameCallback!")
}
}
}
Then ensure your AndroidLauncher implements the required interface:
// Your AndroidLauncher
public class AndroidLauncher extends AndroidApplication implements MyGame.MyGameCallback {
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
// create an instance of MyGame, and set the callback
MyGame myGame = new MyGame;
// Since AndroidLauncher implements MyGame.MyGameCallback, we can just pass 'this' to the callback setter.
myGame.setMyGameCallback(this);
initialize(myGame, config);
}
#Override
public void onStartActivityA() {
Intent intent = new Intent(this, ActivityA.class);
startActivity(intent);
}
#Override
public void onStartActivityB(){
Intent intent = new Intent(this, ActivityB.class);
startActivity(intent);
}
#Override
public void onStartSomeActivity(int someParameter, String someOtherParameter){
Intent intent = new Intent(this, ActivityA.class);
// do whatever you want with the supplied parameters.
if (someParameter == 42) {
intent.putExtra(MY_EXTRA, someOtherParameter);
}
startActivity(intent);
}
}
I have an Activity [Activity1] that starts a Runnable called [ProRunnable] and in the run() of ProRunnable i have an instance of a class called [TExecutor] that i call a method on.
That method then starts another Activity [Activity2] for result. The Activity2 starts a Callable with ExecutorService.
TExecutor contains a reference to Activity1. How can i force Activity2 to finish from outside Activity2? I need Activity2 to finish and the Callable to stop running too.
I have tried activity1.finishActivity(1) where "1" is the request code i used to start Activity2 in TExecutor. But it never calls the onDestroy of Activity2. And i do not see that it is trying to finish the Activity2.
After i make the call for the activity to finish, it does not appear to go into onDestroy and the callable continues to run.
Activity2 has no theme, so it basically runs in the background. It is also in a different process. I set all this in the manifest, shown at bottom.
Sounds confusing, i know. If you need more information, let me know.
Thanks
public class Activity1 extends FragmentActivity {
private ProRunnable proRunnable;
private Thread thread;
public onStart() {
this.proRunnable = new ProRunnable(this);
this.thread = new Thread(this.proRunnable);
this.thread.start();
}
ON BUTTON PRESS {
this.finishActivity(Activity2.REQUEST_CODE);
}
protected void onActivityResult(int reqCode, int resCode, Intent data) {
if(reqCode == Activity2.REQUEST_CODE) {
//do stuff
}
}
}
public class ProRunnable implements Runnable {
private TExecutor tExecutor;
private Activity activty1;
public ProRunnable(Activity activity) {
this.activity1 = activity;
}
public void run() {
this.tExecutor = new TExecutor(this.activity1);
this.tExecutor.execute();
}
}
public final class TExecutor {
private final Activity activity1;
private Intent activity2Intent;
public TExecutor(Activity activity) {
this.activity1 = activity;
}
public void execute() {
this.activity2Intent = new Intent(activity1.getBaseContext(), Activity2.class);
this.activity2Intent.startActivityForResult(this.activity2Intent, Activity2.REQUEST_CODE);
}
}
public class Activity2 extends Activity {
public static final int REQUEST_CODE = 1;
private ExecutorService executor;
protected void onStart() {
Intent returnIntent = new Intent();
InsertThread insert = new InserterThread();
this.executor = Executors.newSingleThreadExecutor();
Future<Boolean> submit = this.executor.submit(inserter);
try {
submit.get();
} catch ... {
}
}
private class InserterThread implements Callable<Boolean> {
public InserterThread() {
}
public Boolean call() throws ... {
while(!Thread.currentThread().isInterrupted()) {
for(...) {
if(Thread.currentThread().isInterrupted()) {
break;
}
}
}
}
protected void onDestroy() {
super.onDestroy();
Log.e(TAG, "DESTROYING THE ACTIVITY");
this.executor.shutdownNow();
}
}
}
<manifest...>
<application android:process="package.path.p1">
<activity android:name="package.path.Activity1"/>
<activity android:name="package.path.Activity2" android:process="package.path.p2" android:theme="#android:style/Theme.NoDisplay"/>
</application>
</manifest>
Try the other functions in the shutdown Life Cycle of Activity2 after TExecutor calls activity1.finishActivity(1). I suspect that Activity2 is actually receiving onPause() or onStop(), just not onDestroy(), which is only invoked by system whim based on resources availability.
We actually moved them into separate apps completely. And changed the structure quite a bit.