requireActivity().getApplicationContext() "may produce a NullPointerExeption" - java

Bellow there is some of the code of my application. The part where I need help is in requireActivity() in SettingFragment.java:
MainActivity.java
...
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
...
}
public void iniciarIntent3() { //this method is called by a button in activity_main.xml
Intent intent = new Intent(this, Settings.class);
startActivityForResult(intent, 1);
}
}
Settings.java
...
public class Settings extends AppCompatActivity implements SettingsFragment.SendToActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings, new SettingsFragment())
.commit();
}
}
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof SettingsFragment) {
SettingsFragment settingsFragment = (SettingsFragment) fragment;
settingsFragment.setSendToActivity(this);
}
}
public void send(int result) {
...
}
}
SettingsFragment.java
public class SettingsFragment extends PreferenceFragmentCompat {
SendToActivity callback;
public void setSendToActivity (SendToActivity callback) {
this.callback = callback;
}
public interface SendToActivity {
void send(int result);
}
if (editTextPreference != null) {
editTextPreference.setOnBindEditTextListener(new
EditTextPreference.OnBindEditTextListener() {
#Override
public void onBindEditText(#NonNull EditText editText) {
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
editText.setText("");
editText.setBackground(ContextCompat.getDrawable(requireActivity()
.getApplicationContext(), R.drawable.fondo_edittextpreference));
}
});
}
...
}
I just want to be sure that requireActivity() in SettingsFragment class is not going to throw a nullpointerexeption. Can you help me to check?

Instead of requireActivity().getApplicationContext() you could do either of the following
editText.setBackground(ContextCompat.getDrawable(editText.getContext(), R.drawable.fondo_edittextpreference))
editText.setBackgroundResource(R.drawable.fondo_edittextpreference)

requireActivity()
can throw null if the Activity is null for whatever reason that may be.
I believe that can be null if the user exists the application or forefully stops it etc. Or there was never one created in the context that youre in
Just do a try-catch
Activity activity;
try {
activity = requireActivity()
editText.setBackground(
ContextCompat.getDrawable(
activity.getApplicationContext(),
R.drawable.fondo_edittextpreference));
} catch (NullPointerException orTypeOfException) {
//handle here when the activity is null
}

Related

Android how to Check if language has changed

I create an application with MVVM concept, there is fragment for viewpager in my Activity. some data changed when I change my language in my application, but the data that showed by webservices is not change. so I try to add android:configChanges="locale" in my every Activity and I already add this code on my Activity class :
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
recreate();
}
}
But its make my UI recreate every configuration change, including Screen Rotation while I just want to recreate if Language is changed.
this is my fragment code :
public class CatalogueFragment extends BaseFragment<FragmentCatalogueBinding, CatalogueViewModel>
implements CatalogueNavigator, CatalogueAdapter.CatalogueAdapterListener {
#Inject
CatalogueAdapter adapter;
#Inject
LinearLayoutManager mLayoutManager;
#Inject
ViewModelProvider.Factory factory;
FragmentCatalogueBinding fragmentCatalogueBinding;
private CatalogueViewModel catalogueViewModel;
public static CatalogueFragment newInstance(int Pos) {
Bundle args = new Bundle();
CatalogueFragment fragment = new CatalogueFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public int getBindingVariable() {
return BR.viewModel;
}
#Override
public int getLayoutId() {
return R.layout.fragment_catalogue;
}
#Override
public CatalogueViewModel getViewModel() {
catalogueViewModel = ViewModelProviders.of(this, factory).get(CatalogueViewModel.class);
return catalogueViewModel;
}
#Override
public void handleError(String error) {
// handle error
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
catalogueViewModel.setNavigator(this);
adapter.setListener(this);
}
#Override
public void onRetryClick() {
catalogueViewModel.fetchData();
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
fragmentCatalogueBinding = getViewDataBinding();
setUp();
}
#Override
public void updateData(List<Movie> movieList) {
adapter.addItems(movieList);
}
private void setUp() {
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
fragmentCatalogueBinding.recyclerCatalogue.setLayoutManager(mLayoutManager);
fragmentCatalogueBinding.recyclerCatalogue.setItemAnimator(new DefaultItemAnimator());
fragmentCatalogueBinding.recyclerCatalogue.setAdapter(adapter);
}
}
and this is my ViewModel class
public class CatalogueViewModel extends BaseViewModel {
private final MutableLiveData<List<Movie>> movieListLiveData;
public CatalogueViewModel(DataManager dataManager, SchedulerProvider schedulerProvider) {
super(dataManager, schedulerProvider);
movieListLiveData = new MutableLiveData<>();
fetchData();
}
public void fetchData() {
setIsLoading(true);
getCompositeDisposable().add(getDataManager()
.getApiHelper().doMovieCall(URLConfig.API_KEY, getDataManager().getLanguage())
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(movieResponse -> {
if (movieResponse != null && movieResponse.getResults() != null) {
movieListLiveData.setValue(movieResponse.getResults());
}
setIsLoading(false);
}, throwable -> {
setIsLoading(false);
// getNavigator().handleError(throwable);
}));
}
public LiveData<List<Movie>> getMovieListLiveData() {
return movieListLiveData;
}
}
Can anybody show me where is my wrong? Thank you very much
You can use: ACTION_LOCALE_CHANGED
Here an example:
private BroadcastReceiver mLangReceiver = null;
protected BroadcastReceiver setupLangReceiver(){
if(mLangReceiver == null) {
mLangReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do what you want
}
};
registerReceiver(mLangReceiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
}
return mLangReceiver;
}

onPostExecute output in fragment

I have a working AsyncTask to get data from a server and display it in a TextView. But is it possible to output the data into a TextView which is located in a fragment? So let's say, the AsyncTask is loaded in the MainActivity and the output will be in a fragment.
This is my AsyncTask:
private static class FtpDownload extends AsyncTask<String, String, String> {
private WeakReference<GuidanceActivity> activityWeakReference;
FtpDownload(GuidanceActivity activity) {
activityWeakReference = new WeakReference<>(activity);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... FTPconnection) {
GuidanceActivity activity = activityWeakReference.get();
if (activity == null || activity.isFinishing()) {
return null;
}
try {
FTPClient ftpClient = new FTPClient();
ftpClient.connect("", 21);
System.out.println(ftpClient.getReplyString());
ftpClient.enterLocalPassiveMode();
ftpClient.login("anonymous", "");
ftpClient.changeWorkingDirectory("/");
InputStream inStream = ftpClient.retrieveFileStream(".html");
activity.contents = IOUtils.toString(inStream, StandardCharsets.UTF_8);
System.out.println(activity.contents);
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String output) {
GuidanceActivity activity = activityWeakReference.get();
if (activity == null || activity.isFinishing()) {
return;
}
TextView textView = activity.findViewById(R.id.text_view);
textView.setText(Html.fromHtml(activity.contents));
}
}
In your fragment:
public class MyFragment extends Fragment {
TextView myTextView;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = View root = inflater.inflate(R.layout.my_frag_layout, null);
myTextView = (TextView) view.findViewById(R.id.myTextView);
//rest of your implementation of onCreateView
return view;
}
//this will be called from activity
public void updateTextView(String text) {
myTextView.setText(text);
}
}
in your activity:
public class MyActivity extends AppCompatActivity {
private final String FRAGMENT_TAG = "myFragment";
private static class FtpDownload extends AsyncTask<String, String, String> {
//rest of your FtpDownload class
#Override
protected void onPostExecute(String output) {
GuidanceActivity activity = activityWeakReference.get();
if (activity == null || activity.isFinishing()) {
return;
}
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG );
/* or
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentById(R.id.fragment );
if your fragment is in an xml layout */
fragment.updateTextView(Html.fromHtml(activity.contents));
}
}
}
Yes, it is possible. This is a sample for WiFi scanning from MainActivity and the results are show at fragment. I believe you can understand the logic and convert it for your project
MainActivity:
public class MainActivity extends AppCompatActivity implements FragmentDiscoverWiFi.ScanWiFi;
//public variable
FragmentDiscoverWiFi fragmentDiscoverWiFi;
//This will be called from your fragment
#Override
public void onScanWiFi(FragmentDiscoverWiFi fragment) {
fragmentDiscoverWiFi = fragment;
}
//use something like this when your want to update fragment
fragmentDiscoverWiFi.onScanWiFiComplete();
Fragment:
public class FragmentDiscoverWiFi extends Fragment {
private Context mContext;
public interface ScanWiFi {
public void onScanWiFi(FragmentDiscoverWiFi fragment);
}
public FragmentDiscoverWiFi() {
// Required empty public constructor
}
#Override
public void onAttach(Context context) {
mContext = context;
super.onAttach(context);
}
public void onScanWiFiComplete() {
if (!isDetached()) {
//Access your data from MainActivity like this:
Log.d(TAG, "Total APs:" + ((MainActivity) mContext).wifiScanResults.size());
}
}
#Override
public void onResume() {
super.onResume();
if (!getUserVisibleHint()) {
return;
}
pullToRefreshText = rootView.findViewById(R.id.pullToRefreshText);
pullToRefresh = rootView.findViewById(R.id.pullToRefresh);
pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
Log.d(TAG, "refreshing...");
pullToRefresh.setRefreshing(true);
((MainActivity)mContext).onScanWiFi(FragmentDiscoverWiFi.this);
}
});
}
}

Why ReferenceQueue always empty in activity?

I'm trying using ReferenceQueue to check Activity if the activity is destory,Whether this activity is recycled.
I just using intent to Main2Activity.class:
switch (v.getId()){
case R.id.btn_turn_two:
Intent intent=new Intent(MainActivity.this,Main2Activity.class);
startActivity(intent);
break;
default:
break;
}
when I press to return MainActivity.class, the Main2Acitivity.class will be destroyed, so I using registerActivityLifecycleCallbacks watch activity in application,
public class MainApplication extends Application{
private watche watche;
#Override
public void onCreate() {
super.onCreate();
watche=new watche(this,getApplicationContext());
}
this class is check the Activity is destoryed.
public class watche {
KeyRefrence ref;
private Context context;
private final Set<String> retainedKeys = new CopyOnWriteArraySet<>();
private final ReferenceQueue<Object> referenceQueue=new ReferenceQueue<>();
public watche(Application application, Context context){
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
this.context=context;
}
Application.ActivityLifecycleCallbacks lifecycleCallbacks=new Application.ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
//weakrefrence to this activity
String key = UUID.randomUUID().toString();
retainedKeys.add(key);
final KeyRefrence weakReference=new KeyRefrence(activity,key,activity.getPackageName(),referenceQueue);
final MyAyTask myAyTask=new MyAyTask(weakReference,activity,context);
myAyTask.doInBackground(null);
}
};
public class MyAyTask extends AsyncTask {
private Activity activity;
private KeyRefrence keyRefrence;
private Context context;
public MyAyTask(KeyRefrence keyRefrence, Activity activity,Context context){
this.activity=activity;
this.context=context;
this.keyRefrence=keyRefrence;
}
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
}
#Override
protected Object doInBackground(Object[] objects) {
gc();
ref=(KeyRefrence)referenceQueue.poll();
if (ref==null){
Log.d(TAG, "onActivityDestroyed:Acitivty is not destory");
}
else if (ref!=null){
Log.d(TAG, "doInBackground: "+ref);
}
return null;
}
}
I have create KeyReference implement WeakReference,and I didn't do anything in Main2Activity.class, I just press the phone return,I check the gc,is working ,but the referencequeue always empty, I'm sure the Activity is destoryed.

java.lang.IllegalStateException: Fragment not attached to Activity issue in android

I am facing strange issue during call of my activity with Fragment usage. I am getting error like,
java.lang.IllegalStateException: Fragment ScoreFragment{ee2b833
id=0x7f0e0198} not attached to Activity
On line 146. My Fragment code which have error is line like below
if(mPageFlag.equalsIgnoreCase(getString(R.string.winners))){
And My full code for same is below,
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mPageFlag = getArguments().getString(ARG_PAGE_FLAG);
}
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser && !mIsPageLoaded){
mContext = getActivity();
mIsPageLoaded = true;
if(mPageFlag.equalsIgnoreCase(getString(R.string.winners))){
new getcontestscorewinners(mContext).execute();
}else{ //
new getcontestscorewinnersNew(mContext).execute();
}
}
}
public class getcontestscorewinners extends AsyncTask<String, Void, String> {
boolean response = false;
private Context mContext;
public getcontestscorewinners(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
progress = ProgressDialog.show(mContext, "Processing...",
"Please wait....");
}
#Override
protected String doInBackground(String... params) {
NetworkTask.getContestScoreWinners(winnerHandler);
return "";
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
Let me know if someone can help me for get out of it. Thanks.
Try using isAdded():
Return true if the fragment is currently added to its activity.
So your code should be like this :
if(isAdded() && mPageFlag.equalsIgnoreCase(getString(R.string.winners))){

How to use interface to communicate between two activities

I am trying to make listener interface between two activities Act1 and Act2. Act1 will start Act2. If there is some event occurred in Act2, it will inform it to Act1. Problem is that I am starting new activity using Intent, so how Act1 will assign itself as listener to Act2's interface?
Act1.java
public class Act1 extends ActionBarActivity implements
ActionBar.OnNavigationListener {
ActionBar actionbar;
Intent pizzaIntent;
boolean visibleFirstTime = true;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menutab);
//set actionbar here
}
#Override
public boolean onNavigationItemSelected(int arg0, long arg1)// item pos,
// itemid
{
switch (arg0) {
case 0:
if(this.visibleFirstTime == false)
{
if(pizzaIntent == null)
{
pizzaIntent = new Intent(this,Act2.class);
//how to call setChangeListener?
}
startActivity(pizzaIntent);
}
else
this.visibleFirstTime = false;
break;
case 1:
System.out.println("selected: " + arg0);
break;
case 2:
System.out.println("selected: " + arg0);
break;
case 3:
System.out.println("selected: " + arg0);
break;
default:
break;
}
return true;
}
}
Act2.java
public class Act2 extends Activity {
selectionChangeListener listener;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pizza_slice_selection);
}
public void setChangeListener(selectionChangeListener listener)
{
this.listener = listener;
}
private interface selectionChangeListener
{
public void selectionMadeAtIndex(int index);
}
}
Note: Please don't suggest me to use fragments. I want to use activities currently.
I would suggest to create a model class. Let me give you an example:
Model class:
public class CustomModel {
public interface OnCustomStateListener {
void stateChanged();
}
private static CustomModel mInstance;
private OnCustomStateListener mListener;
private boolean mState;
private CustomModel() {}
public static CustomModel getInstance() {
if(mInstance == null) {
mInstance = new CustomModel();
}
return mInstance;
}
public void setListener(OnCustomStateListener listener) {
mListener = listener;
}
public void changeState(boolean state) {
if(mListener != null) {
mState = state;
notifyStateChange();
}
}
public boolean getState() {
return mState;
}
private void notifyStateChange() {
mListener.stateChanged();
}
}
And here's how you would use this:
// Imports
public class MainActivity extends Activity implements OnCustomStateListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomModel.getInstance().setListener(this);
boolean modelState = CustomModel.getInstance().getState();
Log.d(TAG, "Current state: " + String.valueOf(modelState));
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
}
#Override
public void stateChanged() {
boolean modelState = CustomModel.getInstance().getState();
Log.d(TAG, "MainActivity says: Model state changed: " +
String.valueOf(modelState));
}
}
Changing the member state in second activity:
// Imports
public class SecondActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CustomModel.getInstance().changeState(true);
}
}
LogCat output:
Current state: false
MainActivity says: Model state changed: true
Have you considered using LocalBroadcastManager?
In Act1's onCreate:
act2InitReceiver= new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
// do your listener event stuff
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(act2InitReceiver, new IntentFilter("activity-2-initialized"));
In Act1's onDestroy:
LocalBroadcastManager.getInstance(this).unregisterReceiver(act2InitReceiver);
In Act2's onCreate:
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("activity-2-initialized"));
Give me a comment if the code doesn't compile, I'm writing it by hand.
The best, shortest and the easiest way to do this is to use static variables, like this:
class Main extends Activity {
static String message = "Hi";
}
class Another extends Activity {
public onCreate() {
Log.i(Main.message); // implementation of the message, 'Hi'
}
}

Categories