I'm creating AsyncTask class in Activity class. I need to get the Context in AsyncTask to build AlertDialog. I'm using constructor to point the context. My code:
public class Plan extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.plan);
//// some Activity code....
class fillSpiners extends AsyncTask<String, Void, String>{
private Context context;
public fillSpiners(Context context){
this.context = context;
}
#Override
protected String doInBackground(String... params) {
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert
.setTitle("Title");
/// setting up alert
AlertDialog showAlert = alert.create();
showAlert.show();
String s;
///making s String stuff...
return s;
}
} /// end of the AsyncTask class
/// now calling the fillSpiners method.
try {
String a = new fillSpiners(this).execute().get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I've read about using constructor to give context to the alert dialog, but this code stops the app(crash). I think the context is problem here.
Because you are not passing context, context in your case is null. First create constructior for your async task inside of him. Wrote on fast.
fillSpiners(Context context)
{
this.context = context;
}
Second run it:
new fullSpiners(Plan.this).execute(params);
Something like that;
OK. I know what is going on. I found this on stack overflow:
The problem is 'You can show AlertDialogs from Activity only'. This is not an issue of context.
Related
My initial issue is being able to click a "PASTE" bubble that pops up when the a click is being held on a text field. Currently I have not found a way to get that action to happen using uiautomator script/code. So I started looking at directly accessing the clipboard. Now I am having issues accessing the clipboard on the android device. We are not using an app (apk), but are pushing a jar to the device and then using adb runtest to run the classes. So no activities are being started. I am guessing that is were all my issues are coming from. I have created a class file that I call trying to access the clipboard. But am currently getting this error message "java.lang.IllegalStateException: System services not available to Activities before onCreate()". I am new to android and uiautomator. Where/how do I add onCreate() to this code. I know the process we are using is odd at best. Any help at either getting the "PASTE" bubble clicked using uiautomator or getting the class to work would be appreciated.
I tried the onCreate() in a few areas, as you can see, but no luck so far.
Here is my class so far:
import android.app.Activity;
import android.content.*;
import android.os.AsyncTask;
public class MyClipBoard extends Activity {
public String clip;
MyClipBoard() {
super.onCreate(null);
}
public void getClipBoard(){
new GetClipBoard().execute();
}
private class GetClipBoard extends AsyncTask<Void, Void, String> {
private String pMyClip;
#Override
protected String doInBackground(Void...params) {
try {
onCreate(null);
// ClipboardManager p = params[0];
String pasteData = "";
ClipboardManager myClipBoard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData.Item myClip = myClipBoard.getPrimaryClip().getItemAt(0);
CreateDeviceInfoFile.createInfoFile("Data from ClipBoard:", myClip.toString());
CreateDeviceInfoFile.createInfoFile("Number of Items:", String.valueOf(myClipBoard.getPrimaryClip().getItemCount()));
pMyClip = myClip.toString();
}catch (Exception e){
CreateDeviceInfoFile.createInfoFile("ERROR",e.toString());
}
// Gets the clipboard as text.
return pMyClip;
}
#Override
protected void onPostExecute(String result) {
clip = result;
CreateDeviceInfoFile.createInfoFile("Data from PostExecute:", result);
}
}
}
---------Edited added class-------------------
public class MiApp extends Application {
public MiClipBoard newBoard;
private static Context appContext;
MiApp(){
this.onCreate();
Looper.prepare();
newBoard = new MiClipBoard();
}
public MiClipBoard appClipBoard(){
return newBoard;
}
#Override
public void onCreate(){
super.onCreate();
}
public static Context getContext(){
return appContext.getApplicationContext();
}
}
public class MiClipBoard extends Activity {
private ClipboardManager clipboard;
MiClipBoard(){
Context context = MiApp.getContext();
clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
}
public void writeToClipBoard(String clipText){
try {
ClipData clip = ClipData.newPlainText("simple text", "Hello, World!");
clipboard.setPrimaryClip(clip);
CreateDeviceInfoFile.createInfoFile("Writing to ClipBoard", "Hello World");
} catch (Exception e){
CreateDeviceInfoFile.createInfoFile("Write Error", e.toString());
}
}
public void readClipBoard(){
String pasteData = "";
try {
ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);
pasteData = item.getText().toString();
CreateDeviceInfoFile.createInfoFile("From ClipBoard", pasteData);
} catch (Exception e){
CreateDeviceInfoFile.createInfoFile("Read Error", e.toString());
}
}
}
Android system only allow us to activate one Activity at a time, and the others are in onPause() state. Starting an activity should have a layout.xml, and must call startActivity(Intent).
From the logcat:
"java.lang.IllegalStateException: System services not available to Activities before onCreate()".
We can know that getSystemService() only available after super.onCreate(Bundle), which triggers the activity to be created.
A good practice to call getSystemService() in non-activity class is by passing Context parameter to GetClipBoard's constructor and make it as public:
public class GetClipBoard extends AsyncTask<Void, Void, String> {
private Context context;
public GetClipBoard(Context context){
this.context = context;
}
private String pMyClip;
#Override
protected String doInBackground(Void...params) {
try {
// ClipboardManager p = params[0];
String pasteData = "";
ClipboardManager myClipBoard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
...
}catch (Exception e){
...
}
// Gets the clipboard as text.
return pMyClip;
}
...
}
So once you executing AsyncTask, call the class from Android components that has Context, e.g. Activity, Service, BroadcastReceiver, etc.
new GetClipBoard(this).execute(); // 'this' > context
I believe that is my issue, currently I don't think I have a component that has Context. This is the class I am making the call from (part of it) and the first class that is being called by adb runtest.
public class SetupApp extends UiAutomatorTestCase {
public void testAppSetup() throws UiObjectNotFoundException, RemoteException
{
//other code here
MyClipBoard myBoard = new MyClipBoard();
myBoard.getClipBoard();
I had a simple program where i need to update the list and text based on the server response ...
But Asynctask onpostexecute is not updating views if the screen is rotated while doinbackground is executed .
I came to know the reason that , as the activity is recreated , onpostexecute wont update its views (Same problem..here is the link : Chek this link)
But i was not satisfied with the answer as it just suggesting to restricting to recreate the activity (i want recreating the activity as in my project i had some extra layout in landscape mode).
Please dont suggest setretaininstance(true) by taking fragments as it doesnt call oncreateview(), which is not suitable for my project.
May be as lastoption i can restrict orientation programatically in onpreexecute and release it in onpostexecute. But still it will not be good practice i think.
public class MainActivity extends ActionBarActivity {
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView=(TextView) findViewById(R.id.textview);
if(savedInstanceState==null)
{
new myAsync().execute();
}
}
public class myAsync extends AsyncTask<Void, String, Void>
{
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
textView.setText("started");
Log.e("started", "started");
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#SuppressWarnings("deprecation")
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
Log.e("executed", "executed");
}
}
}
This is my sample program . textview is not updating if screen is rotated.
Please suggest . Thanks in advance .
You could provide myAsyncTask with a TextView member with a setter and store the current task as static member of the activity.
class MyActivity extends Activity {
private static AsyncTask myTask = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.textview);
if (myTask == null) {
new myAsync(textView).execute();
} else if(myTask.getStatus() != AsyncTask.Status.FINISHED) {
myTask.set(textView);
}
}
private class myAsync extends AsyncTask<Void, String, Void>
{
TextView textView;
myAsync(TextView textView) {
this.textView = textView;
}
synchronized void setTextView(TextView textView) {
this.textView = textView;
}
...
}
}
You would still have to deal with race conditions. E.g. you would probably want to impelemnt a mechanism to pause/resume your task, whenever the activity pauses/resumes.
You'd also have to make sure that the tasks textView is still valid and that you cleanup your static task in onPostExecute.
You can use the concept of bundle to put some string in it. When the activity is recreated after rotation check if saved instance state is null or not in the oncreate method. If not null retrieve the string using the bundle and update the textview. For more information on this rotation thing check out the videos of slidenerd on YouTube in the asynctask and threads playlist. Hope it helps.
So I'm just trying to create an Alert Dialog that is just a message (no buttons or titles). I want to display an alert dialog when a background task is running. The alert dialog will run on the UI thread.
Here's what I have done so far:
protected void onPreExecute() {
super.onPreExecute();
AlertDialog altDlg;
altDlg = new AlertDialog.Builder(AlertDialogActivity.this).create();
altDlg.setMessage("Retrieving Information. Please Wait");
altDlg.show();
}
I also tried doing this:
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setMessage("Retrieve Info. Please Wait").show();
The error I am getting with the first one is:
cannot find symbol 'AlertDialogActivity'
symbol: class AlertDialogActivity
location: class com.example.Device.Activity
The second attempt error says:
incompatible types: com.example.Device.Activity cannot be converted to android.content.Context
I'm not sure what I am doing wrong in either scenario. I just want to display a basic message when a background task is running and I was hoping the closest thing I can use is AlertDialog.
EDIT for how to set up AsyncTask properly:
Small background of what I want to do. I just want to read in a file, deserialize it and save it's contents to a db.
Right now I'm assuming I only need two activities.
One is my main activity:
public class MainActivity extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.setup);
final Button setup_button = (Button) findViewById(R.id.setup_button);
setup_button.setOnClickListener (new View.OnClickListener() {
public void onClick(View view){
setContentView(R.layout.retrieve_info);
}
});
}
}
Now the onClick event just moves to the new view that is supposed to display the message or alert dialog that says retrieving information. Please Wait. It displays the message while reading a file and saving to db. Once the file is read and saved, The message should disappear and say something like setup complete.
My second activity so far is:
public class RetrieveInfoActivity extends AsyncTask<Void,Void,Void> {
private ProgressDialog progressBar;
private void retrieveInfo(String fileName) {
try {
File file = new File(fileName);
Scanner scanner = new Scanner(file);
//Read all the lines until there are no more lines
while (scanner.hasNextLine()) {
scanner.nextLine();
//TODO: deserialize and save to db
}
scanner.close();
}
catch (FileNotFoundException e) { e.printStackTrace(); }
}
#Override
protected Void doInBackground(Void... params) {
retrieveInfo("test.txt");
return null;
}
protected void onPreExecute() {
super.onPreExecute();
progressBar.setIndeterminate(true);
progressBar.setCancelable(false);
progressBar.setMessage("Retrieve Information.Please wait");
progressBar.show();
}
#Override
protected void onPostExecute() {
progressBar.dismiss();
}
}
That's all I really have so far. I just need to understand how to set up this in Android conceptually.
Hope this makes sense.
Try this:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
Instead of using an AlertDialog use a ProgressBar, it will do the trick for you.
private ProgressDialog progressBar;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setIndeterminate(true);
progressBar.setCancelable(false);
progressBar.setMessage("Your message");
progressBar.show();
}
#Override
protected void onPostExecute(final String error_code) {
progressBar.dismiss();
}
Looks like you are extending AsyncTask and trying to use it as a context. That won't work as AsyncTask itself is nothing but an abstract class.
You need to create a custom constructor for your AsyncTask to fetch the Context:
public class MyTask extends AsyncTask<Void, Void, Void> {
private Context mCtx;
public MyTask(Context context) {
mCtx = context;
}
...
Then when starting your AsyncTask, pass the context:
new MyTask(this).execute();
Another way would be to make the AsyncTask an inner class and use YourActivity.this when creating the dialog. Example:
public class YourActivity extends Activity {
...
private class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
AlertDialog dialog = new AlertDialog.Builder(YourActivity.this).create();
}
#Override
protected Void doInBackground(Void... params) {
...
}
}
}
after been searching stackoverflow to see if there was a question to this, there none that helped me on this.
On my main activity I have this:
if (GlobalVars.espera == 0)
{
GlobalVars.espera = 1;
try
{
bgIntent = new Intent(this, Loadscreen.class);
startService(bgIntent);
}
catch (Exception e)
{
GlobalFunctions.toast_message(context, "nao");
}
}
When i start the application it should load the intend to work on background but it isn't.
Here is the class of loadscreen:
public class Loadscreen extends IntentService{
MainActivity teste;
private static final String intService = "loadscreen";
public Loadscreen()
{
super(intService);
// TODO Auto-generated constructor stub
}
#Override
protected void onHandleIntent(Intent intent)
{
teste = new MainActivity ();
try
{
teste.inic();
}
catch (Exception e)
{
}
}
}
and manifest I have put
<service android:name=".Loadscreen"></service>
on it too, as a child of application
Even that I have the try, it doesn't go into the catch AKA error, but still doesn't go into the class Loadscreen.
Thanks for the help and time
You have
teste = new MainActivity (); // assuming MainActivity is a Activity class
You are instantiating Activity class which is wrong.
I would like to enable a few buttons from my main activity once the stuffs from doInBackground() is finished! Can someone please let me know how to do that?
I can't use findViewByID() for making he button visible from the AsyncTask class as it's not an activity class! :/
Do Like this...
Define a method which enables the Buttons.
Then on PostExecute() on AsyncTask, call that method
there is one callback onPostExecution(...) { } of AsynTask class use this method to UI stuff,for enable,disable button just write this way in onPostExcustion(...)
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
}
});
also make sure this method only available in activity class
thank you
Follow this way:
[1] Create your AsyncTask :
public class performBackgroundTask extends AsyncTask<Void, Void, Void> {
ProgressDialog Dialog = new ProgressDialog(HotUsers.this);
protected void onPreExecute() {
Dialog.setMessage("Loading Hot Users...");
Dialog.show();
}
protected void onPostExecute(Void unused) {
if(Dialog.isShowing())
Dialog.dismiss();
set_details_on_screen();
}
#Override
protected Void doInBackground(Void... params) {
get_details_from_server(); // get data like userid,username,userdesc etc...
return null;
}
}
[2] That will call function to proceed for UI changes.
public void set_details_on_screen()
{
if(userid > 0 )
handler_default.sendEmptyMessage(0);
else
handler_default.sendEmptyMessage(1);
}
[3] At last your UI changes will be reflected on screen with this Handler.
private Handler handler_default = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 0: {
textuserid = (TextView) findViewById(R.id.userid);
textusername = (TextView) findViewById(R.id.username);
textuserdesc = (TextView) findViewById(R.id.userdesc);
textuserid.setText(userid);
textusername.setText(username);
textuserdesc.setText(userdesc);
break;
}
case 1: {
Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show();
break;
}
}
}
};
Thanks.
your class which extends AsyncTask you can push your context into it, when calling the execute().
private class RegisterUser extends AsyncTask<String,String,String> {
private ListActivity activity;
public RegisterUser(ListActivity activity) {
this.activity = activity;
}
protected void onPostExecute(JSONObject json) {
activity.editText = (EditText)activity.findViewById(R.id.editText1);
//or
activity.enableButton();
}
}
and call the execute from the Activity like this:
new RegisterUser(this).execute(new String[] {"param"});
or you can define the AsyncTask class inside your Activity class - where you can reach everything.
more info Lars Vogel - Android Threads, Handlers and AsyncTask