Android - Starting a thread from a widget View class - android

So I have a View:
public class RadialMenuWidget extends View
from where I want to start a thread like I do from an activity
String urlInput = "http://myserver.com/"+mynewfile;
DownloaderThread downloaderThread = new DownloaderThread(UpdateActivity, urlInput);
downloaderThread.start();
but I get the message "Expression expected" on this line "DownloaderThread(UpdateActivity,... " more specifically on the activity name (UpdateActivity) even though I imported the activity inside the Widget.
What can I do to avoid this while still being able to call the thread.
The idea is, I use the RadialMenuWidget, and inside the RadialMenuWidget class I test to see which menu button was pressed and based on that, I decide what to do next. Calling other intents works just fine, but now I want to start to download a file using a separate thread (that I can call from a regular activity's onButtonClick)
EDIT
So my radialMenu has this structure:
public class RadialMenuWidget extends View {
...
public interface RadialMenuEntry {
...
}
public RadialMenuWidget(Context context) {
...
}
#Override
public boolean onTouchEvent(MotionEvent e) {
...
if (state == MotionEvent.ACTION_UP) {
...
if (menuEntries.get(i).getName() == "Update now") {
String urlInput = "http://myhost.com/"+mynewfile;
DownloaderThread downloaderThread = new DownloaderThread(this.UpdateActivity, urlInput);
downloaderThread.start();
}
}
...
And the DownloadThread class looks like this:
public class DownloaderThread extends Thread {
public DownloaderThread(UpdateActivity inParentActivity, String inUrl)
{
downloadUrl = "";
if(inUrl != null)
{
downloadUrl = inUrl;
}
parentActivity = inParentActivity;
}
#Override
public void run()
{
// does the download
}
...
}
Please help.
Thank you

My solution in the end was to mimic a 2 button radial menu using images. I used the images as backgrounds for a button, placed them in a linear layout, used 9-patch images and got to call the thread onClick like before. So I avoided having to deal with radialMenuWidget in this view.
So question is over now.
I was hoping for a java solution to this problem since I am a newbie and eager to learn anything Android, but this is it, I will manage with my (ugly) solution.

Related

Generic asyncTask with callback (for web services)

I've already developed many Android apps that make web service requests, always with the following approach:
In every activity that need to make a web service request, I define an inner AsyncTask that shows a ProgressDialog in onPreExecute(), makes the web service call in doInBackground, and dismisses the progressDialog and updates the results in the UI from onPostExecute().
My concern is: Is there a better (shorter) way to do it? Does it make sense to repeat all that code in every activity? I've been googling a lot, but I've found nothing.
My question is: Couldn't I define a Callback interface? for example this one:
public interface RequestCallback {
public void onSuccess(Whatever whatever);
public void onError(ErrorCode errorCode, String message);
}
... and then define an external class, for example AsyncRequest, that wraps the AsyncTask definition and the ProgressDialog show() and dismiss() statements. So, all activities would just need to instantiate that class, and pass in the following parameters:
1) The method of the web service to run
2) A Bundle with all the parameters of that method of the web service
3) A RequestCallback instance (that could be an anonymous inline instance, where I could update the UI from onSuccess())
4) The context of the Activity (necessary to show the ProgressDialog(), so I would still need a way to prevent configuration change exceptions and so...),
Do you find this a good design? It could save hundreds of lines of code...
Your approach is what I did on my project. And it saved a lot of code as you said, I don't have any complaint about it. But here is some issues that I want to tell you:
You should create new instance of AsyncTask every time you do a background thread to avoid to pile callback.
For the progress dialog, I use it as Singleton, because you don't show many dialogs at the same time. The dialog will be showed when you call the background job, and will be dismiss in the callback. Here is what I did:
private void showProgressDialog(String strMess){
if(null == progressDialog){
progressDialog = new ProgressDialog(MainActivity.this);
}
if(!progressDialog.isShowing()){
progressDialog.setMessage(strMess);
progressDialog.show();
}
}
private void hideProgressDialog(){
if(null != progressDialog && progressDialog.isShowing()){
progressDialog.dismiss();
}
}
void someMethod(){
showProgressDialog("Loading...");
doBackgroundJob(param, new RequestCallBack() {
public void onRequestCompleted(String message, boolean isSuccess) {
hideProgressDialog();
if(isSuccess){
}else{
//do something on error
}
}
});
}
It is an optional, I defined an interface to notify instead of specific class, for each response I use one class, so in base class, I don't care what the response is. Here is it:
public interface OnRequestCompleted<TResponse> {
void requestCompleted(TResponse response);
}
public abstract class BaseRequest<TResponse> implements IRequest{
protected OnRequestCompleted<TResponse> delegate;
protected Class<TResponse> responseClass;
#Override
public void send() {
new HttpTask().execute();
}
private class HttpTask extends AsyncTask<Void, Void, String> {
//...
#Override
protected void onPostExecute(String result) {
if (null != response && null != delegate) {
delegate.requestCompleted(response);
}
}
}
// the response example
public class GroupResponse {
public static class Clip {
public int clipId;
public String detail;
}
public static class Movie {
public int movieId;
public String detail;
}
}
In the subclass of BaseRequest, I will tell it exactly what the response class is (Movie, Clip...)
Hope this help.
If you use it already and it works for you, then yes it makes sense to make it generic and save the time (and bugs) of reimplementing the same thing dozens of times. If you ever find yourself copy-pasting large sections of code with few to no differences you should turn it into a library function or class of some sort. Otherwise if you find a problem later you'll have to fix it in a dozen places. It doesn't even matter if you think of a better way to do things later- its still easier to change it in one place than a dozen.
The only real issue I'd have with your solution is I wouldn't add the progress bar to it- I'd handle it in the calling code and the onSuccess/onError implementations. That way you could also reuse it for a background call that doesn't need to put up a UI. I try to keep my UI decisions as far away from data grabbing code as possible, MVC patterns are good.

ListView not updating after async call

I have a weird / unique situation with my ListView. This is the scenario:
I'm making use of the MVP design pattern. As the Activity starts, it raises an event to notify the presenter to fetch some data from a web service. The web service call is an Async call. Once the web service Completed event is raised, I take the result and push it into a property (which is of type Array) that resides within my View / Activity.
Everything I mentioned works just fine, but as soon as the device is rotated, some interesting developments take place.
The async call resumes as normal and provides the property (Array) with a value. So nothing wrong there... (And yes there is data in the collection) I then set the ListView Adapter and call the notifyDataSetChanged, but nothing happens. The UI is not updated or anything?? If I re-enter the Activity the data is visible again ??
I even tried calling invalidateViews and invalidate on the ListView - this didn't do anything.
Could someone please assist me in this matter?
Many thanks in advance!
[Update]
I would like to stress the fact that I am making use of C# (Xamarin) and not Java (:sigh: - yes I know). Furthermore, I am not making use of the ASyncTask class, instead I'm making use of the async methods created within the proxy classes generated by Visual Studio. Pretty straight forward, but this is the code that populates the ListView - the property is set from the presenter
Presenter
Where View is of type IContactsView
protected override void OnCollectData(System.Collections.IEnumerable data, Type typeOfData)
{
if (data != null && typeOfData != null && typeOfData.Equals(typeof(UserContact)))
{
this.View.UserInformationCollection = data.Cast<UserContact>().ToArray();
}
}
Activity
The activity implements IContactsView
public UserContact[] UserInformationCollection
{
get
{
return this._userInformationCollection;
}
set
{
this.RunOnUiThread(() =>
{
this._userInformationCollection = value;
ListView listview = this.FindViewById<ListView>(Resource.Id.userLV);
if (listview != null)
{
UserContact[] subsidiesList = this.GetIndexedContacts(this._userInformationCollection);
listview.Adapter = new ContactsAdapter(this, subsidiesList.ToList());
((ContactsAdapter)listview.Adapter).NotifyDataSetChanged();
}
});
}
}
[/Update]
Found a much better solution! So please ignore the static variable idea!
Activity:
Override the OnRetainNonConfigurationInstance and return the presenter
public override Java.Lang.Object OnRetainNonConfigurationInstance()
{
return this._presenter;
}
Within the OnCreate check the LastNonConfigurationInstance and get the presenter - if it isn't null:
protected override void OnCreate(Bundle bundle)
{
...
if (this.LastNonConfigurationInstance != null)
{
this._presenter = this.LastNonConfigurationInstance as ContactsPresenter;
this._presenter.RefreshView(this);
}
else
{
// create a new presenter
this._presenter = new ContactsPresenter(this);
}
...
}
So maybe, you saw what I did in the previous code sample? Yes, I send the new instance of the activity to the presenter - have a look at the RefreshView
Presenter:
So within my base presenter I have the following method:
public class Presenter<T> : Java.Lang.Object, IPresenter where T : IView
{
/// <param name="view">The view.</param>
public void RefreshView(T view)
{
this.View = view;
}
}
The above code helps my presenter say with the creation of new activities - so when it returns data after the async call it will have the latest and greatest instance of the activity!
Hope this helps!
Kind regards,
Got it working by doing the following:
declare a static variable of the activity:
private static ContactsActivity _cachedActivity = null;
Overrode the OnResume within the activity and set the variable:
protected override void OnResume()
{
base.OnResume();
_cachedActivity = this;
}
Override the OnCreate within the activity and set the variable:
protected override void OnCreate(Bundle bundle)
{
...
_cachedActivity = this;
...
}
Lastly I changed the property mentioned earlier:
public USBUserContact[] UserInformationCollection
{
get
{
return this._userInformationCollection;
}
set
{
_cachedActivity.RunOnUiThread(() =>
{
_cachedActivity._userInformationCollection = value;
ListView listview = _cachedActivity.FindViewById<ListView>(Resource.Id.userLV);
if (listview != null)
{
UserContact[] subsidiesList = _cachedActivity.GetIndexedContacts(_cachedActivity._userInformationCollection);
listview.Adapter = new ContactsAdapter(_cachedActivity, subsidiesList.ToList());
((ContactsAdapter)listview.Adapter).NotifyDataSetChanged();
}
});
}
}
Kind regards,

CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views

I'm doing a manipulation in database in an IntentService, and in the Activity im showing a CustomProgressBar, but I want to show also the percentage value. So, for that I get the percentage value in the IntentService and set this value in a static method in the Activity. But the error show up:
CalledFromWrongThreadException: Only the original thread that created
a view hierarchy can touch its views.
I dont want to do this operation in an AsyncTask becaus I don't want to block the UI, so I'm using a IntentService.
Here is how I am doing this.
MyIntentService.java
public class MyIntentService extends IntentService
{
#Override
public void onHandleIntent(Intent intent)
{
updateDatabase();
}
public void updateDatabase()
{
resetPercentage(cursor.getCount * 2)
do
{
// do operation for updating the database
// here I update the view everytime a new item is inserted in DB.
int updatedReturn = MyActivity.updatePercentageValue(percentage());
}
while(...)
}
public void resetPercentage(int elementsNum)
{
mUpdatePercentage = 0;
mMaxItems = elementsNum;
}
public int incrementPercentageCounter()
{
return ++mPercentageCounter;
}
public int percentage()
{
int value = (mPercentageCounter/mMaxItems)*100;
return (value > 100) ? 100 : value;
}
}
MyActivity.java
public class MyActivity extends Activity
{
private TextView mMyTextView;
#Override
public void onCreate(Bundle bundle)
{
super.onCreate(bundle);
mMyTextView = (TextView) findViewById(R.id.textview);
}
public static int updatePercentageValue(int percentageValue)
{
mMyTextView.setText("" + percentageValue + " %");
return 1;
}
}
Any Idea of how can I solve this problem or do this operation using my IntentService so the UI wont be blocked.
Obs: I want to keep using IntentService also because a lot of things is done, and I dont want to change all over again.
Thanks!
An AsyncTask won't block the UI. You should probably use it. The kind of thing you're trying to do is exactly what it's good for. The AsyncTask doesn't need to exist outside of your Activity, it's short-lived work (relatively), and your work needs to update this UI. An AsyncTask seems more appropriate than a Service here.
Doing things in an async task is specifically to not block the UI thread. It even has an on progress method to do exactly what you want to do wih updating the UI. Gven that you don't want to do that, but you need to look into the running method.
Looking at this code I am somewhat confused as to how it works since you are accessing a member variable in a static method.

Android findViewById Null Scope Issue

I am having a few problems with how I've structured my App. I have a click handler in my Core class
that I decided I want to be forwarded to another class to make my code smaller and more modular, the problem is
inside ButtonClass, findViewById always returns NULL, I believe due to being out of scope.
In my XML manifest file I do have: android:name="com.prj.MyAppName"
In my core class things work fine, but once I create a new class I cannot use findViewById() inside of it.
Here is a stripped down version of my code:
public class Class1 extends Core
{
Button buttonHint1 = (Button)findViewById(R.id.buttonHint1);
}
public class Core extends Activity
{
public void myClickHandler(View target)
{
//THIS WORKS
//TextView userText2 = (TextView) findViewById(R.id.textViewHint1);
//userText2.setText( "OKOKOKO" );
ButtonClass myButtonClass = new ButtonClass();
myButtonClass.myClickHandler(target);
}
}
public class ButtonClass extends Core
{
public void myClickHandler(View target)
{
switch( target.getId() )
{
case R.id.buttonHint1:
//CRASHES ON findViewById ()!!!
TextView userText1 = (TextView) findViewById(R.id.textViewHint1);
userText1.setText( "OKOKOKO" );
break;
}
}
}
Does anyone know if there are any modifications I can make to allow ButtonClass to be able to use findViewById and perhaps
fix my scoping issues so my App does not crash?
I am still learning Android and would appreciate any advice.
Why not change the constructor of ButtonClass to allow the parameter (TextView)findViewById(R.id.textViewHint1)?
public ButtonClass(TextView tv){
//constructor stuff
}
If this is called in an Activity it should work.
Edit: My mistake, not TextView, Button!

How can I call a function in my main Activity class from a custom Gallery view in Android?

I have a custom gallery view in which I am overriding some methods. I would like to be able to call a function in my main activity from this class. How do I make a reference back to my main class?
I thought I'd just push the class reference into CustomGallery by creating a setter function ---> g.setBaseClass(this);
CustomGallery g = (CustomGallery) findViewById(R.id.playSelectionGallery);
g.setSpacing(10);
g.setCallbackDuringFling(false);
g.setAdapter(new ImageAdapter(this));
g.setSelection(1);
registerForContextMenu(g);
g.setBaseClass(this);
Problem is this is of type Context and someFunctionToCall() will result in a not a member of this class error. In my custom class I have:
public void setBaseClass(Context baseClass)
{
_baseClass = baseClass;
}
private void callSomeFuntionOnMyMainActivityClass()
{
_baseClass.someFunctionToCall();
}
All I want to do is call back to my main class, called ViewFlipperDemo. This would be easy in As3. Any thoughts? Hopefully I'm missing something really simple.
That's actually not a good idea... but you can do it this way:
private void callSomeFuntionOnMyMainActivityClass()
{
((ViewFlipperDemo)_baseClass).someFunctionToCall();
}
What you should do instead is implementing a simple observer which allows you to notify the Activity that something happened. That's one of the main OO principles, your custom class shouldn't know anything about your activity class.
Observer pattern example
The Observer interface:
// TheObserver.java
public interface TheObserver{
void callback();
}
Your custom view:
public class CustomGallery{
private TheObserver mObserver;
// the rest of your class
// this is to set the observer
public void setObserver(TheObserver observer){
mObserver = observer;
}
// here be the magic
private void callSomeFuntionOnMyMainActivityClass(){
if( mObserver != null ){
mObserver.callback();
}
}
// actually, callSomeFuntionOnMyMainActivityClass
// is not a good name... but it will work for the example
}
This is the activity that will benefit of the observer (notice that now you can use your custom view on different activities not just one, that's one of the key reasons to implement it this way):
public class YourActivity extends Activity{
// your normal stuff bla blah
public void someMethod(){
CustomGallery g=(CustomGallery)findViewById(R.id.playSelectionGallery);
g.setObserver(new TheObserver(){
public void callback(){
// here you call something inside your activity, for instance
methodOnYourActivity();
}
});
}
}
You will notice that this design pattern (observer) is widely used in Java and Android... almost any kind of UI event is implemented using observers (OnClickListener, OnKeyListener, etc.). By the way, I didn't test the code, but it should work.

Categories

Resources