How do I combine this two application class for Android Studio? - java

I have two application class which I want to combine in one, but provides two function, but I want it only one class so that I can call it on the application class in my manifest and get the App to produce both functions since i can not have two classes called on the application class in my manifest file in android studo.
I would like to put the AppController class in the App.Java class
Where I am confused is how to combine it since both extends different classes which java does not permit extending two classes in one.
Below is the App.java class
public class App extends MultiDexApplication implements Constants {
public static final String TAG = App.class.getSimpleName();
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static App mInstance;
private ArrayList<Feeling> feelingsList;
private ArrayList<BaseGift> giftsList;
private SharedPreferences sharedPref;
private String username, fullname, accessToken, gcmToken = "", fb_id = "", photoUrl, coverUrl, area = "", country = "", city = "";
private Double lat = 0.000000, lng = 0.000000;
private long id;
private int state, allowRewardedAds = 1, admob = 1, ghost, pro, verify, balance, allowShowMyInfo, allowShowMyFriends, allowShowMyGallery, allowShowMyGifts, allowGalleryComments, allowComments, allowMessages, allowLikesGCM, allowCommentsGCM, allowFollowersGCM, allowGiftsGCM, allowMessagesGCM, allowCommentReplyGCM, errorCode, currentChatId = 0, notificationsCount = 0, messagesCount = 0, guestsCount = 0, newFriendsCount = 0;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
FirebaseApp.initializeApp(this);
sharedPref = this.getSharedPreferences(getString(R.string.settings_file), Context.MODE_PRIVATE);
this.readData();
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
try {
ProviderInstaller.installIfNeeded(this);
} catch (Exception e) {
e.getMessage();
}
}
}
// NB; I have some more codes in here which i am unable to put in full here.
}
}
Then this this the second class AppController.java
public class AppController extends Application {
private static Context mContext;
private static String mAppUrl;
public static MediaPlayer player;
public static Activity currentActivity;
#Override
public void onCreate() {
super.onCreate();
setContext(getApplicationContext());
mAppUrl = Constant.PLAYSTORE_URL + mContext.getPackageName();
setTelephoneListener();
player = new MediaPlayer();
mediaPlayerInitializer();
//AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
public static void mediaPlayerInitializer(){
try {
player = MediaPlayer.create(getAppContext(), R.raw.snd_bg);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setLooping(true);
player.setVolume(1f, 1f);
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
public static String getAppUrl() {
return mAppUrl;
}
private static void setContext(Context context) {
mContext = context;
}
public static Context getAppContext() {
return mContext;
}
public static void playSound()
{
try {
if (SettingsPreferences.getMusicEnableDisable(mContext)&&!player.isPlaying()) {
player.start();
}else{
}
} catch (IllegalStateException e) {
e.printStackTrace();
mediaPlayerInitializer();
player.start();
}
}
public static void StopSound() {
if (player.isPlaying()) {
player.pause();
}
}
private void setTelephoneListener() {
PhoneStateListener phoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_RINGING) {
StopSound();
} else if (state == TelephonyManager.CALL_STATE_IDLE) {
} else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
StopSound();
}
super.onCallStateChanged(state, incomingNumber);
}
};
TelephonyManager telephoneManager = (TelephonyManager) getAppContext().getSystemService(Context.TELEPHONY_SERVICE);
if (telephoneManager != null) {
telephoneManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
static
{
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
}

Just Extend Your "AppController" class to "App" class. No need to do extra other work.
Like Below.
public class AppController extends App {
......
}

MulitdexApplication extends Application.
You could change your AppController to:
public class AppController extends MulitdexApplication
and then your App to
public class App extends AppController implements Constants

Related

Using Dagger 2 in SyncAdapter class

I am using Sync Adapter along with Dagger 2 for dependency injection. I am stuck since I cannot seem to figure out where should I use XYZ.inject since SyncAdapter class does not provide OnCreate or an Activity to stick to. Can someone suggest how to deal with Dependency injection in case of Sync Adapter alike classes which do not belong to activity/fragment?
PS: I have looked at several similar questions but failed to find a solution to my problem.
SyncAdapter.java
public class SyncAdapter extends AbstractThreadedSyncAdapter {
ContentResolver mContentResolver;
//Injects here
#Inject
SyncCenterPresenter mSyncCenterPresenter;
private final AccountManager mAccountManager;
Context context;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
mContentResolver = context.getContentResolver();
mAccountManager = AccountManager.get(context);
this.context=context;
}
Account mainAccount;
public static final int SYNC_INTERVAL = 60 * 1;
public static final int SYNC_FLEXTIME = SYNC_INTERVAL/3;
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.v("Sync class me","sync adapter on perform sync");
if (mSyncCenterPresenter == null){
Log.v("messsage","null");
} else {
Log.v("messsage","not null");
mSyncCenterPresenter.loadDatabaseCenterPayload();
mSyncCenterPresenter.syncPayload();
}
}
/**
* Helper method to schedule the sync adapter periodic execution
*/
public static void configurePeriodicSync(Context context, int syncInterval, int flexTime) {
Account account = myAccount;
String authority = "com.mifos.provider";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// we can enable inexact timers in our periodic sync
SyncRequest request = new SyncRequest.Builder().
syncPeriodic(syncInterval, flexTime).
setSyncAdapter(account, authority).
setExtras(new Bundle()).build();
ContentResolver.requestSync(request);
} else {
ContentResolver.addPeriodicSync(account,
authority, new Bundle(), syncInterval);
}
}
static Account myAccount;
public static void onAccountCreated(Account newAccount, Context context) {
/*
* Since we've created an account
*/
myAccount = newAccount;
SyncAdapter.configurePeriodicSync(context, SYNC_INTERVAL, SYNC_FLEXTIME);
/*
* Without calling setSyncAutomatically, our periodic sync will not be enabled.
*/
ContentResolver.setSyncAutomatically(newAccount, "com.mifos.provider", true);
/*
* Finally, let's do a sync to get things started
*/
syncImmediately(context);
}
public static Account getSyncAccount(Context context) {
// Create the account type and default account
Account newAccount = new Account(
context.getString(R.string.app_name), "com.mifos");
return newAccount;
}
/**
* Helper method to have the sync adapter sync immediately
* #param context The context used to access the account service
*/
public static void syncImmediately(Context context) {
Bundle bundle = new Bundle();
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
ContentResolver.requestSync(getSyncAccount(context),
"com.mifos.provider", bundle);
}
}
SyncCenterPresenter.java
public class SyncCenterPresenter {
private final DataManagerCenter mDataManagerCenter;
private CompositeSubscription mSubscriptions;
List<CenterPayload> centerPayloads;
int mCenterSyncIndex = 0;
#Inject
public SyncCenterPresenter(DataManagerCenter dataManagerCenter) {
Log.v("messsage","const me");
mDataManagerCenter = dataManagerCenter;
mSubscriptions = new CompositeSubscription();
centerPayloads = new ArrayList<>();
}
public void loadDatabaseCenterPayload() {
Log.v("messsage","load me");
mSubscriptions.add(mDataManagerCenter.getAllDatabaseCenterPayload()
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<List<CenterPayload>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<CenterPayload> centerPayloads) {
showCenters(centerPayloads);
}
}));
}
public void syncCenterPayload(CenterPayload centerPayload) {
mSubscriptions.add(mDataManagerCenter.createCenter(centerPayload)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<SaveResponse>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(SaveResponse center) {
showCenterSyncResponse();
}
}));
}
public void deleteAndUpdateCenterPayload(int id) {
mSubscriptions.add(mDataManagerCenter.deleteAndUpdateCenterPayloads(id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<List<CenterPayload>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(List<CenterPayload> centerPayloads) {
showPayloadDeletedAndUpdatePayloads(centerPayloads);
}
}));
}
public void showCenters(List<CenterPayload> centerPayload) {
centerPayloads = centerPayload;
}
public void showCenterSyncResponse() {
deleteAndUpdateCenterPayload(centerPayloads
.get(mCenterSyncIndex).getId());
}
public void showPayloadDeletedAndUpdatePayloads(List<CenterPayload> centers) {
mCenterSyncIndex = 0;
this.centerPayloads = centers;
}
public void syncPayload() {
for (int i = 0; i < centerPayloads.size(); ++i) {
if (centerPayloads.get(i).getErrorMessage() == null) {
syncCenterPayload(centerPayloads.get(i));
mCenterSyncIndex = i;
break;
} else {
Log.v("messsage","else block");
}
}
}
}
ActivityComponent
#PerActivity
#Component(dependencies = ApplicationComponent.class, modules =
ActivityModule.class)
public interface ActivityComponent {
void inject(LoginActivity loginActivity);
void inject(PassCodeActivity passCodeActivity);
//other methods
void inject(SyncAdapter syncAdapter);
}
ActivityModule
#Module
public class ActivityModule {
private Activity mActivity;
public ActivityModule(Activity activity) {
mActivity = activity;
}
#Provides
Activity provideActivity() {
return mActivity;
}
#Provides
#ActivityContext
Context providesContext() {
return mActivity;
}
}
EDIT
SyncService.java
public class SyncService extends Service {
private static final Object sSyncAdapterLock = new Object();
private static SyncAdapter sSyncAdapter = null;
#Override
public void onCreate() {
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return sSyncAdapter.getSyncAdapterBinder();
}
}
Can someone please help me to get this working? since I can't figure out where to use the inject and how to do it without an Activity Component? A different and a better approach would be appreciated as well.
Thanks
You can implement the constructor, so please use constructor injection to initialize your adapter.
public class SyncAdapter extends AbstractThreadedSyncAdapter {
// ...
#Inject
public SyncAdapter(Context context, boolean autoInitialize) { /*...*/ }
}
Then you simply inject the service that returns the SyncAdapter like you would anything else...
public class SyncService extends Service {
#Inject SyncAdapter syncAdapter;
#Override
public void onCreate() {
AndroidInjection.inject(this);
// or
DaggerSyncServiceComponent.create().inject(this);
}
#Override
public IBinder onBind(Intent intent) {
return syncAdapter;
}
}
And that's it.

How to active a Foreground Service using a Mediaplayer Singleton

I am very newer in Android and I have a Mediaplayer Singleton because I am using fragment that show a list, I want that when the Mediaplayer Singleton is playing will active a service, I was trying with runOnUiThread but this only active many times the service.
this is the Singleton in MyMediaSingleton.java
public class MyMediaSingleton {
MediaPlayer player;
private static volatile MyMediaSingleton instance=null;
private MyMediaSingleton(){
}
public static MyMediaSingleton getInstance(){
if(instance==null){
synchronized (MyMediaSingleton.class){
if(instance==null){
instance=new MyMediaSingleton();
}
}
}
return instance;
}
}
Thank you for your patience.
Media Player Singleton Class
public class MyMediaSingleton {
MediaPlayer mp;
private static volatile MyMediaSingleton instance = null;
private MyMediaSingleton () { }
public static MyMediaSingleton getInstance() {
if (instance == null) {
synchronized (MyMediaSingleton .class) {
if (instance == null) {
instance = new MyMediaSingleton ();
}
}
}
return instance;
}
}
Activity class
public class MainActivity extends Activity {
private MyMediaSingleton player = getInstance();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void playSound(View view){
if(player.mp==null)
player.mp = MediaPlayer.create(getApplicationContext(), R.raw.sound);
player.mp.start();
//For playing multiple sound using single MediaPlayer do it as:
if(player.mp ==null)
player.mp = new MediaPlayer();
else
player.mp.reset();
String fileName="android.resource://"+getPackageName()+
"/"+ R.raw.sound;
player.mp.setDataSource(getApplicationContext(),Uri.parse(fileName));
player.mp.prepare();
player.mp.start();
}
}

How to use a MediaPlayer Singleton

I am new to Android developing and am starting with a simple soundboard application. I started developing a soundboard using multiple fragments until I realized that I was using multiple instances of MediaPlayer. This is not good because I want only one sound to play at a time.
I realized that I'd have to use a MediaPlayer Singleton to solve my problem. The only problem is that I can't find many sources or examples of the MediaPlayer Singleton online.
Here's what I originally put into every "onCreateView" in each fragment:
public static class FragmentPage1 extends Fragment {
int selectedSoundId;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_page1, container, false);
final MediaPlayer player = new MediaPlayer();
final Resources res = getResources();
final int[] buttonIds = { R.id.btn1, R.id.btn2, R.id.btn3, R.id.btn4, R.id.btn5, R.id.btn6, R.id.btn7, R.id.btn8, R.id.btn9 };
final int[] soundIds = { R.raw.sound01, R.raw.sound02, R.raw.sound03, R.raw.sound04, R.raw.sound05, R.raw.sound06, R.raw.sound07, R.raw.sound08, R.raw.sound09 };
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i < buttonIds.length; i++) {
if (v.getId() == buttonIds[i]) {
selectedSoundId = soundIds[i];
AssetFileDescriptor afd = res.openRawResourceFd(soundIds[i]);
player.reset();
try {
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
player.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
player.start();
break;
}
}
}
};
for (int i = 0; i < buttonIds.length; i++) {
ImageButton soundButton = (ImageButton) rootView.findViewById(buttonIds[i]);
registerForContextMenu(soundButton);
soundButton.setOnClickListener(listener);
}
return rootView;
}
}
To my knowledge I'd probably put the onClickListener inside of each fragment and the MediaPlayer Singleton in a new Java class. I don't know what to do from there though.
How do I implement a MediaPlayer Singleton and how do I call it back in the fragment's "onCreateView" method?
Examples are highly appreciated and thanks!
See, Singleton is a design pattern, and it is implemented by setting the default constructor as private, then you should provide a get method from wich you can recover your object instance. Check out the example bellow:
public class Foo {
private MediaPlaye md;
private Foo () {
md = new MediaPlayer();
}
public MediaPlayer getMediaPlayer () {
if (md == null) {
new Foo();
}
return md;
}
}
In your sittuation, the best thing to do is to create a Service class that will encapsulate all the MediaPlayer methods. This is done like that because, usually, the developer wants that the player keeps playing even if the user leaves the Activity to which it is binded. In each fragment that you want to use the MediaPlayer API, you can bind the Service and use the defined interface. Take a look in the class below:
public class MusicPlayerService extends android.app.Service implements MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener,
ObserverSubject {
private static final int NOTIFY_ID = 1;
private List<MusicPlayerObserver> mObservers;
private MediaPlayer mMediaPlayer;
private final IBinder playerBind = new MusicBinder();;
private List<Track> mPlaylist;
private Integer mPosition;
private Boolean isRepeating;
private Boolean isShuffling;
private Boolean isPrepared;
private Boolean isPaused;
// Callback Methods______________________________________________
#Override
public void onCreate() {
...
}
#Override
public void onPrepared(MediaPlayer mp) {
...
}
#Override
public IBinder onBind(Intent intent) {
return playerBind;
}
#Override
public boolean onUnbind(Intent intent) {
mMediaPlayer.stop();
mMediaPlayer.release();
return false;
}
#Override
public void onDestroy() {
stopForeground(true);
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp.reset();
return false;
}
// UTIL METHODS__________________________________________________
private Long getCurrentTrackId() {
return mPlaylist.get(mPosition).getTrackId();
}
private Long getCurrentAlbumId() {
return mPlaylist.get(mPosition).getAlbumId();
}
// MEDIA PLAYER INTERFACE________________________________________
public void play() {
...
}
public void pause() {
...
}
public void resume() {
...
}
public void next() {
...
}
public void previous() {
...
}
public void seekTo(int pos) {
...
}
// SERVICE INTERFACE PROVIDER_____________________________________
/**
* Interface through the component bound to this service can interact with it
*/
public class MusicBinder extends Binder {
public MusicPlayerService getService() {
return MusicPlayerService.this;
}
}
}
I highly recommend that you follow this strategy of creating a MusicPlayer service. Also, I suggest you to take a look in another Design Patter called Observer. Usually, in music apps, you want to update several UI elements based on the MP state. Observer is perfect for that situation.
Hope I've helped a little.

start AsyncTask from one activity, get result in another

I'm new to Android programming, and I'd like to create a central database service class which will take care of user data exchange with an external database. For this, I created a service which is started after successful login. I created another class that extends AsyncTask to do the data retrieval.
Now, I wanted the methods for the data retrieval to be stored in the service. I would fire intents to the service from different activities, and with .setAction() I would determine which method to call, or which data to retrieve.
I also created an interface class for handling the AsyncTask results.
Now, from this question I thought that it would be possible to have multiple listeners to one and the same AsyncTask result. But now this seems impossible to achieve: I'd like to retrieve the AsyncTask results in the MainMenuActivity, but I can't create an instance of AsyncUserData there as a delegate for the UserData class. In my example below, the missing piece is a valid instance of AsyncUserData for the UserData class to work with. How could I do it?
Here's the example:
MainMenuActivity
public class MainMenuActivity extends ActionBarActivity implements AsyncUserData {
TextView tvUsername;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
tvUsername =
(TextView) findViewById(R.id.tvUsername);
TelephonyManager tManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
getDataFromUserSessionService(this, uid);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void retrieveResult(String result) throws JSONException {
JSONObject jsonObject = new JSONObject(result);
String joName;
joName = jsonObject.getJSONObject("name").toString();
user.setName(joName);
tvUsername.setText(joName);
}
public void getDataFromUserSessionService(Context context, String uid) {
Intent intent = new Intent(context, UserSession.class);
intent.setAction(UserSession.ACTION_FETCH_USER_DATA);
intent.putExtra(UserSession.UID, uid);
context.startService(intent);
}
UserSession Service
public class UserSession extends IntentService {
public static final String ACTION_FETCH_USER_DATA = "com.example.blahblah.services.action.read_user_data";
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
utils = new Utils(this);
final String action = intent.getAction();
uid = intent.getStringExtra(UID);
if (ACTION_FETCH_USER_DATA.equals(action)) {
handleUserDataFetch(uid);
}
}
}
private void handleUserDataFetch(String uid) {
String[] parameters = new String[2];
parameters[0] = uid;
parameters[1] = Constants.USER_DATA_FETCH;
UserData userData = new UserData(this);
userData.execute(parameters);
}
UserData AsyncTask Class (the Utils class just has another post method):
public class UserData extends AsyncTask < String, Void, String > {
public AsyncUserData delegate = null;
private Context myContext;
public UserData(Context context) {
myContext = context;
}
#Override
protected String doInBackground(String...params) {
String serverResponse = "";
String uid = params[0];
Utils utils = new Utils(myContext);
String phpName = params[1];
List < NameValuePair > nameValuePairs = new ArrayList < NameValuePair > ();
nameValuePairs.add(new BasicNameValuePair("uid", uid));
try {
serverResponse = utils.passDataToServer(phpName, nameValuePairs);
} catch (IOException e) {
e.printStackTrace();
}
return serverResponse;
}
protected void onPostExecute(String result) {
try {
delegate.retrieveResult(result);
} catch (JSONException e) {
e.printStackTrace();
}
}
};
And the AsyncUserData interface:
public interface AsyncUserData {
void retrieveResult(String result) throws JSONException;
}
You can use a Singleton that stores a reference to the activity
public class ServiceToActivity
{
public ActionBarActivity mainactivity = null;
private static ServiceToActivity singleton = null;
public Class<?> cl = null;
private ServiceToActivity()
{
}
public static ActionBarActivity getSingleton()
{
if(singleton==null)
return null;
return singleton.mainactivity;
}
public static Class<?> getSingletonClass()
{
if(singleton==null)
return null;
return singleton.cl;
}
public static void setSingleton(ActionBarActivity mainactivity, Class<?> cl)
{
if(singleton==null)
singleton = new ServiceToActivity();
singleton.mainactivity = mainactivity;
singleton.cl = cl;
}
}
Then create the singleton before the service is started
public void getDataFromUserSessionService(Context context, String uid) {
Intent intent = new Intent(context, UserSession.class);
intent.setAction(UserSession.ACTION_FETCH_USER_DATA);
intent.putExtra(UserSession.UID, uid);
ServiceToActivity.setSingleton(this,this.getClass()); //create Singleton to store a reference to the activity
context.startService(intent);
}
In UserData retrieve data to the main activity by:
protected void onPostExecute(String result) {
try {
Class<?> cl = ServiceToActivity.getSingletonClass();
Method met = cl.getMethod("retrieveResult", String); //String because result is of type String: you can use result.getClass() instead
met.invoke(cl.cast(ServiceToActivity.getSingleton()), result); // compare it to this ServiceToActivity.getSingleton().retrieveResult(result);
} catch (JSONException e) {
e.printStackTrace();
}
}
It sounds like you might want to use an event bus such as otto

Calling handler.removeCallbacks from onDeleted method in a widget throws a nullpointerexception

I need to stop the handler when the widget is removed by the user but calling handler.removeCallbacks throws a nullpointerexception from the onDeleted method. I tried other workarounds like creating a method,in a class which implements runnable, to kill the runnable but this throw a nullpointerexception also.
Maybe handler gets null after the call of the onDeleted method so I tried to put it in the onDisabled method but nothing stop.
What am I doing wrong?
Here the code :
public class RAMWidget extends AppWidgetProvider {
private PieGraph pg;
private Context context;
private RemoteViews remoteViews;
private AppWidgetManager appWidgetManager;
private ComponentName widget;
private Handler handler;
private CustomRunnable runnable;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
this.context=context;
this.appWidgetManager=appWidgetManager;
remoteViews=new RemoteViews(context.getPackageName(),R.layout.widget_ram);
widget=new ComponentName(context,RAMWidget.class);
new DrawTask().execute();
handler=new Handler();
runnable=new CustomRunnable();
handler.postDelayed(runnable,3000);
}
private class CustomRunnable implements Runnable
{
private boolean stop;
public CustomRunnable()
{
stop=false;
}
#Override
public void run()
{
new DrawTask().execute();
Log.i("STOP",stop+"");
if(!stop)
handler.postDelayed(this,3000);
else
return;
Log.i("STOP",stop+"");
}
void killThread()
{
stop=true;
}
}
private class DrawTask extends AsyncTask<Void,Void, Void>
{
private PieSlice slice,_slice;
private long total=0,free=0,rate=0;
#Override
protected Void doInBackground(Void... unused)
{
RandomAccessFile reader=null;
try
{
reader=new RandomAccessFile("/proc/meminfo","r");
long[] mems=new long[4];
for(int i=0;i<4;i++)
{
String load = reader.readLine();
String[] toks = load.split(":");
mems[i] = Long.parseLong(toks[1].replace("kB","").trim());
}
total=mems[0]/1024;
free=(mems[1]+mems[2]+mems[3])/1024;
rate=(int)((float)(total-free)/total*100);
}
catch (Exception e)
{
e.printStackTrace();
}
if(reader!=null)
try
{
reader.close();
}
catch (IOException e)
{
e.printStackTrace();
}
slice=new PieSlice();
slice.setTitle("Available RAM");
slice.setColor(Color.parseColor("#99CC00"));
slice.setValue(total-free);
_slice=new PieSlice();
_slice.setTitle("Used RAM");
_slice.setColor(Color.parseColor("#FFBB33"));
_slice.setValue(free);
publishProgress();
return null;
}
#Override
protected void onProgressUpdate(Void... values)
{
pg=new PieGraph(context);
pg.measure(200,200);
pg.layout(0,0,200,200);
pg.setDrawingCacheEnabled(true);
pg.addSlice(slice);
pg.addSlice(_slice);
pg.setInnerCircleRatio(150);
for (PieSlice s : pg.getSlices())
s.setGoalValue(s.getValue());
pg.setDuration(1000);
pg.setInterpolator(new AccelerateDecelerateInterpolator());
pg.animateToGoalValues();
pg.setPadding(3);
remoteViews.setTextViewText(R.id.widget_ram_text, "Total RAM " + total + " MB");
remoteViews.setTextViewText(R.id.widget_ram_text1,"Avaiable RAM "+(total-free)+" MB");
remoteViews.setTextViewText(R.id.widget_ram_text2,"Used RAM "+free+" MB");
Bitmap bitmap=pg.getDrawingCache();
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLACK);
paint.setTextSize(18);
paint.setShadowLayer(1f,0f,1f,Color.WHITE);
Rect bounds=new Rect();
paint.getTextBounds(rate+" %",0,new String(rate+" %").length(),bounds);
int x=(bitmap.getWidth()-bounds.width())/2;
int y=(bitmap.getHeight()+bounds.height())/2;
canvas.drawText(rate+" %",x,y,paint);
remoteViews.setImageViewBitmap(R.id.graph_widget,bitmap);
appWidgetManager.updateAppWidget(widget,remoteViews);
}
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
runnable.killThread();
handler.removeCallbacks(runnable); //both of them don't work
super.onDeleted(context, appWidgetIds);
}
#Override
public void onDisabled(Context context) {
runnable.killThread();
handler.removeCallbacks(runnable);
super.onDisabled(context);
}
}
The problem is that you can't depend on the same instance of your widget being called by Android each time, and so keeping non-static fields in your widget provider is a problem.
An easy solution would be to use static fields for handler and runnable. It looks like some of the other fields could go away too, for example PieGraph is constructed each time onProgressUpdate is called, so it could be a local. Basically you should avoid all non-static fields in a widget.

Categories