Use "this" in Runnable inside Fragment Android - android

In my onResume() I'm running a new Handler which runs the following line of code:
adapter = new FeedListAdapter(this, feed);
list.setAdapter(adapter);
Now, when I move this code into the Handler, the this inside the first line becomes disallowed because obviously it's inside a runnable, as shown here:
new Handler().postDelayed(new Runnable() {
public void run() {
adapter = new FeedListAdapter(this, feed);
list.setAdapter(adapter);
}
}, 500);
Now, my question is how I access the Fragment I'm in without having to create a method/variable storing the current Fragment?
I got around the issue by doing the following:
private FeedListActivity myInstance(){
return this;
}
And changing this to myInstance(), but it seems a bad way of doing it. Same with creating a new variable to store the Fragment. Is there a way I can call the Fragment I'm running from?
Perhaps this will make it clear what I want to do:
new Handler().postDelayed(new Runnable() {
public void run() {
adapter = new FeedListAdapter(getFragment(), feed);
list.setAdapter(adapter);
}
}, 500);
All answers are appreciated.

You use an inner class, it implicitly has reference to outer class. You can use syntax: FeedListActivity.this inside an inner class.

Related

Load the same Fragment with different data

I had a fragment called DomaineDashboardFragment, if it's the current fragment and I opened it with a different data in the bundle, it's not refreshed, it keeps the old data, Does anyone have an idea to resolve that ?
the fragment works fine, the problem is just when I change data.
To everyone faces the same probleme, you can do this :
DomaineDashboardFragment currentFragment = (DomaineDashboardFragment) getSupportFragmentManager().findFragmentByTag("DomaineDashboardFragment");
if(currentFragment != null && currentFragment.isAdded())
((MyApplication)getApplication()).removeFragment(MainActivity.this, currentFragment);
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override
public void run() {
DomaineDashboardFragment domaineDashboardFragment = new DomaineDashboardFragment();
domaineDashboardFragment.setArguments(b);
((MyApplication)getApplication()).setUpFragment(MainActivity.this, domaineDashboardFragment, R.id.fragment_container);
}
}, 100);
remove fragment and then attach the new one
You can use the latest Android Architecture components and create a ViewModel class. So, what you can do it, whenever you get data in bundle in Fragment, set the data to ViewModel and notifyChange();
Other than this, you must detach and attach the fragment again to get the new data.

call adapter.notifyDataSetChanged from different activity

I'm fairly new to android programming. I'm using socket.io to build a basic chat application in androd. I'm using a singleton class to share data between two activities. I have a list adapter in the second activity and I want to call adapter.notifyDataSetChanged(); from the first activity when I receive data from the server. Is this possible?
In the first activity:
mSocket.on("New", new Emitter.Listener() {
#Override
public void call(Object... args) {
JSONObject temp = (JSONObject) args[0];
Singleton.getInstance().AddMsg(temp);
// I want to call the adapter defined in the second activity here. i.e. adapter.notifyDataSetChanged();
}
});
A few points to note:
adapter.notifyDataSetChanged(); is working well if I call it from 2nd activity.
1st activity runs only once when the application is launched
You can do that by Broadcast
mSocket.on("New", new Emitter.Listener() {
#Override
public void call(Object... args) {
JSONObject temp = (JSONObject) args[0];
Singleton.getInstance().AddMsg(temp);
// I want to call the adapter defined in the second activity here. i.e. adapter.notifyDataSetChanged();
// send broadcast that is added something
Intent intent = new Intent("Added_something");
//intent.putExtra("current speed", "102.4");
//intent.putExtra("latitude", "12.2342342");
//intent.putExtra("longitude", "12.21124");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
});
In SecondActivity
register for BroadcastReceiver like below
LocalBroadcastManager.getInstance(this).registerReceiver(message,
new IntentFilter("Added_something"));
Declare BroadcastReceiver
private BroadcastReceiver message = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// refresh your adapter from SecondAdapter itself
}
};
Refer this good tutorial for local brodacast
There's no point in calling notifyDataSetChanged() from the first activity as ListView is in Second Activity. You should transfer the data from first activity to second activity whenever you open the second activity through intents and then call notifyDataSetChanged() from the second activity itself.
Reason for not calling from first activity is that you don't know if the second activity will be visible or not. Only change adapter data when the corresponding list is visible on the screen. Don't modify the adapter from other activities.
adding to #JyotmanSingh you can try to create a socket service and a callback handler in your activity to perform the updates...

Android handler and runnable nullpointer

I have a problem
I am using handler and runnable to update timer inside my app, inside my Runnable I am updating textview, after 1minut I want to show some content, everything works fine until I rotate the screen, every textview is now null, and I couldnt figure out why.
My code:
Runnable mTimer = new Runnable() {
#Override
public void run() {
textView.setText(DateFormat.format("mm:ss", timers - System.currentTimeMillis()));
test();
mHandler.postDelayed(this, TIME);
}
};
Any ideas why this might happen?
Handler probably delivers a Runnable to an Activity that was recycled. Proper use of Handler is like
private Handler mHandler;
private TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
setContentView(R.layout.yourView);
mTextView = findViewById(R.id.text);
}
#Override
protected void onStart() {
super.onStart();
//start updating every time Activity is started
handler.postDelayed(mTimer, oneMinuteDelay);
}
#Override
protected void onStop() {
super.onStop();
//make sure to remove all messages
handler.removeCallbacksAndMessages(null);
}
In theory, this (null views) should not happen.
When you change the screen orientation, the activity leaves the screen and becomes useless, but it still exists and references the views. Your runnable references the instance of activity that has created it, so the activity cannot die while the runnable is still there. At least, so it was. Which Android version do you use?
It seems I understand what you mean. You mean null contents in the views. You have to create a static variable, say, lastInstance:
class MyActivity extends Activity {
static MyActivity lastInstance;
void onCreate(...) {
...
lastInstance = this;
}
// no need to reference an instance of any Activity, so static
static class MyRunnable implements Runnable {
#Override
public void run() {
lastInstance.textView.setText(DateFormat.format("mm:ss", timers - System.currentTimeMillis()));
lastInstance.test();
mHandler.postDelayed(this, TIME);
}
}
static Runnable mTimer = new MyRunnable();
}
I do not recommend android:configChanges="screenSize|keyboardHidden|orientation" because this is not the only case when Android recreates an Activity, so this way you will not fix any bugs, you will just make them more difficult to reproduce.
For this thing you have to specify in your manifest with the specified line in your activity tag then your issue will be fixed.
i.e,
<activity android:name="your activity"
android:configChanges="screenSize|keyboardHidden|orientation">
</activity>
Then it will work for you on rotating the screen also.
Edited Answer
Better check that textview If it is null create a reference and then add the data it may fix your issue. or meanwhile you can pass your old data from onSavedInstance();
and you can get the data from onCreate(SavedInstance savedinstance)
here it will returns that prevoius data what you are setted in onsavedInstance Method.
try this for data exchange it will work
After rotate your activity recreates, so textView is null.
Please remove the handler code from the runnable. Also first create object of handler then write the handlers post delayed method where you want. Main use of handler is to update UI from thread.
If the Activity doesn't crash when you turn round the device, it means that the textView is there. If you see nulls on the screen it is the content of the textView that is being set as null.
In the text, the only variable I see is timers.
Where is this variable defined and where is it being set?
First check that you properly initialize the handler as below :
handler = new Handler();
The null pointer error may come if you not initialize the handler.

notifyDataSetChanged() on my adapter does not update the listview, why?

I have a activity that extends listactivity, extended in this class i have a class that extends baseadapter.
now in my listactivity i have this onCreate
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new BuildingAdapter(this));
final ProgressDialog loading = new ProgressDialog(this);
loading.setProgressStyle(ProgressDialog.STYLE_SPINNER);
loading.setTitle("Laddar");
loading.setMessage("Hämtar data från servern");
loading.show();
new AsyncTask<Void, Void, DataPacket.Data>()
{
#Override
protected DataPacket.Data doInBackground(Void... params){
return ServerConnection.getBuildings();
}
#Override
protected void onPostExecute(DataPacket.Data param) {
((MainenanceApplication)getApplication()).setDataStructure(param);
loading.dismiss();
//((BuildingAdapter)getListAdapter()).notifyDataSetChanged();
setListAdapter(new BuildingAdapter(BuildingSelectionActivity.this));
}
}.execute();
}
This works as it's supposed to, but my question is in onPostExecute I update the datastructure that the list adapter uses.
Why cant I just call notifyDataSetChanged ??
If I have that line the view does not update itself, but if I use the line under where I do setListAdapter, it all works.
If the adapter is already set, setting it again will not refresh the listview. Instead first check if the listview has a adapter and then call the appropriate method.
I think its not a very good idea to create a new instance of the adapter while setting the list view. Instead, create an object.
BuildingAdapter adapter = new BuildingAdapter(context);
if(getListView().getAdapter() == null){ //Adapter not set yet.
setListAdapter(adapter);
}
else{ //Already has an adapter
adapter.notifyDataSetChanged();
}
Have you tried using an AsyncTaskLoader instead of an AsyncTask for this. It's this kind of stuff that Loaders were exactly designed for. Note that even though Loaders weren't available until API-10 you can still easily access them via the android Support Pacakge from API-4 and up.
The only place you can update the UI is in onProgressUpdate(...);. From your doInBackground(...), call publishProgress(...).

Possible to programmatically open a Spinner in Android app?

If you have a handle to a Spinner object in an Android Activity, can you programmatically pop open the spinner options - thereby forcing the user to choose an option even though they did not click on the Spinner themselves?
To open the Spinner you just need to call it's performClick() method.
Keep in mind that you may only call this method from the UI thread. If you need to open the Spinner from a separate thread you should create a Handler in the UI thread and then, from your second thread, send a runnable object that calls performClick() to the Handler.
package com.example.SpinnerDemo;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.os.Handler;
public class SpinnerDemo extends Activity {
private Handler h;
private Spinner s;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
h = new Handler();
s = (Spinner) findViewById(R.id.spinner);
ArrayAdapter adapter = ArrayAdapter.createFromResource(this,
R.array.planets, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item);
s.setAdapter(adapter);
// Open the Spinner...
s.performClick();
// Spawn a thread that triggers the Spinner to open after 5 seconds...
new Thread(new Runnable() {
public void run() {
// DO NOT ATTEMPT TO DIRECTLY UPDATE THE UI HERE, IT WON'T WORK!
// YOU MUST POST THE WORK TO THE UI THREAD'S HANDLER
h.postDelayed(new Runnable() {
public void run() {
// Open the Spinner...
s.performClick();
}
}, 5000);
}
}).start();
}
}
The resources used by this example can be found here.
To show the Spinner items you just need to call it's performClick() method.
Spinner spDeviceType = (Spinner) findViewById(R.id.spDeviceType);
spDeviceType.performClick();
You don't need to use 2 runnables as shown in the previous example.
This will be enough :
h.postDelayed(new Runnable() {
public void run() {
s.performClick();
}
}, 5000);
Simply use this
yourspinner.performClick();
#Override
protected void onResume() {
super.onResume();
_spinner_operations.performClick();
}
you need the call in onResume, in onCreate this not work.
You can call performClick() after the UI thread is done with its current operation(s). If you don't use post {}, you may not see the Spinner open.
findViewById<Spinner>(R.id.spinner).post {
performClick()
}

Categories

Resources