I'm loading a picture from a url into a bitmap. This code below worked on previous classes that extended Fragment. This time, I'm just copying the code and trying to use it in a class that extends AppCompatActivity. The only difference is how I'm getting context.
public void loadBitmap(String url) {
if (loadtarget == null) loadtarget = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
handleLoadedBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
mContext = MyActivity.this;
Picasso.with(mContext).load(url).into(loadtarget); //giving me null
}
In the original code, where I used it in a Fragment, I had it as
Picasso.with(getActivity()).load(url).into(loadtarget);
So now, since this class extends AppCompatActivity, I thought I could use "this" or MyActivity.this but that didn't work. I've tried initializing a Context variable "mContext" in onCreate and right before I load the image into the bitmap (like above) but neither worked. I've tried this.getApplicationContext() and I've also tried to pass mContext as a parameter in the loadBitmap() method but that didn't work either.
My URL string is correct. I'm just not sure how to tackle this problem after trying, what seems like, everything.
Last piece of information, the exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:112)
at com.salty.seas.Driver.MyActivity.loadBitmap(MyActivity.java:144)
at com.salty.seas.Driver.MyActivity$1.onKeyEntered(MyActivity.java:61)
at com.firebase.geofire.GeoQuery$2.run(GeoQuery.java:126)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
In the comments to the question you said that the activity, the loadBitmap() belongs to, you actually instantiate yourself (in some other fragment) and use it as an utility class.
You should never create activites manually as they are managed by android and they have a lifecycle android maintains.
In your case the activity is not in a correct state (one of its internal fields is null), that's why you get NPE.
For utility methods create utility classes and call those from wherever you want.
Related
I have been trying to use getResources in a non-activity class. I found some advice on how to do so here. To use one of the suggested ways, by Lilzilala, (there are multiple, but mostly suggest the same thing), I have created a special class, used this to specify the resources as "res", and then instantiated this class using "new" in a line which invokes "getResources".
However, I'm getting a "cannot resolve method getResources" error on "getResources". I'm a bit of a noob, but don't know why this is happening. From what I can tell, this error happens when there simply isn't a resource with that name available. Which makes me think maybe Resources doesn't contain getResources() by default?
class executeTrimmer<Resdefine> {
public class ResDefine {
private Resources res;
public ResDefine(Resources res)
{
this.res = res;
}}
Bitmap img1 = BitmapFactory.decodeResource(new ResDefine(getResources()),
R.drawable.bmpname);
}
EDIT - following suggestions that I add context, I have tried this:
class executeTrimmer<Resdefine> {
private static Context context;
public executeTrimmer(Context context){
this.context = context;
}
public class ResDefine {
private Resources res;
public ResDefine(Resources res)
{
this.res = res;
}}
Bitmap img1 = BitmapFactory.decodeResource(new ResDefine(executeTrimmer.context.getResources),
R.drawable.bmpname);
But this still brings up error "cannot resolve symbol getResources". I've tried multiple different ways to pass context to it, and consistently faced the same error.
As you can see in the official documentation, "getResources" is Context's method, therefore you can't call it out from nowhere, neither statically. This method requires a context instance.
In your case you must at least pass a context to your class to be able to invoke it as next:
context.getResources()
I think you got confused from seen it being directly called inside Activities without a prefixed context, but as all Activities are actually a context, this is why there is no prefix.
To clarify. When called inside an activity, this:
getResources()
is the same as this:
this.getResources()
where the prefix "this." refers to the activity, which in turn is a context by itself.
On the other hand your code should be like next, without the ResDefine class. And notice that the decodeResource call is required to be inside a method and not at class level scope (this is not allowed in Java). And in fact you don't even need to use a context, so pass instead the Resources instance from the caller's class which is supposed to hold the context:
public class executeTrimmer {
private final Resources res;
public executeTrimmer(final Resources res) {
this.res= res;
}
public void loadBitmap()
Bitmap img1 = BitmapFactory.decodeResource(this.res, R.drawable.bmpname);
........
}
}
And for the caller, next a very naive example, so may get an idea:
public class MainActivity extends Activity {
#Override
protected void onCreate(#Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new executeTrimmer(this.getResources()).loadBitmap();
}
}
I found this question was marked as duplicate for one about how to prevent Null Pointer Exceptions. For clarification, the problem is that the library is throwing it. My variable isn't null. More specific help about the library is more helpful.
I am creating an app for playing music. I am trying to make use of the MediaController class to add controls to the song being played. However, when I run the .show() function, I get a Null Pointer Exception.
Here is the code for the MediaController:
public void onViewCreated(#NonNull final View view, #Nullable Bundle savedInstanceState) {
MediaController timer = view.findViewById(R.id.song_progress);
timer.setMediaPlayer(new MediaController.MediaPlayerControl() {
#Override
public void start() {
MainActivity.playingSong.start();
}
#Override
public void pause() {
MainActivity.playingSong.pause();
}
#Override
public int getDuration() {
return MainActivity.playingSong.getDuration();
}
#Override
public int getCurrentPosition() {
return MainActivity.playingSong.getCurrentPosition();
}
#Override
public void seekTo(int pos) {
MainActivity.playingSong.seekTo(pos);
}
#Override
public boolean isPlaying() {
return MainActivity.playingSong.isPlaying();
}
#Override
public int getBufferPercentage() {
return 0;
}
#Override
public boolean canPause() {
return true;
}
#Override
public boolean canSeekBackward() {
return true;
}
#Override
public boolean canSeekForward() {
return true;
}
#Override
public int getAudioSessionId() {
return MainActivity.playingSong.getAudioSessionId();
}
});
timer.setAnchorView(view);
timer.setEnabled(true);
timer.show();
}
Here is the error log:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.luner.mobilemusic, PID: 2021
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.measure(int, int)' on a null object reference
at android.widget.MediaController.updateFloatingWindowLayout(MediaController.java:173)
at android.widget.MediaController.show(MediaController.java:363)
at android.widget.MediaController.show(MediaController.java:314)
at com.luner.mobilemusic.Playlist$Song$PlayFragment.onViewCreated(Playlist.java:271)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:892)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7156)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
Why is this happening? Is there a good way to fix this, or should I use a different class completely? I would very much appreciate any code examples you might have.
Also, I found that removing the setAnchorView(view) prevented the error, but then caused no MediaController to appear.
Edit
After doing a more thorough search, I found two things:
The line numbers aren't accurate for some reason; the line for updateFloatingWindowLayout appeared inside a different method.
The culprit is the mDecor variable, which while running the setAnchorView method is set to the view variable. However, the view variable can't be null, as that would have caused an exception before getting to the show function. Thus, I still can't quite figure out the source of this ... the mDecor variable must somewhere be set to null, but only when I add a custom anchor view.
Edit 2
I have made lots of changes to the program at this point, so I am unable to test if a solution works. However, feel free to post an answer to help anyone else with the issue. I will accept any answer with a good amount of upvotes, as the upvotes signify that the solution worked. Thanks to everyone who tried to help!
My app crash only in vivo phones, and the error log is this:
java.lang.NullPointerException: Attempt to invoke virtual method
'java.lang.String android.content.Context.getOpPackageName()' on a
null object reference at
android.media.PlayerBase.PlaybackDetectionCallBack(PlayerBase.java:348)
at android.media.PlayerBase.baseStop(PlayerBase.java:229) at
android.media.MediaPlayer$2.onCompletion(MediaPlayer.java:3578) at
android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:3351)
at android.os.Handler.dispatchMessage(Handler.java:106) at
android.os.Looper.loop(Looper.java:192) at
android.app.ActivityThread.main(ActivityThread.java:6671) 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:818)
I believe it is about MediaPlayer which I use to play BGM in my app.
But I can't find out how this happens since the error stack didn't retrieve to my code.
Here is all my code about play BGM.
public void playBgm(final int resId, boolean restartIfSame) {
if(resId == currentBgmRes && !restartIfSame) {
if(!bgmPlayer.isPlaying()) {
bgmPlayer.start();
}
return;
}
if(bgmPlayer.isPlaying()) {
bgmPlayer.stop();
}
_playBgm(resId);
}
private void _playBgm(int resId) {
bgmPlayer.release();
bgmPlayer = MediaPlayer.create(this, resId);
bgmPlayer.setLooping(true);
currentBgmRes = resId;
bgmPlayer.start();
}
The two functions are inside class AppDelegate extends Application, so this should be the application instance.
It doesn't always crash. Since the phone causing the problem is some far-away user's, I can't get the phone in several days. So I'm not sure in what situation it will happen, but it should not happen in any situation.
I figured out the problem.
My MediaPlayer variable has an initial value new MediaPlayer().
When the Activity playing the BGM calls onPause(), I call MediaPlayer.pause().
But calling pause() to a new MediaPlayer() seems to cause crash in some devices, while OK in other devices.
I change the initial value to null, and do the null check whenever I use the object. The crash never happen again.
I used the anko library to create a login view.
class SingInView : AnkoComponent<SingleInActivity> {
override fun createView(ui: AnkoContext<SingleInActivity>) = with(ui) {
verticalLayout {
lparams(width = matchParent, height = matchParent)
textView("Member Login")
editText {
hint = "E-mail"
}
editText {
hint = "PassWord"
}
button("Login")
}
}
}
and SingleInActivity.kt
class SingleInActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState)
SingInView().setContentView(this)
and MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startActivity(new Intent(this, SingInView.class));
finish();
}
}
current My app MainActivity -> SingleInActivity -> SingInView .
of course it can be made simply.
but there is a condition
1. MainActivity is java (kotlin prohibition)
2. use only MainActivity, SingInView.
How to solve this problem?
How to call the Anko class directly from a Java class
If you dig through the Anko source code you'll quickly find this:
interface AnkoComponent<in T> {
fun createView(ui: AnkoContext<T>): View
}
And from the wiki (where MyActivityUI is the component): MyActivityUI().setContentView(this). Now, the AnkoComponent is just an interface and the setContentView method is an extension function that returns createView.
Anyways, the setContentView extension function passes the last variable of the AnkoContextImpl as true. The last variable is whether or not to actually set the content view, which is the reason the activity is passed in the first place.
TL;DR (and possibly more sensible summary of my point):
The component is not an Activity
The setContentView method is not a replacement for setContentView in an Activity; just a wrapper for it.
And since it isn't an activity, you can't use an intent into it. And, as a result of that, you cannot use it standalone. You need an activity. Now, you can of course use the regular approach, but there's also another way. Since the AnkoComponent itself doesn't have any fields, it can be serialized without much trouble. Just to clarify: some fields can be serialized even if it isn't serializable (all though some classes like Context cannot be serialized). Anyways, you create an activity:
class AnkoComponentActivity : AppCompatActivity(){//Can be a regular Activity too
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
val component = intent.getSerializableExtra("uiComponent") as AnkoComponent<AnkoComponentActivity>//The type has to match this activity, or setContentView won't allow passing `this`
component.setContentView(this)//The context of the activity doesn't get passed until this point, which enables the use of this system.
}
}
Or it's equivalent in Java:
public class AnkoComponentActivity extends AppCompatActivity {
public void onCreate(Bundle sis){
super.onCreate(sis);
AnkoComponent<AnkoComponentActivity> component = (AnkoComponent<AnkoComponentActivity>) getIntent().getSerializableExtra("uiComponent");
org.jetbrains.anko.AnkoContextKt.setContentView(component, this);//For reference, this is how you call Kotlin extension functions from Java
}
}
Note that any UI component sent to this class has to be declared with <AnkoComponentActivity>. In addition, the components have to implement Serializable. Otherwise they can't be passed through the Bundle. Alternatively, you can use ints or Strings as identifiers and use the value to pick which AnkoComponent to show.
All though, the absolutely easiest way is just creating one activity per component.
TL;DR: AnkoComponent is not an Activity, meaning you can't use intents into it. You have to use an Activity, but using Serializable enables you to pass the component through a bundle to an Activity made for manual creation of multiple AnkoComponents without specifying specific types.
In my application I want 2 fragments in a Activity. and for showing these 2 fragments I use ViewPager.
In Fragment two I have one method, and I want call this method from Fragment one!
My method in Fragment two :
public void getComments() {
JsonObject requestBean = new JsonObject();
requestBean.addProperty("entityType", 4);
requestBean.addProperty("reviewType", 5);
requestBean.addProperty("reviewUserType", 2);
requestBean.addProperty("entityID", serialID);
requestBean.addProperty("celebrityId", 0);
requestBean.addProperty("pageIndex", 1);
requestBean.addProperty("pageSize", 10);
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<CommentResponse> call = api.getComments(token, requestBean);
call.enqueue(new Callback<CommentResponse>() {
#Override
public void onResponse(Call<CommentResponse> call, Response<CommentResponse> response) {
if (response.body().getData() != null) {
if (response.body().getData().size() > 0) {
reviewSerialFrag_NoComment.setText("");
} else {
reviewSerialFrag_NoComment.setText(context.getResources().getString(R.string.noReviews));
}
commentModel.clear();
commentModel.addAll(response.body().getData());
commentsListAdapter.notifyDataSetChanged();
reviewSerialFrag_newsCommentsRecyclerView.setAdapter(commentsListAdapter);
reviewSerialFrag_newsCommentsUserTypeText.setText(userTypeStr);
reviewSerialFrag_newsCommentsReviewTypeText.setText(reviewTypeStr);
reviewSerialFrag_Progress.setVisibility(View.GONE);
}
}
#Override
public void onFailure(Call<CommentResponse> call, Throwable t) {
reviewSerialFrag_Progress.setVisibility(View.GONE);
}
});
}
And call this method with below codes from Fragment one :
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<SendCommentResponse> call = api.getSendComment(token, sendData);
showView(loadProgress);
goneView(sendBtn);
call.enqueue(new Callback<SendCommentResponse>() {
#Override
public void onResponse(Call<SendCommentResponse> call, Response<SendCommentResponse> response) {
if (response.body().getData()) {
Alerter.create(getActivity())
.setText(context.getResources().getString(R.string.successSendComment))
.setDuration(2000)
.setIcon(R.drawable.ic_tick_new)
.setBackgroundColorRes(R.color.colorPrimary)
.enableSwipeToDismiss()
.enableProgress(true)
.setOnShowListener(new OnShowAlertListener() {
#Override
public void onShow() {
watchlistDialog.dismiss();
goneView(loadProgress);
showView(sendBtn);
}
})
.setOnHideListener(new OnHideAlertListener() {
#Override
public void onHide() {
infoEpisodeFrag_addWatchList.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_eye_white));
infoEpisodeFrag_addWatchList.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#1da8b9")));
getData();
new EpisodeDetail_ReviewFrag().getComments();
}
})
.setProgressColorRes(R.color.whiteMe)
.show();
}
}
#Override
public void onFailure(Call<SendCommentResponse> call, Throwable t) {
}
});
But show me this error in LogCat :
FATAL EXCEPTION: main
Process: com.example.app, PID: 11978
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.support.v4.app.FragmentActivity.getResources()' on a null object reference
at com.example.app.Fragments.EpisodeDetailFrags.EpisodeDetail_ReviewFrag$6.onResponse(EpisodeDetail_ReviewFrag.java:305)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5349)
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:908)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
Show me error for this line in Fragment two :
reviewSerialFrag_NoComment.setText(context.getResources().getString(R.string.noReviews));
How can I fix it? Please help me
It is really a bad idea to use Fragments like regular classes. Even when you want to pass simple data around you'd use and instance or use the bundle.
If your method does not rely on the fragment itself, create a separate utility class that both fragments share. Just pass it a context so it can resolve some of the variables in it.
Separate the UI manipulation in a separate class within your fragments. Create a listener to this utility class and change the visual state in your fragment.
No need to call getResources() method. Just getString(R.string.noReviews) works.
Get the instance of fragment
ExampleFrag frag=(ExampleFrag)getActivity().getSupportFragmentManager().findFragmentById(R.id.fragment2);
Then call any method
frag.myMethod();