I am making an app that is using Fragments and wish to change the text in a TextView based on a message received in a client thread communicating with a laptop. The client server communication is no issue as the client thread is receiving the strings just fine.
I can't seem to properly figure out how to access the fragments TextView and alter its text.
Here is how I am currently trying to do so:
class ClientThread implements Runnable {
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
LivingRoomFragment frag = (LivingRoomFragment)getSupportFragmentManager().findFragmentById(R.id.LivingRoomFragment);
frag.setText("Inside ClientThread right now");
}
});
}
}
public static class LivingRoomFragment extends Fragment {
public static final String ARG_SECTION_NUMBER = "section_number";
TextView temp;
public LivingRoomFragment(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_room_control_fragment1, container, false);
temp = (TextView) rootView.findViewById(R.id.textView5);
MainActivity main = new MainActivity();
new Thread(main.new ClientThread(requests)).start();
return rootView;
}
public void setText(String s){
temp.setText(s);
}
}
In this case, MainActivity is the activity extending FragmentActivity.
I'm using an emulator and the app always crashing saying there was a null pointer exception at the line using frag.setText("Inside ClientThread right now"), which I believe means that the instance of LivingRoomFragment is null. It is to my understanding so far that this is supposed to be executed using a Handler because you cannot access the UI from a thread without using a method like this.
What am I doing wrong?
I am not sure, try
MainActivity main = (MainActivity)getActivity;
instead of
MainActivity main = new MainActivity();
okay Toast.
now here is your Solution.
create Broadcast Receiver in your Fragments.
create your action,action is an key which diffrenciat your broadcast.
use below sample code.(you do not have post more code,so it may not ecxatly what you want okay?)
class ClientThread implements Runnable {
private Handler mHandler;
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
Intent intent = new Intent("my_action");
intent.putExtra("message", "TEXT_YOU_WANT_TO_SET");
sendBroadcast(intent);
// LocalBroadcastManager manager = LocalBroadcastManager
// .getInstance(context);
// LivingRoomFragment frag = (LivingRoomFragment)
// getSupportFragmentManager()
// .findFragmentById(R.id.LivingRoomFragment);
// frag.setText("Inside ClientThread right now");
}
});
}
}
public static class LivingRoomFragment extends Fragment {
public static final String ARG_SECTION_NUMBER = "section_number";
TextView temp;
private MyBroadCastReceiver broadCastReceiver;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
broadCastReceiver = new MyBroadCastReceiver();
getActivity().registerReceiver(broadCastReceiver,
new IntentFilter("my_action"));
}
public LivingRoomFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.activity_room_control_fragment1, container, false);
temp = (TextView) rootView.findViewById(R.id.textView5);
MainActivity main = new MainActivity();
new Thread(main.new ClientThread(requests)).start();
return rootView;
}
public void setText(String s) {
temp.setText(s);
}
private class MyBroadCastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent intent) {
// chaneg the TextView text here
if (intent.getAction() != null
&& intent.getAction().equalsIgnoreCase("my_action")) {
temp.setText(intent.getStringExtra("message"));
}
}
}
}
good luck.
Related
Currently I'm coding an android project using Android Studio 3.1.2 and SDK 19.
When I refactored almost my whole code and replaced a lot of getContext() calls with requireContext() and getActivity() with requireActivity() i came across the problem, that the app crashes already at the launcher activity. I know that there are several posts related to the same problem of getting IllegalStateException: Fragment myFragment not attached to a contextbut they're all very project-specific so it doesn't actually show me the step i missed to do. So i hereby show you my example of code and pray for a merciful programmer that enlightens me, what I have to do, to solve this problem just in the suiting way.
This is my SplashActivity (the launcher activity):
public class SplashActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
Fragment fragmentToDisplay = null;
if (!(getIntent().getBooleanExtra("isLaunch", true))) {
fragmentToDisplay = new LoginFragment();
} else {
if (savedInstanceState == null) {
fragmentToDisplay = new SplashFragment();
}
}
if (fragmentToDisplay.isAdded()) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragmentToDisplay).commit();
}
}
}
This is the SplashFragment which gets loaded initially:
public class SplashFragment extends RequestingFragment {
private Handler delayHandler = new Handler();
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_splash, container, false);
requestQueue = Volley.newRequestQueue(this.requireContext());
requestParams.add(SessionHandler.getAppInstanceID(this.getContext()));
startRequest(RequestOperation.SESSION_CHECK);
onSuccess(new JSONObject(), "");
return fragmentView;
}
#Override
public void onDestroy() {
super.onDestroy();
delayHandler.removeCallbacksAndMessages(null);
}
#Override
public void onSuccess(final JSONObject json, String parsingKey) {
delayHandler.postDelayed(new Runnable() {
#Override
public void run() {
//parsing stuff
}
}, 2000);
}
#Override
public void onError() {
showErrorDialog();
}
private void showErrorDialog() {
//show a horrifying dialog
}
}
I would be very thankful, if someone could explain to me, what in particular is causing the exception and how do I do it correctly. Thanks in advance.
I am nuebie in Android. I suppose i am try run code from non UI thread. How i can update my grid in Fragment. I have activity SimpleImageActivity. In this Activity i am waiting Back key and I am trying update my data in GridView. Method invalidate() postInvalidate() nothing doing.
private Handler handler;
protected OnBackPressedListener onBackPressedListener;
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Fragment fr;
String tag= GridViewFragment.class.getSimpleName();
fr = getSupportFragmentManager().findFragmentByTag(tag);
if (fr == null) {
fr = new GridViewFragment();
}
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, fr, tag).commit();
}
#Override
public void onBackPressed() {
if (onBackPressedListener != null){
// ...some code...
handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
System.out.println("[VAN] I am in Runnable");
GridView gV = (GridView)findViewById(R.id.grid); // gV - links to my GridView and not null here
gV.invalidate(); //this code nothing doing
gV.postInvalidate(); //this code nothing doing too
}
}, 0);
onBackPressedListener.onBackPres(); // event Back key for fragment
}
In my GridViewFragment I am trying execute gridView.invalidate too, but in fragment below gridView=null
public class GridViewFragment extends AbsListViewBaseFragment implements OnBackPressedListener {
public GridView gridView;
private FragmentActivity activity;
View rootView;
public GridViewFragment() {
this.activity = getActivity();
}
#Override
public void onBackPres() {
new Thread(new Runnable() {
public void run() {
updateScreen();
// I am try this
// gridView.invalidate() there not working, because gridView=null
//
System.out.println("[VAN] updateScreen");
}
}).start();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
activity = getActivity();
((SimpleImageActivity)activity).setOnBackPressedListener(new GridViewFragment());
rootView = inflater.inflate(R.layout.fragment_image_grid, container, false);
gridView = (GridView) rootView.findViewById(R.id.grid);
// ... some code ...
}
private void updateScreen(){
gridView.postInvalidate(); // error because there gridView=null
}
How i can update my GridView? When triggering method public void onBackPres() { in fragment gridView.invalidate - don't working because gridView = null.
When in activity use handler.postDelayed(new Runnable() { gV return my GridView, but
gV.invalidate();
gV.postInvalidate();
nothing doing and execute without any errors.
A found the answer on my own question
handler = new Handler();
handler.post(new Runnable() {
public void run() {
GridView gV = (GridView)findViewById(R.id.grid);
gV.invalidateViews(); //this works fine
}
});
Using invalidateViews() instead invalidate()
As per the Android 4.4 developer guideline we have to use Fragment in each activity. If we make inner fragment class non-static then Android will crash our app when it comes from background to foreground so we need to make the fragment class static. In that case all the variables and classes which have been used in the fragment class (other than fragment class variable) should be static.
I think that will consume more VM memory and the app will be unstable. Can anyone suggest if I am right? Or suggest if there is other way to overcome that problem.
Here is the snippet of code.
public class MainActivity extends ActionBarActivity {
// Video variable
MediaRecorder recorder;
// Networking variables
public static String SERVERIP="";
public static final int SERVERPORT = 6775;
private Handler handler = new Handler();
private ServerSocket serverSocket;
public static SurfaceHolder mHolder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
// User Interface Elements
VideoView mView;
TextView connectionStatus;
/** Called when the activity is first created. */
public PlaceholderFragment() {
}
NotificationManager notificationManager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
Button btn = (Button)view.findViewById(R.id.notifybtnID);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
// Define UI elements
mView = (VideoView) view.findViewById(R.id.video_preview);
// connectionStatus = (TextView) findViewById(R.id.connection_status_textview);
mHolder = mView.getHolder();
// mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
SERVERIP = "192.168.1.126";
// Run new thread to handle socket communications
Thread sendVideo = new Thread(new SendVideoThread());
sendVideo.start();
}
public static class SendVideoThread implements Runnable{
public void run(){
// From Server.java
try {
if(SERVERIP!=null){
handler.post(new Runnable() {
#Override
public void run() {
// connectionStatus.setText("Listening on IP: " + SERVERIP);
}
});
}
i wanna pass a string to all fragment(child) from fragment activity (main), may be this picture can explain what exactly what i want to do
https://dl.dropboxusercontent.com/u/57465028/SC20140205-163325.png
so, from above picture...i wanna pass a string from edittext by press a button to all activity in viewpager....how could i do that?
i tried to follow this code https://stackoverflow.com/a/12739968/2003393 but it can't solved my problem..
please help me...i'm stuck
thank in advance.
here is my code from fragment activity (MainActivity)
public class Swipe_Menu extends FragmentActivity {
//String KeyWord;
//private static final String KEYWORD = "keyword";
private ViewPager _mViewPager;
private ViewPagerAdapter _adapter;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.swipe_menu_image);
Button Back = (Button)findViewById(R.id.account);
ImageButton Search = (ImageButton)findViewById(R.id.search);
EditText Keyword = (EditText)findViewById(R.id.keyword);
final String KeyWord = Keyword.getText().toString();
/**
* Back button click event
* */
Back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
finish();
}
});
setUpView();
setTab();
}
protected void sendValueToFragments(String value) {
// it has to be the same name as in the fragment
Intent intent = new Intent("my_package.action.UI_UPDATE");
intent.putExtra("UI_KEY", KeyWord );
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
and here is my fragment (Child Activity)
public class Store_Swipe extends Fragment {
public static final String ACTION_INTENT = "my_package.action.UI_UPDATE";
String KeyWord;
private TextView kata_keyword;
protected BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(ACTION_INTENT.equals(intent.getAction())) {
String value = intent.getStringExtra("UI_KEY");
updateUIOnReceiverValue(value);
}
}
};
private void updateUIOnReceiverValue(String value) {
// you probably want this:
KeyWord = value;
}
public static Fragment newInstance(Context context) {
Store_Swipe f = new Store_Swipe();
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(ACTION_INTENT);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, filter);
}
#Override
public void onDestroy() {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
super.onDestroy();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
/*Bundle bundle = this.getArguments();
KeyWord = bundle.getString("keyword");*/
View view = inflater.inflate(R.layout.store_swipe, container, false);
init(view);
return view;
}
void init(View view) {
kata_keyword = (TextView) view.findViewById(R.id.keyword);
//ImageView image = (ImageView) view.findViewById(R.id.image_error);
kata_keyword.setText(KeyWord);
}
}
You don't have access directly to your fragments that reside in ViewPager so you can't reference them directly.
What I am doing in these cases is send a broadcast message from Activity to Fragments. For this reason register a BroadcatReceiver in the fragment (either in onCreate or onCreateView - your decision)m, set a custom action for that receiver (ex. "my_package.actions.internal.BROADCAST_ACTION"), don't forget to unregister the receiver from complementary method.
When you want to send a message from activity, create an intent with above mentioned action, add the string in intent extra and send the broadcast.
In your receiver's onReceive method (within the fragment), get the String from intent paramter and there you have the string.
Makes sense?
EDIT: To provide some code, below are the changes that I would make for fragment:
public class Store_Swipe extends Fragment {
public static final String ACTION_INTENT = "my_package.action.UI_UPDATE";
protected BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(ACTION_INTENT.equals(intent.getAction())) {
String value = intent.getStringExtra("UI_KEY");
updateUIOnReceiverValue(value);
}
}
};
private void updateUIOnReceiverValue(String value) {
// you probably want this:
kata_keyword.setText(value);
}
String KeyWord;
private TextView kata_keyword;
public static Fragment newInstance(Context context) {
Store_Swipe f = new Store_Swipe();
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(ACTION_INTENT);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, filter);
}
#Override
public void onDestroy() {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
super.onDestroy();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle bundle = this.getArguments();
KeyWord = bundle.getString("keyword");
View view = inflater.inflate(R.layout.store_swipe, container, false);
init(view);
return view;
}
void init(View view) {
kata_keyword = (TextView) view.findViewById(R.id.keyword);
ImageView image = (ImageView) view.findViewById(R.id.image_error);
kata_keyword.setText(KeyWord);
}
}
And this code I would have from activity, the parameter is the value from EditText:
protected void sendValueToFragments(String value) {
// it has to be the same name as in the fragment
Intent intent = new Intent("my_package.action.UI_UPDATE");
intent.putExtra("UI_KEY", value);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
You would call this from the click listener that you would set in onCreate:
findViewById(R.id.button_id).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String valueThatYouWantToSend = null; /// just the value
sendValueToFragments(valueThatYouWantToSend);
}
});
// I think this solution will solved your issue
// In Main activity put your code -----------------------------------
public void onPageSelected(int position)
{
System.out.println("nilesh");
PageOneFragment f = new PageOneFragment();
f.getText();
PageTwoFragment ff = new PageTwoFragment();
ff.setText();
}
//in General Class ------------------------------------------------
public class General
{
public static String name="";
}
// first Fragment ---------------------------------------------
public void getText()
{
General.name = edittext.getText().toString();
}
// second Fragment ----------------------------------------------
public void setText()
{
System.out.println("name**" + General.name);
tv.setText(General.name);
}
I have a "HomeFragment" class which extends Fragment. Everything is working fine fragment is created for the first time. But when I switch to some other fragment and come back to this, the UI does not get updated. In fact it shows nothing in that TextSwitcher. I checked using Log.d that ChangeText thread is running in background all the time. Where is the mistake ?
public class HomeFragment extends Fragment {
private TextSwitcher mSwitcher;
String textToShow[]={"Main HeadLine","Your Message"};
int messageCount=textToShow.length;
int currentIndex=-1;
private Handler myHandler;
ChangeText CT;
public HomeFragment(){}
#SuppressLint("HandlerLeak")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
mSwitcher = (TextSwitcher) rootView.findViewById(R.id.textSwitcher);
mSwitcher.setFactory(new ViewFactory() {
public View makeView() {
// TODO Auto-generated method stub
TextView myText = new TextView(getActivity());
myText.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
myText.setTextSize(36);
myText.setTextColor(Color.BLUE);
return myText;
}
});
// Declare the in and out animations and initialize them
Animation in = AnimationUtils.loadAnimation(getActivity(),android.R.anim.slide_in_left);
Animation out = AnimationUtils.loadAnimation(getActivity(),android.R.anim.slide_out_right);
mSwitcher.setInAnimation(in);
mSwitcher.setOutAnimation(out);
myHandler = new Handler() {
public void handleMessage(Message msg) {
doUpdate();
}
};
CT = new ChangeText();
CT.execute();
return rootView;
}
class ChangeText extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... f_url) {
try {
while(true)
{
if (isCancelled()) break;
myHandler.sendEmptyMessage(currentIndex);
SystemClock.sleep(1500);
}
} catch (Exception e) {
Log.e("VIVEK: ", e.getMessage());
}
return null;
}
}
private void doUpdate() {
currentIndex++;
if(currentIndex==messageCount)
{
currentIndex=0;
}
Log.d("VIVEK", textToShow[currentIndex]);
mSwitcher.setText(textToShow[currentIndex]);
}
}
you should use asynctask for that, try using handler with other thread
here is an example: Change View from other thread
also other nice example: http://androidexample.com/Thread_With_Handlers_-_Android_Example/index.php?view=article_discription&aid=58&aaid=83
hope it helps,
regards
First, I strongly suggest you take a look at CountDownTimer class. I think it will fit more in your use case.
Second, try moving these:
CT = new ChangeText();
CT.execute();
to fragment's onResume() and see if it solves your problem.