Cannot Update Image from Runnable - Android - java

I have the following class that implements runnable. When I start the thread I get an error preventing me from updating the image. I have tried setting the image as you will see in the runOnUiThread function but it doesn't work. I would like to ultimately update the image every x seconds but I cannot seem to do this unless I put the thread inside the main activity class. Once I move it out nothing I try works.
public class Test implements Runnable {
MainActivity activity;
ArrayList<Media> media = new ArrayList<Media>();
public Test(MainActivity activity){
this.activity = activity;
}
public void run(){
activity.runOnUiThread(new Runnable(){
#Override
public void run() {
ImageView img= (ImageView) activity.findViewById(R.id.imageView1);
img.setImageResource(R.drawable.ic_launcher_foreground);
}
});
}
}
In MainActivity.java's onCreate() function I start the thread.
Test p = new Test(this);
Thread t = new Thread(p);
t.start();
Then my error:
2019-10-31 19:26:47.274 5407-5407/com.desotomatrix.digitalsignageplayer E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.desotomatrix.digitalsignageplayer, PID: 5407
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageResource(int)' on a null object reference
at com.desotomatrix.digitalsignageplayer.Test$1.run(Test.java:30)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:209)
at android.app.ActivityThread.main(ActivityThread.java:7021)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:486)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:872)

Related

How to get Activity/getWindow() from services java class?

I'm trying to run a function that requires passing it a screen capture. When I run this from the main activity, I can run the code like this:
SendScreenFunction(getWindow().getDecorView().getRootView(), getApplicationContext());
I'm not trying to call this function from a service and I can't access the getWindow() function because it requires an activity (which isn't available in the service). I was looking around online and someone suggested a function to get the activity so I can use the function. My current code looks like this:
public class ASTasks extends Service {
// This method run only one time. At the first time of service created and running
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
Log.d("onCreate()", "After service created");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Entered Timer!", Toast.LENGTH_SHORT).show();
Activity main_activity = getActivity(getApplicationContext());
try {
Log.i("Services", "Before crash");
SendScreenFunction(main_activity.getWindow().getDecorView().getRootView(), getApplicationContext());
Log.i("Services", "After crash");
} catch (IOException e) {
e.printStackTrace();
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding
return null;
}
public void SendScreenFunction(View view, Context context){
// Function goes here
}
public static Activity getActivity(Context context) {
if (context == null) return null;
if (context instanceof Activity) return (Activity) context;
if (context instanceof ContextWrapper) return getActivity(((ContextWrapper)context).getBaseContext());
return null;
}
}
Unfortunately, that solution doesn't seem to work and it's crashing. The Logcat error is shown below:
Process: com.example.ASservice:remote, PID: 15966
java.lang.RuntimeException: Unable to start service com.example.ASservice.ASTasks#6e7fed5 with Intent { cmp=com.example.ASservice/.ASTasks }: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window android.app.Activity.getWindow()' on a null object reference
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:5110)
at android.app.ActivityThread.access$2100(ActivityThread.java:310)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2319)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8680)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window android.app.Activity.getWindow()' on a null object reference
at com.example.ASservice.ASTasks.onStartCommand(ASTasks.java:41)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:5092)
at android.app.ActivityThread.access$2100(ActivityThread.java:310) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2319) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loopOnce(Looper.java:226) 
at android.os.Looper.loop(Looper.java:313) 
at android.app.ActivityThread.main(ActivityThread.java:8680) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135) 
Any ideas on the best way to take the screen capture from within the service (or even a way to pass a flag back to main to process it there)?
Any suggestions would be greatly appreciated. Thanks!

NullPointerException Context errors on code moved from one working source into a Main application

Context is not a strong point of mine, I keep getting this error this is part of code i have moved over from another application and works in there just fine, however i am trying to transplant the code from the smaller app to this main app, as adding it as a library was causing headaches which are best sorted out another day.
So the error i receive is:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app, PID: 12564
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
at androidx.localbroadcastmanager.content.LocalBroadcastManager.getInstance(LocalBroadcastManager.java:107)
at com.app.TManager.startUpdatingTrace(TManager.java:229)
at com.app.activities.ui.routeaction.RouteActionFragment$2.onFinish(RouteActionFragment.java:128)
at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:127)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
So this is the relevant code in TManager:
public class TManager extends AppCompatActivity implements Serializable {
BroadcastReceiver sensorReceiver;
BroadcastReceiver locationReceiver;
ExecutorService executorService = Executors.newFixedThreadPool(20);
public static Intent locationIntent;
public static Intent sensorService;
public LocalBroadcastManager localBroadcastManager;
public static MutableLiveData<Integer> status = new MutableLiveData<Integer>();
//Empty constructor
public TManager(){}
#RequiresApi(api = Build.VERSION_CODES.O)
public void startUpdating() {
status.setValue(0);
//register for sensorBroadcast
sensorReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
TCIMUEvent tcimuEvent = (TCIMUEvent) intent.getSerializableExtra("imuevent");
// Log.d(TAG, "In Motion Received "+ tcimuEvent.getTime());
Runnable provideDM = new Runnable() {
#Override
public void run() {
//traceCWrapper.provideDeviceMotion(tcimuEvent, Status, 0, RotationMode.Undetermined);
}
};
executorService.execute(provideDM);
}
};
localBroadcastManager.getInstance(MyApplication.getAppContext()).registerReceiver(
sensorReceiver, new IntentFilter("imuCreated")
);
//register for locationBroadcast
locationReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
TCLocationEvent tcLocationEvent = (TCLocationEvent) intent.getSerializableExtra("locationevent");
Runnable provideLoc = new Runnable() {
#Override
public void run() {
traceCWrapper.provideLocation(tcLocationEvent);
}
};
executorService.execute(provideLoc);
}
};
LocalBroadcastManager.getInstance(context).registerReceiver( //Error Here <-----
locationReceiver, new IntentFilter("locationCreated")
);
isRunning = true;
//Start the Services
AsyncTask as1 = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
startUpdatingLocation();
return null;
}
}.execute();
AsyncTask as2 = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
startUpdatingSensors();
return null;
}
}.execute();
}
}
This is just one example i keep getting these errors all through the code which was copied in another example error:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.AssetManager android.content.Context.getAssets()' on a null object reference
It seeems to especially be where is use
MyApplication.getAppContext......
MyApplication just returns as below:
public class MyApplication extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
}
}
How do i resolve these issues? The whole classes have been moved over it is not code taken from one class dumped into another. So not sure why context should have changed.
As i was using the MyApplication static context class in some places i needed to add this line to my Manifest file within the tag
android:name="com.yourapp.app.yourapp.MyApplication"
and make sure the application class is placed in the top level main/java/com.yourapp.app.yourapp/
This worked for me and solved the issue throughout the App. I would pay attention to the comments made as this may well not be the best way to be using Context, however this solved my issue at the moment.

Null Error attempting to create an intent in AsyncTask

Apologizes if this is a stupid question but I'm attempting to create a Intent to the next activity in AsynTask after it has pulled a user from my AWS Database. Note that this class is HomeActivity and the next one is GroupActivity. Below I have the button that will run the AsynTask:
Button groupPageBtm = findViewById(R.id.groupPage);
groupPageBtm.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
LoadGroupUser loadGroupUser = new LoadGroupUser(HomeActivity.this);
loadGroupUser.execute(makeUserIDString.uniqueIDCreater(userProfile));
}
});
Here is my AsynTask subclass:
class LoadGroupUser extends AsyncTask<String, Void, GroupDO>{
private DynamoDBMapper dynamoDBMapper;
Activity activity;
public LoadGroupUser(Activity mActivity){
this.activity = mActivity;
}
Intent groupLoadIntent = new Intent(activity, GroupActivity.class);
#Override
protected GroupDO doInBackground(String... groupPresidentGroups) {
AmazonDynamoDBClient dynamoDBClient = new AmazonDynamoDBClient(AWSMobileClient.getInstance().getCredentialsProvider());
this.dynamoDBMapper = DynamoDBMapper.builder()
.dynamoDBClient(dynamoDBClient)
.awsConfiguration(AWSMobileClient.getInstance().getConfiguration())
.build();
GroupDO groupPresDO = dynamoDBMapper.load(GroupDO.class, groupPresidentGroups[0]);
Log.i("loadedPresident: ", groupPresDO.getGroupId().toString());
return null;
}
#Override
protected void onPostExecute(GroupDO groupDO) {
super.onPostExecute(groupDO);
groupLoadIntent.putExtra("groupPresident", groupDO.getGroupPresident().toString());
activity.startActivity(groupLoadIntent);
Log.i("groupPresident", groupDO.getGroupPresident().toString());
}
}
Error Message:
-12 17:02:59.424 10503-10503/com.ronone.securesender E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ronone.securesender, PID: 10503
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:130)
at android.content.Intent.<init>(Intent.java:5780)
at com.ronone.securesender.LoadGroupUser.<init>(HomeActivity.java:188)
at com.ronone.securesender.HomeActivity$1.onClick(HomeActivity.java:77)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
The problem is here:
public LoadGroupUser(Activity mActivity){
this.activity = mActivity;
}
Intent groupLoadIntent = new Intent(activity, GroupActivity.class);
The field initializer runs before the constructor, so activity is still null. Do this instead:
Intent groupLoadIntent;
public LoadGroupUser(Activity mActivity){
this.activity = mActivity;
groupLoadIntent = new Intent(activity, GroupActivity.class);
}
But note that you're potentially leaking your activity by having a strong reference to it in an AsyncTask. That's a whole other topic. Search this site for "AsyncTask activity leak."

Context for intent in onpostexecute is not null but getting null exception

I've been stumped with this problem for two days now. I've checked this forum and other forums but can't get a question or answer close enough to my problem.
Basically I'm trying to execute an intent to open an activity from a non-activities onpostexecute, I'm sending the context (MainActivty.this) and string from a onMarkerClick function that is in a method in the MainActivity. This is going to a constructor in the non-activity which has the parameters for context and the string.
The issue is that I'm getting a null exception, but after debugging, the context is not null, it has the value of MainActivity, but when the intent is executed it returns a null exception. I've also tried many variations eg. Activity, getApplicationContext, this.context, (classname).context, (classname).this and tried a global context to no avail. The odd thing is I put the intent into an if statement if(context != null) and it passes through and it executes the intent which in turn gives me null exception which doesn't make sense. I know I'm new to android if anyone has any other suggestions on opening the activity that would be great thanks very much.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.quantusapps.joggertest, PID: 12253
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.content.ContextWrapper.getPackageName(ContextWrapper.java:131)
at android.content.ComponentName.(ComponentName.java:77)
at android.content.Intent.(Intent.java:4029)
at com.example.quantusapps.joggertest.BusCoachTramInfo.onPostExecute(BusCoachTramInfo.java:131)
at com.example.quantusapps.joggertest.BusCoachTramInfo.onPostExecute(BusCoachTramInfo.java:25)
at android.os.AsyncTask.finish(AsyncTask.java:632)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)<
This is the Mainactivity Method with onMarkerClick
mGoogleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
String bctID = bctExtraMarkerInfo.get(marker.getId());
BusCoachTramInfo busCoachTramInfo = new BusCoachTramInfo(bctID, MainActivity.this);
busCoachTramInfo.execute(bctID);
return false;
}
});
This is the non-activity constructor.
Context context;
BusCoachTramInfo(String busstopID, Context context) {
this.context = context;
naptanIdUrl = "https://api.tfl.gov.uk/StopPoint/" + busstopID + "/Arrivals?app_key=" + tfl_API_KEY + "&app_id=9c0b3009";
}
This is where the null exception is happening.
#Override
protected void onPostExecute(TreeMap<Integer, String[]> Map) {
super.onPostExecute(Map);
Intent i = new Intent(context, BusArrivalTime.class);
context.startActivity(i);
One way to get things done is implementing the AsyncTask as part of a method which takes an instance of MainActivity as a parameter. The AsyncTask on the other hand would work with a WeakReference:
void doExecuteBusCoachTramInfo(final String busstopID, MainActivity activity){
final WeakReference<MainActivity> wrActivity = new WeakReference<MainActivity>(MainActivity.this);
new AsyncTask<Void, Void, TreeMap<Integer, String[]>>(){
#Override
protected TreeMap<Integer, String[]> doInBackground(Void... params)
{
// your code from BusCoachTramInfo here
}
#Override
protected void onPostExecute(TreeMap<Integer, String[]> integerTreeMap)
{
// get back to the original Activity if possible:
MainActivity activity = wrActivity.get();
if (activity != null){
Intent i = new Intent(activity, BusArrivalTime.class);
activity.startActivity(i);
}
}
}.execute();
}
This method may be part of MainActivity, but it can just as well belong to some other class.

Start fragment in landscape mode

Thanks in advance for your help.
I'm trying to load one of my fragments which is loaded from a drawerlayout activity in landscape mode by invoking
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
The fragment does load in landscape mode. I also have a runnable thread which starts from onStart() after the fragment binds to a background service and the runnable is killed onStop().
private final Runnable initCommands = new Runnable() {
#Override
public void run() {
Log.d(TAG,"running thread");
if(isServiceBound) {
//some code...
new Handler().postDelayed(initCommands,800);
}
}
};
The runnable is launched after the fragment is bound to service:
private ServiceConnection serviceConn = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
ELMScanner.ELMScannerServiceBinder serviceBinder = (ELMScanner.ELMScannerServiceBinder) binder;
scanner = serviceBinder.getService();
isServiceBound = true;
if (scanner.isConnected()) {
Log.d(TAG,"init commands");
new Handler().post(initCommands);
}
}
public void onServiceDisconnected(ComponentName className) {
isServiceBound = false;
scanner.resetCommands();
}
};
#Override
public void onStop() {
super.onStop();
Log.d(TAG,"onStop");
FRAGMENT_RUNNING = 0;
if (isServiceBound) {
getActivity().getApplicationContext().unbindService(serviceConn);
Log.d(TAG,"unbinding service");
isServiceBound = false;
scanner.resetCommands();
}
}
The problem I'm facing is coming from setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE). For some reason this method reloads the fragment not killing the first thread and as a result there are two instances of the thread running.
07-30 18:38:53.054 2940-2940/com.package/FuelFragment﹕ on Attach
07-30 18:38:53.054 2940-2940/com.package/FuelFragment﹕ onCreate
07-30 18:38:53.054 2940-2940/com.package/FuelFragment﹕ onCreatView
07-30 18:38:53.054 2940-2940/com.package/FuelFragment﹕ onstart
07-30 18:38:53.062 2940-2940/com.package/FuelFragment﹕ onStop
07-30 18:38:53.062 2940-2940/com.package/FuelFragment﹕ on Detach
07-30 18:38:53.070 2940-2940/com.package/ApplicationPackageManager﹕ cscCountry is not German : THR
07-30 18:38:53.070 2940-2940/com.package/FuelFragment﹕ on Attach
07-30 18:38:53.070 2940-2940/com.package/FuelFragment﹕ onCreate
07-30 18:38:53.242 2940-2940/com.package/FuelFragment﹕ onCreatView
07-30 18:38:53.250 2940-2940/com.package/FuelFragment﹕ onstart
07-30 18:38:53.257 2940-2940/com.package/FuelFragment﹕ init commands
07-30 18:38:53.257 2940-2940/com.package/FuelFragment﹕ init commands
07-30 18:38:53.328 2940-2940/com.package/FuelFragment﹕ running thread
My question: is there an alternative to setRequestedOrientation() that does not reload fragment?
Thanks.
Solution:
In case you're wondering how to fix this.
In the method onStart(), add the condition
int orientation = getResources().getConfiguration().orientation;
if (orientation == 2) {
Intent serviceIntent = new Intent(getActivity(), ELMScanner.class);
getActivity().getApplicationContext().bindService(serviceIntent, serviceConn, Context.BIND_AUTO_CREATE);
}
This will ensure that the fragment only binds to service and runs the thread when it starts on landscape mode. Also make sure to add
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
#Override
public void onDetach() {
super.onDetach();
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
AFAIK, no. Orientation changes need to restart the Activity/Fragment so the system gets a chance to reload all the resources.
From the docs for setRequestedOrientation:
Change the desired orientation of this activity. If the activity is
currently in the foreground or otherwise impacting the screen
orientation, the screen will immediately be changed (possibly causing
the activity to be restarted). Otherwise, this will be used the next
time the activity is visible.
Your code should be able to handle being destroyed and recreated without messing up and creating two threads. It's not clear what you're trying to accomplish so I can't give you any further suggestions, but properly handling the activity lifecycle is necessary.

Categories