I am using the code below in my activity class:
public static Activity list_Addresses_Activity;
And in my onCreate I used from this :
list_Addresses_Activity = this;
But it throws an error stated below:
Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)
I need to use it from static because I will use from this in my Service class.
My CloseActivies.class :
public class CloseActivies {
Activity a;
Activity b;
Activity c;
protected void CLSActivities(Activity ListAddresses, Activity ListOrder, Activity SendReports) {
a = ListAddresses;
b = ListOrder;
c = SendReports;
if (ListAddressesActivity.FlagLiveAddress && a != null) {
Log.e("ADASFSDAGWEG", "X");
a.finish();
ListAddressesActivity.FlagLiveAddress = false;
}
if (ListOrderActivity.FlagLiveOrder && b != null) {
Log.e("ADASFSDAGWEG", "Y");
b.finish();
ListOrderActivity.FlagLiveOrder = false;
}
if (SendReportsActivity.FlagSendReport && c != null) {
Log.e("ADASFSDAGWEG", "Z");
c.finish();
SendReportsActivity.FlagSendReport = false;
}
}
protected void CLSActivities() {
if (ListAddressesActivity.FlagLiveAddress && a != null) {
Log.e("ADASFSDAGWEG", "X");
a.finish();
ListAddressesActivity.FlagLiveAddress = false;
}
if (ListOrderActivity.FlagLiveOrder && b != null) {
Log.e("ADASFSDAGWEG", "Y");
b.finish();
ListOrderActivity.FlagLiveOrder = false;
}
if (SendReportsActivity.FlagSendReport && c != null) {
Log.e("ADASFSDAGWEG", "Z");
c.finish();
SendReportsActivity.FlagSendReport = false;
}
}
}
It will cause a memory leak as your service class is working on a separate thread and passing a static reference to your activity will keep the instance in memory even if the activity is dismissed and not garbage collected, a safer way to do this is passing a reference of your activity as a parameter to your service and storing it in a weakreference something like this
public class MyIntentService extends IntentService {
private final WeakReference<Context> mContextWeakReference;
public MyIntentService() {
super("MyIntentService");
}
public static void startActionFoo(Context context) {
mContextWeakReference = new WeakReference<>(context);
Intent intent = new Intent(context, MyIntentService.class);
context.startService(intent);
}
#Override
protected void onHandleIntent(Intent intent) {
Context context = mContextWeakReference.get();
if(context != null) {
//do your work as since context is not null means
//activity is still present and if activity is dismissed
//context will come null
}
}
}
If you need activity reference for one of its static variable you can pass it in intent extras, or you want to call a static function of activity, a broadcast receiver would be a better choice to do this.
If you are starting service from activity and use some data of activity in that service. You can pass them in intent.
Intent intent = new Intent(this,MyService.class);
intent.putExtra("data", "some_value");
startService(intent);
Related
Can we call IntentService class from a running Service class .
Intent myintentservice = new Intent(this, MyIntentService.class);
startService(myintentservice);
I using above lines of code in service class to start IntentService class. But then I get following error:-
Process: objectdistance.ankeshkjaisansaria.ram.sita.cameratag, PID: 21823
java.lang.NullPointerException: Attempt to invoke virtual method
'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.content.ComponentName.<init>(ComponentName.java:77)
at android.content.Intent.<init>(Intent.java:4161)
**Edited:------------- **
1. Main Activity.Java
OnCreate():-
Intent i = new Intent(this, ServiceA.class);
startService(i);
2. ServiceA.java
public class ServiceA extends Service {
String TAG = "Log";
private static HandlerThread sWorkerThread;
private static Handler sWorkerQueue;
private static DataProviderObserver sDataObserver;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
sWorkerThread = new HandlerThread("ContentObserver");
sWorkerThread.start();
sWorkerQueue = new Handler(sWorkerThread.getLooper());
final ContentResolver r = this.getContentResolver();
if (sDataObserver == null) {
sDataObserver = new DataProviderObserver(getApplicationContext(), sWorkerQueue);
Log.d("CP", " " + android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
r.registerContentObserver(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, sDataObserver);
}
else{Log.d("Error","Error Content Observer Service");}
super.onCreate();
}
public void IntService(){
Intent MyIntentService = new Intent(this, MyIntentService.class);
startService(MyIntentService);
}
#Override
public void onDestroy() {
getContentResolver().unregisterContentObserver(sDataObserver);
super.onDestroy();
}
}
3. DataProviderObserver.Class
public class DataProviderObserver extends ContentObserver {
Context context;
DataProviderObserver(Context context ,Handler h) {
super(h);
this.context = context;
}
#Override
public void onChange(boolean selfChange, Uri uri) {
if (uri.toString().equals("content://media/external/images/media")){
ServiceA obj1 = new ServiceA();
ob1.IntService();
}
}
#Override
public boolean deliverSelfNotifications() {
return false;
}
}
4. MyIntentService.java
public class MyIntentService extends IntentService {
Context ctx;
public MyIntentService() {
super("test-service");
}
#Override
public void onCreate() {
ctx = getBaseContext();
super.onCreate();
}
#Override
public void onHandleIntent(Intent i){
try {
Uri uri;
Cursor cursor;
int column_index_id , column_index_data;
uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String order = MediaStore.MediaColumns.DATE_ADDED + " desc";
String[] projection = {MediaStore.MediaColumns._ID , MediaStore.MediaColumns.DATA};
cursor = **CONTEXT_REQUIRED**.getContentResolver().query(uri, projection, null, null, order);
column_index_id = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID);
column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
cursor.close();
}catch (Exception e){
e.printStackTrace();
}
// My Task
}
}
I have answered another question today which has exactly the same mistake.
ServiceA obj1 = new ServiceA();
ob1.IntService();
You are trying to create a new object of a service which is a very very bad practice. You cannot simply create an object of service like this. All Services in Android must go through the Service lifecycle so that they have a valid context attached to them. In this case a valid context is not attached to the obj1 instance. So as a result the line
Intent MyIntentService = new Intent(this, MyIntentService.class);
causes a null pointer as 'this' is null. (Why? Because this refers to the context which has not yet been created as the service is not started using startService(intent))
Btw I don't understand why you are starting the intent service from within the service. you can simply do it from the DataProviderObserver class like this
Intent MyIntentService = new Intent(context, MyIntentService.class);
context.startService(MyIntentService);
since context is present in the class.
I want update ListView from BroadcastReceiver in onReceiver event.
How to initialized ListView in this class then update to ListView:
public class CallBroadcast extends BroadcastReceiver {
private static int pState = TelephonyManager.CALL_STATE_IDLE;
#Override
public void onReceive(final Context context, final Intent intent) {
TelephonyManager telManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telManager.listen(new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
callDAO = new CallDAO(context);
if (configPreferenceManager.getAutoRecord()) {
if (state != pState) {
if (state == TelephonyManager.CALL_STATE_OFFHOOK && callInfoPreferenceManager.getCallState()) {
uri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(callInfoPreferenceManager.getPhoneNumber()));
projection = new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
, ContactsContract.Contacts.PHOTO_ID
};
// START SERVICES TO RECORD CALL. AFTER IT, I WANT UPDATE MY LIST
sIntent = new Intent(context.getApplicationContext(),
CallRecordService.class);
context.startService(sIntent);
} else if (state == TelephonyManager.CALL_STATE_RINGING && callInfoPreferenceManager.getCallState()) {
callInfoPreferenceManager.setPhoneNumber(incomingNumber);
callInfoPreferenceManager.setSending(String.valueOf(false));
} else if (state == TelephonyManager.CALL_STATE_IDLE && callInfoPreferenceManager.getCallState() == CALLING) {
callDAO.insert(callInfoPreferenceManager.getName(),
callInfoPreferenceManager.getPhoneNumber(),
callInfoPreferenceManager.getStartDate()
+ configPreferenceManager.getPathFormat());
callDAO.close();
// Record call start service
sIntent = new Intent(context.getApplicationContext(),
CallRecordService.class);
context.stopService(sIntent);
callInfoPreferenceManager.setCallState(IDLE);
}
pState = state;
}
}
}
}, PhoneStateListener.LISTEN_CALL_STATE);
}//onReceive
}
In the code I posted is BroadcastReceiver class.
And I can't using getActivity() class or findViewById(a, b) when extends BroadcastReceiver.
How to fix this problem?
Start the activity that will populate the listview using Intents.
Intent intent = new Intent(context,Myactivity.class)
startactivity(intent);
To avoid multiple instances of same 'Myactivity', use appropriate flags in the Manifest file.
If you want to transfer data between your broadcastReceiver and 'Myactivity', either use intent.putExtra() or store the data into sharedPreferences
how can I check if Activity is started by default or a method of the Activity is called from an intent in an other activity?
I think at the moment my Code is very bad, because i handle it over a Try/Catch
It works fine, but i want better code
public class MyScan extends Activity {
public final static String EXTRA_MESSAGE = ".MESSAGE";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
checkIntent();
}
public void checkIntent() {
try {
Intent i = getIntent();
String method_name = i.getStringExtra("method_name");// is firing an error if there is no intent call
if (method_name.equals("scanBarcode")) {
scanBarcode2();// That starts my method
}
} catch (Exception e) {
setContentView(R.layout.activity_my_scan); // that shows just my Content
}
}
....
Thanky you for your hint Alex Terreaux
i changed the code this way
public void checkIntent() {
Intent i = getIntent();
if (i != null) {
String method_name = i.getStringExtra("method_name");
if (method_name != null && method_name.equals("scanBarcode")) {
scanBarcode2();
} else {
setContentView(R.layout.activity_my_scan);
}
}
}
and that works.
Try checking if the result of getIntent() is null.
You could use extras. In strings.xml add a new string:
<string name="starting_from_intent">STARTING_FROM_INTENT</string>
In the file where you are starting the activity by intent you can use:
intent.putExtra(getString(R.string.starting_from_intent), 1);
Then, in the checkIntent(), do:
boolean startedFromIntent;
Intent i = getIntent();
if (i.getIntExtra(getString(R.string.starting_from_intent), 0) == null
|| i.getIntExtra(getString(R.string.starting_from_intent), 0) == 0)
startedFromIntent = false;
else
startedFromIntent = true;
Hope this wasn't too hard to understand and hope this helps.
When your activity was started just by startActivity() a getCallingActivity() method in target activity will return null.
When it was called by startActivityForResult() it will return name of calling activity.
I want to start an activity through IntentService, but the catch is the activty name or the class name will be passed as parameter to the IntentService.
Following are my code blocks...
public class Runner {
Context context;
public void startActivity() {
Intent intent = new Intent(context, ActivityLauncher.class);
intent.putExtra("caller", "Runner");
//CameraActivity is my activity which i want to start
// I will be giving other activities also in other parts of my code
intent.putExtra("class",CameraActivity.class);
context.startService(intent);
}
}
Now the code for ActivityLauncher Service is as follows.....
public class ActivityLauncher extends IntentService {
public ActivityLauncher(String name) {
super("ActivityLauncher");
}
protected void onHandleIntent(Intent intent) {
try{
Bundle b = intent.getExtras();
Class<?> c = (Class<?>) b.get("class");
Intent mainActivityIntent = new Intent(getBaseContext(), c.getClass());
mainActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String intentType = intent.getExtras().getString("caller");
if(intentType == null)
return;
if(intentType.equals("Runner"))
getApplication().startActivity(mainActivityIntent);
} catch (Exception localException) {
Log.d("TAG", localException.getMessage());
}
}
}
Please tell me how can i improve my code. and how can i get the solution.
I refactoring my threads in order to avoid memory leaks, and I got 2 errors regarding handler and startActivityForResult being called from within the thread ( dealing with GoogleDrive)
I have in my DownloadActivity :
public class DownloadActivity extends Activity {
....
private void getFolderId(){
getFolderIdThread = new GetFolderIdThread();
getFolderIdThread.start();
}
private static class GetFolderIdThread extends Thread {
private Boolean mRunning = false;
#Override
public void run() {
mRunning = true;
fResultList = new ArrayList<File>();
Files f1 = mService.files();
Files.List request = null;
aFolderId = null;
do {
try {
request = f1.list();
String aQuery = "'root' in parents and mimeType='application/vnd.google-apps.folder' and title='"+ aFolderName + "'";
request.setQ(aQuery);
FileList fileList = request.execute();
fResultList.addAll(fileList.getItems());
request.setPageToken(fileList.getNextPageToken());
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION); <= THIS RAISES THE ERROR
} catch (IOException e) {
e.printStackTrace();
if (request != null){
request.setPageToken(null);
}
}
} while (request.getPageToken() !=null && request.getPageToken().length() > 0);
if (fResultList.size() == 0) {
Log.d(TAG, "cannot find the training folder at root level");
Message msg = handler.obtainMessage(); <= THIS RAISES THE ERROR
Bundle bundle = new Bundle();
bundle.putInt("msgKey", DownloadActivity.NO_TRAININGS_FOLDER);
msg.setData(bundle);
handler.sendMessage(msg); <= THIS RAISES THE ERROR
} else {
File folder = fResultList.get(0);
aFolderId = folder.getId();
getFolderContents(); <= THIS RAISES THE ERROR
}
}
public void close() {
mRunning = false;
}
}
I have the handler defined in my activity
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
...
}
}
and the onActivityResult
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_ACCOUNT_PICKER:
....
break;
}
}
what are my options to bypass this error ?
Your GetFolderIdThread class is static and a static nested class cannot reference non-static methods and fields in the instance of the outer class that created it. Such a nested class can only access static methods and fields in your Activity. Remove static from the class definition and I think your problem will resolve.
You also need to post your call to startActivityForResult on the UI thread. Of course you should be able to use your handler for that, something like:
handler.post(new Runnable()
{
public void run()
{
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
}
});
Make sure your thread can gracefully complete as well when you do that because it will continue to run.