This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
In my application, I want to run code every 120second and to achieve this I am using Thread.
Following is the code snippet that I am using, but it is giving me Force close error.
Show me error for this line :
getActivity().runOnUiThread(new Runnable() {}
My Codes :
public class MainReminderFragment extends Fragment {
#BindView(R.id.mainExplore_noExploreTxt)
TextView mainExplore_noExploreTxt;
#BindView(R.id.newsPageLoadLay)
RelativeLayout newsPageLoadLay;
#BindView(R.id.toolbarTitleTxt)
TextView toolbarTitleTxt;
private Context context;
public List<Datum> model = new ArrayList<>();
public ReminderAdapter reminderAdapter;
private SharedPrefrencesHandler prefrencesHandler;
private String token = "";
private LinearLayoutManager layoutManager;
private MainActivity mainActivity;
private InterfaceApi api;
private boolean isRunning = false;
public ProgressBar mainExplore_progressBar;
public RecyclerView mainExplore_recyclerView;
public MainReminderFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_main_reminder, container, false);
//Initialize
ButterKnife.bind(this, view);
context = getActivity();
prefrencesHandler = new SharedPrefrencesHandler(context);
reminderAdapter = new ReminderAdapter(context, model);
layoutManager = new LinearLayoutManager(context);
mainExplore_progressBar = view.findViewById(R.id.mainExplore_progressBar);
mainExplore_recyclerView = view.findViewById(R.id.mainExplore_recyclerView);
isRunning = true;
mainActivity = (MainActivity) getActivity();
api = ApiClient.getClient().create(InterfaceApi.class);
//Toolbar name
toolbarTitleTxt.setText(context.getResources().getString(R.string.reminder));
//RecyclerView
mainExplore_recyclerView.setLayoutManager(layoutManager);
mainExplore_recyclerView.setHasFixedSize(true);
//Get token
token = prefrencesHandler.getFromShared(SharedPrefrencesKeys.TOKEN.name());
//Get data
getData();
if (getActivity() != null) {
Thread thread = new Thread() {
#Override
public void run() {
float i;
try {
for (i = 0; i <= 100; i++) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
getData();
}
});
sleep(120000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
return view;
}
//Get data
private void getData() {
try {
Call<SerialReminderListResponse> call = api.getListSerialReminder(token, "2", sendData(1));
mainExplore_progressBar.setVisibility(View.VISIBLE);
call.enqueue(new Callback<SerialReminderListResponse>() {
#Override
public void onResponse(Call<SerialReminderListResponse> call, Response<SerialReminderListResponse> response) {
if (response.body().getData() != null) {
if (response.body().getData().size() > 0) {
model.clear();
model.addAll(response.body().getData());
reminderAdapter.notifyDataSetChanged();
mainExplore_recyclerView.setAdapter(reminderAdapter);
//Gone no explore
mainExplore_noExploreTxt.setVisibility(View.GONE);
} else {
mainExplore_noExploreTxt.setVisibility(View.VISIBLE);
mainExplore_recyclerView.setVisibility(View.GONE);
}
}
mainExplore_progressBar.setVisibility(View.GONE);
}
#Override
public void onFailure(Call<SerialReminderListResponse> call, Throwable t) {
mainExplore_progressBar.setVisibility(View.GONE);
}
});
} catch (Exception e) {
}
}
Force close error in logCat :
Process: in.nouri.sevenwatchlist, PID: 7104
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v4.app.FragmentActivity.runOnUiThread(java.lang.Runnable)' on a null object reference
at com.app.test.Fragments.MainPageFrags.MainReminderFragment$1.run(MainReminderFragment.java:136)
Your below code
getActivity().runOnUiThread(new Runnable() {
public void run() {
getData();
}
});
sleep(120000);
Replce With:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
getData();
}
}, 120000);
Try this one.
TextView tv= new TextView(this);
tv.postDelayed(sendData, 1000);
Handler handler = new Handler();
private Runnable sendData=new Runnable(){
public void run(){
try {
//prepare and send the data here..
handler.removeCallbacks(sendData);
handler.postDelayed(sendData, 12000);
}
catch (Exception e) {
e.printStackTrace();
}
}
};
I recommend using ScheduledExecutorService as it is based on nano time, hence more accurate. Example:
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( 1 );
final Runnable r = new Runnable() {
public void run() {
// execution point
}
};
scheduler.scheduleAtFixedRate(r, 0, 1000, MILLISECONDS);
Related
I'm new to threading but I have an EditText view which whenever is getting out of focused it fills a RecyclerView with image logos using the user's input from EditText. But, whenever the user gets out of focuse and the method is called everything stops for a while(which mean im bad at threading). How can I improve this code so it can run smoothly?
My activity class:
public class addItem extends AppCompatActivity {
LoadingDialog loadingDialog;
RecyclerView imgList;
ArrayList<Bitmap> bitmapList = new ArrayList<>();
BitmapAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
/*
/ Code Unnecessary to the problem…
*/
et_title.setOnFocusChangeListener((v, hasFocus) -> {
if(!hasFocus){
getImageLogo(et_title.getText().toString());
}
});
}
#SuppressLint("NotifyDataSetChanged")
private void getImageLogo(String serviceName){
googleRequest googleList = new googleRequest(serviceName);
googleList.start();
try {
googleList.join();
} catch (InterruptedException e) {
Log.e("Interrupted Error","Thread Was Interrupted unexpectedly",e);
}
if(googleList.getImgRealList() != null) {
bitmapList.clear();
bitmapList.addAll(googleList.getImgRealList());
}else {
bitmapList.clear();
}
adapter.notifyDataSetChanged();
}
My googleRequest class:
public class googleRequest extends Thread {
private ArrayList<Bitmap> imgRealList;
private final String keyword;
public googleRequest(String keyword){
this.keyword = keyword;
}
public ArrayList<Bitmap> getImgRealList() {
return imgRealList;
}
#Override
public void run() {
String newKeyword = keyword.toLowerCase(Locale.ROOT);
newKeyword = newKeyword.replace(' ','+');
String url = "https://www.google.gr/search?bih=427&biw=1835&hl=el&gbv=1&tbm=isch&og=&ags=&q="+ newKeyword;
try {
Document document = Jsoup.connect(url).get();
imgRealList = new ArrayList<>();
Elements imgList = document.select("img");
for (int i=1;i<imgList.size();i++) {
if(i==8)
break;
String imgSrc = imgList.get(i).absUrl("src");
InputStream input = new java.net.URL(imgSrc).openStream();
Bitmap bitmap = BitmapFactory.decodeStream(input);
imgRealList.add(bitmap);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Here is an example of how it can be implemented using a callback as I have mentioned in comments. For this, we need to define a callback inerface I named it as following, you can change the names for your convenience.
RequestConsumer it is simple java interface.
/// Must be executed in the UI (main) thread.
#MainThread
public interface RequestConsumer {
void onRequestResult(List<Bitmap> bitmaps);
}
googleRequest thread class.
public class googleRequest extends Thread {
private ArrayList<Bitmap> imgRealList;
private final String keyword;
/*
We will use the request consumer callback in order to deliver the results
to the UI from background. Since we need to touch the UI by this callback
we ensure that it will execute within the UI thread's queue using the
uiHandler.
*/
private final RequestConsumer requestConsumer;
private final Handler uiHandler = new Handler(Looper.getMainLooper());
public googleRequest(#NonNull String keyword, #NonNull RequestConsumer requestConsumer){
this.keyword = keyword;
this.requestConsumer = requestConsumer;
}
#Override
public void run() {
String newKeyword = keyword.toLowerCase(Locale.ROOT);
newKeyword = newKeyword.replace(' ','+');
String url = "https://www.google.gr/search?bih=427&biw=1835&hl=el&gbv=1&tbm=isch&og=&ags=&q="+ newKeyword;
try {
Document document = Jsoup.connect(url).get();
imgRealList = new ArrayList<>();
Elements imgList = document.select("img");
for (int i=1;i<imgList.size();i++) {
if(i==8)
break;
String imgSrc = imgList.get(i).absUrl("src");
InputStream input = new java.net.URL(imgSrc).openStream();
Bitmap bitmap = BitmapFactory.decodeStream(input);
imgRealList.add(bitmap);
}
// I think according to your code; the data you've requested is ready
// to deliver from now on. But attention! we post it to execute it in the UI thread
uiHandler.post(() -> requestConsumer.onRequestResult(imgRealList));
} catch (IOException e) {
e.printStackTrace();
}
}
}
addItem activity class
public class addItem extends AppCompatActivity {
LoadingDialog loadingDialog;
RecyclerView imgList;
ArrayList<Bitmap> bitmapList = new ArrayList<>();
BitmapAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
/*
/ Code Unnecessary to the problem…
*/
et_title.setOnFocusChangeListener((v, hasFocus) -> {
if(!hasFocus){
getImageLogo(et_title.getText().toString());
}
});
}
#SuppressLint("NotifyDataSetChanged")
private void getImageLogo(String serviceName){
googleRequest googleList = new googleRequest(serviceName, images -> {
// Here we get the delivered results in this callback
if(images != null) {
bitmapList.clear();
bitmapList.addAll(images);
}else {
bitmapList.clear();
}
adapter.notifyDataSetChanged();
});
googleList.start();
}
}
Note I've written it in a text editor so the code needs some function test.
I'm trying to fetch some data from LastFm API, process it, and display it in a recycler view. My problem is that because of the way my code is structured I think that I initialize my recycler view before data is fetched so nothing is being shown until I reopen my fragment and I don't know how to fix that.
Here is my fragment code:
public class TopArtistsFragment extends Fragment {
private RecyclerView recyclerView;
private ArtistRecyclerViewAdapter adapter;
private TopArtistsViewModel mArtistsViewModel;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mArtistsViewModel = new ViewModelProvider(this).get(TopArtistsViewModel.class);
mArtistsViewModel.init();
mArtistsViewModel.getArtists().observe(this, new Observer<ArrayList<ArtistData>>() {
#Override
public void onChanged(ArrayList<ArtistData> artistData) {
adapter.notifyDataSetChanged();
}
});
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_top_artists, container, false);
recyclerView = view.findViewById(R.id.artistRecyclerView);
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initRecyclerView();
}
private void initRecyclerView() {
adapter = new ArtistRecyclerViewAdapter(mArtistsViewModel.getArtists().getValue(), getActivity());
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView.setAdapter(adapter);
}
}
This is my ViewModel:
public class TopArtistsViewModel extends ViewModel {
private MutableLiveData<ArrayList<ArtistData>> mArtists;
private ArtistDataRepository mRepo;
public void init() {
if(mArtists != null)
return;
mRepo = ArtistDataRepository.getInstance();
mArtists = mRepo.getArtists();
}
public LiveData<ArrayList<ArtistData>> getArtists() {
return mArtists;
}
}
And this is my repository where the work is being done:
public class ArtistDataRepository {
private static ArtistDataRepository instance;
private ArrayList<ArtistData> dataSet = new ArrayList<>();
public static ArtistDataRepository getInstance() {
if(instance == null)
instance = new ArtistDataRepository();
return instance;
}
public MutableLiveData<ArrayList<ArtistData>> getArtists() {
setArtists();
MutableLiveData<ArrayList<ArtistData>> data = new MutableLiveData<>();
data.setValue(dataSet);
return data;
}
private void setArtists () {
fetchData();
}
private void fetchData () {
final String requestUrl = "https://ws.audioscrobbler.com/2.0/?method=chart.gettopartists&api_key=2124b8e156db20ac7a5035fad9c01b8e&format=json";
final OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(requestUrl).build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e) {
Log.d("NETWORK FAILURE", "Artist fetch");
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
if(response.isSuccessful())
parseData(response.body().string());
else Log.d("OKHTTP", "Response not successful");
}
});
}
private void parseData (String queryResponse) {
try {
JSONArray artistResponse = new JSONObject(queryResponse).getJSONObject("artists").getJSONArray("artist");
for(int i = 0; i < artistResponse.length(); i++) {
JSONObject artist = artistResponse.getJSONObject(i);
dataSet.add(new ArtistData(artist.getString("mbid"), artist.getString("playcount"), artist.getString("listeners"),
artist.getString("name"), artist.getJSONArray("image").getJSONObject(0).getString("#text")));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
I'm just a beginner so right now I'm basically trying to merge code from different tutorials into one. That's why some things you see here probably don't make sense, so please do tell me what I can fix.
In order to tell the Recycleview that the data has come you need to get the Adapter and set its data then call adapter.notifyDataSetChanged();
mArtistsViewModel.getArtists().observe(this, new Observer<ArrayList<ArtistData>>() {
#Override
public void onChanged(ArrayList<ArtistData> artistData) {
--> adapter.setData(artistData); // Something like that
adapter.notifyDataSetChanged();
}
});
Got through this link
first try to learn how to fetch data using retrofit and you won't to parse data their is a library GSON and Moshi which will do all your work you just need to use POJO. Just go through this example
So to answer the question, part of the solution is, like someone suggested, to add adapter.setData() function to my adapter and call it in onChanged().
mArtistsViewModel.getArtists().observe(this, new Observer<ArrayList<ArtistData>>() {
#Override
public void onChanged(ArrayList<ArtistData> artistData) {
--> adapter.setData(artistData); // Something like that
adapter.notifyDataSetChanged();
}
});
The second part was adding data.postValue() in parseData function in my repo
private void parseData (String queryResponse) {
try {
JSONArray artistResponse = new JSONObject(queryResponse).getJSONObject("artists").getJSONArray("artist");
for(int i = 0; i < artistResponse.length(); i++) {
JSONObject artist = artistResponse.getJSONObject(i);
dataSet.add(new ArtistData(artist.getString("mbid"), artist.getString("playcount"), artist.getString("listeners"),
artist.getString("name"), artist.getJSONArray("image").getJSONObject(0).getString("#text")));
}
data.postValue(dataSet); //THIS WAS ADDED
} catch (JSONException e) {
e.printStackTrace();
}
}
This probably isn't the optimal solution for what I'm doing here, but it works as intended.
Trying to run MIDI on my Android app. I'm following the midisuite example to configure my app and it works fine with the exception of aftertouch. Whenever I try to trigger aftertouch, I run into a threading exception type
InteruptedException. How should I prevent this threading issue? My knowledge on multithreading isn't the best or else I would've figured this out already. All I can really tell right now is that the message is sending too fast and the thread hasn't woken up yet from its sleep call.
I followed the github repo with my code as follows:
MidiReceiver subclass:
#TargetApi(Build.VERSION_CODES.M)
public class MidiEngine extends MidiReceiver {
public AudioActivity activity;
private MidiEventScheduler eventScheduler;
private MidiFramer midiFramer;
private MidiReceiver midiReceiver = new MyReceiver();
private Thread mThread;
private boolean go;
private int mProgram;
public MidiEngine() {
this(new AudioActivity());
}
public MidiEngine(AudioActivity activity) {
this.activity = activity;
midiReceiver = new MyReceiver();
midiFramer = new MidiFramer(midiReceiver);
}
public AudioActivity getActivity() {
return this.activity;
}
/* This will be called when MIDI data arrives. */
#Override
public void onSend(byte[] data, int offset, int count, long timestamp)
throws IOException {
if (eventScheduler != null) {
if (!MidiConstants.isAllActiveSensing(data, offset, count)) {
eventScheduler.getReceiver().send(data, offset, count,
timestamp);
}
}
}
// Custom Listener to send to correct methods
private class MyReceiver extends MidiReceiver {
#Override
public void onSend(byte[] msg, int offset, int count, long timestamp) throws IOException {
byte command = (byte)(msg[0] & MidiConstants.STATUS_COMMAND_MASK);
int channel = (byte)(msg[0] & MidiConstants.STATUS_CHANNEL_MASK);
switch (command) {
case MidiConstants.STATUS_NOTE_ON:
activity.keyDown(i, msg[1], msg[2]);
break;
case MidiConstants.STATUS_NOTE_OFF:
activity.keyUp(channel, msg[1]);
break;
case MidiConstants.STATUS_POLYPHONIC_AFTERTOUCH:
activity.keyDown(channel, msg[1], msg[2]);
break;
case MidiConstants.STATUS_PITCH_BEND:
activity.pitchBendAction(channel, (msg[2] << 7) + msg[1]);
break;
case MidiConstants.STATUS_CONTROL_CHANGE:
activity.ccAction(channel, msg[1], msg[2]);
break;
case MidiConstants.STATUS_PROGRAM_CHANGE:
mProgram = msg[1];
break;
default:
break;
}
}
}
class MyRunnable implements Runnable {
#Override
public void run() {
do {
try {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
try {
processMidiEvents();
}
catch (Exception e) {
Log.e("Java", "SynthEngine background thread exception.", e);
}
}
});
Thread.sleep(100);
}
catch (InterruptedException e) {
Log.e("Java", "Threading exception", e);
}
}
while (go);
}
}
/**
* #throws IOException
*
*/
private void processMidiEvents() throws IOException {
long now = System.nanoTime();
MidiEventScheduler.MidiEvent event = (MidiEventScheduler.MidiEvent) eventScheduler.getNextEvent(now);
while (event != null) {
midiFramer.send(event.data, 0, event.count, event.getTimestamp());
eventScheduler.addEventToPool(event);
event = (MidiEventScheduler.MidiEvent) eventScheduler.getNextEvent(now);
}
}
public void start() {
stop();
go = true;
mThread = new Thread(new MyRunnable());
mThread.setPriority(6);
eventScheduler = new MidiEventScheduler();
mThread.start();
}
public void stop() {
go = false;
if (mThread != null) {
try {
mThread.interrupt();
mThread.join(500);
}
catch (Exception e) {
}
mThread = null;
eventScheduler = null;
}
}
}
Stack Trace Error (line 154 refers to the Thread.sleep part in my custom Runnable class):
Java: Threading exception
java.lang.InterruptedException
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:1031)
at java.lang.Thread.sleep(Thread.java:985)
at com.rfoo.midiapp.communication.MidiEngineInput$MyRunnable.run(MidiEngineInput.java:154)
at java.lang.Thread.run(Thread.java:818)
Thanks!
EDIT: Thread start
Midi Device Service subclass (thread will start whenever a device has connected or disconnected).
#TargetApi(Build.VERSION_CODES.M)
public class MidiSynthDeviceService extends MidiDeviceService {
private static final String TAG = "MidiSynthDeviceService";
private boolean midiStarted = false;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
AudioActivity.midiEngine.stop();
super.onDestroy();
}
#Override
// Declare the receivers associated with your input ports.
public MidiReceiver[] onGetInputPortReceivers() {
return new MidiReceiver[] { AudioActivity.midiEngine };
}
/**
* This will get called when clients connect or disconnect.
* You can use it to turn on your synth only when needed.
*/
#Override
public void onDeviceStatusChanged(MidiDeviceStatus status) {
if (status.isInputPortOpen(0) && !midiStarted) {
AudioActivity.midiEngine.start();
midiStarted = true;
} else if (!status.isInputPortOpen(0) && midiStarted){
AudioActivity.midiEngine.stop();
midiStarted = false;
}
}
}
Activity class:
public class AudioActivity extends AppCompatActivity {
private Thread thread;
public static MidiEngine midiEngine;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Layout inits
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Setup MIDI:
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) {
Toast.makeText(this, "MIDI not supported!", Toast.LENGTH_LONG).show();
}
else {
midiEngine = new MidiEngine(this);
setupMidi();
}
// Setup audio thread:
if (thread == null) {
thread = new Thread() {
public void run() {
setPriority(Thread.MAX_PRIORITY);
// Runs an Open SL audio thread (C++)
// This generates a waveform.
// AudioEngine is a wrapper class connecting C++ to Java
AudioEngine.runProcess();
}
}
}
}
public void setupMidi() {
if (activity == null) activity = (AudioActivity) getContext();
mMidiManager = (MidiManager) activity.getSystemService(AudioActivity.MIDI_SERVICE);
if (mMidiManager == null) {
Toast.makeText(activity, "MidiManager is null!", Toast.LENGTH_LONG).show();
return;
}
// Get Device Info
MidiDeviceInfo deviceInfo = MidiTools.findDevice(mMidiManager, "RFOO", "AudioApp");
// MIDI Input
portIndex = 0;
inputPortSelector = new MidiOutputPortConnectionSelector(mMidiManager, activity, R.id
.inputListView, deviceInfo, portIndex);
inputPortSelector.setConnectedListener(new MyPortsConnectedListener());
midi_ch_input = 0;
midi_ch_output = 0;
}
// Bunch of UI code here....
}
I have a fragment class that describes RecyclerView. It takes array for creating elements. The array is forming by parsing JSON. When I use good internet connection everything is OK, and I can see desirable list of items. But using low-speed connection my UI is empty.
I realize that there are some problems with threads, but I haven't enough knowledge to fix my problem.
Here is a code:
public class ListVideo extends Fragment {
private int loadLimit = 9;
private RecyclerView recyclerView;
private RecyclerAdapter adapter;
private LinearLayoutManager linearLayoutManager;
final OkHttpClient client = new OkHttpClient();
List<VideoData> videoList;
List<String> videoDataList;
JSONArray json_array_list_of_videos;
int counter = 0;
int offset;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.listvideofragment, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
videoList = new ArrayList<>();
videoDataList = new ArrayList<>();
recyclerView = (RecyclerView) view.findViewById(R.id.list);
loadData(offset);
createRecycleView();
recyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(
linearLayoutManager) {
#Override
public void onLoadMore(int offset) {
// do somthing...
loadMoreData(offset);
}
});
}
private void loadMoreData(int offset) {
loadLimit += 10;
loadData(offset);
adapter.notifyDataSetChanged();
}
private void loadData(final int offset) {
try {
Request request = new Request.Builder()
.url("http://video.motti.be/api/video.getVideoList?offset=" +
offset
+ "&limit=20")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException throwable) {
throwable.printStackTrace();
}
#Override
public void onResponse(Response response) throws IOException {
try {
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
String json_string_obj = response.body().string();
JSONObject url = new JSONObject(json_string_obj);
json_array_list_of_videos = url.getJSONArray("data");
System.out.println(json_array_list_of_videos.toString());
for (int y = 0; y <= 9; y++) {
if (json_array_list_of_videos.get(y).toString().equals("A9knX0GXrg")) {
videoDataList.add("6kS9Tt1e47g");
} else {
videoDataList.add(json_array_list_of_videos.get(y).toString());
System.out.println("++++++" + json_array_list_of_videos.get(y).toString());
}
}
for (int i = counter; i <= loadLimit; i++) {
if (videoDataList == null) {
return;
} else {
VideoData next_queue_id = new VideoData(videoDataList.get(i));
videoList.add(next_queue_id);
counter++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
}
public void createRecycleView() {
adapter = new RecyclerAdapter(videoList, getContext());
linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
}
}
I understand, that I get Response later then new adapter creates.For the lack of knowledge, as I sad, I have no idea how to make thread with onResponse method to wait.
Hope that you won't find this question as dull or stupid and will help me.
Thank you in advance!
You need to notify the adapter after you modify its list (videoList).
Currently the loadMoreData(int offset) method doesn't guaranty that because the loadData(offset); method can return before the list is modified (the request is processed asynchronously).
What you could do is this:
Remove the adapter.notifyDataSetChanged(); statement from the loadMoreData(int offset) method and add it to the onResponse(Response response) method.
Example:
#Override
public void onResponse(Response response) throws IOException {
try {
...
for (int i = counter; i <= loadLimit; i++) {
if (videoDataList == null) {
return;
} else {
VideoData next_queue_id = new VideoData(videoDataList.get(i));
videoList.add(next_queue_id);
counter++;
}
}
ListVideo.this.runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
This approach can create other problems because the videoList can be modified by multiple threads at the same time. You need to find a way to synchronize the access to this list or use a thread safe list.
I'm trying to make a simple app that lists all the found Ibeacons in a ListView and changes the RSSI values according to the distance the user is from the beacons itself.
The app works fine, but the problem I'm having is that if a beacon is out of reach it does not get removed from the list. Any ideas on how to remove the item when the beacon isn't in range anymore?
I have the following code:
MainActivity.java:
public class MainActivity extends Activity implements BeaconConsumer {
public ListView list;
public BeaconAdapter adapter;
public ArrayList<Beacon> arrayL = new ArrayList<>();
public LayoutInflater inflater;
public BeaconManager mBeaconManager;
public boolean beaconPresent;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = (ListView)findViewById(R.id.lijst);
mBeaconManager = BeaconManager.getInstanceForApplication(this.getApplicationContext());
mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
mBeaconManager.setForegroundBetweenScanPeriod(100);
mBeaconManager.bind(this);
adapter = new BeaconAdapter();
list.setAdapter(adapter);
inflater =(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void onBeaconServiceConnect() {
Region region = new Region("all-beacons-region", null, null, null);
try {
mBeaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
mBeaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(final Collection<Beacon> beacons, Region region) {
runOnUiThread(new Runnable() {
#Override
public void run() {
ArrayList<Beacon> allRangedBeacons = (ArrayList<Beacon>) beacons;
ArrayList<Beacon> newRangedBeacons = new ArrayList<>();
ArrayList<Beacon> cloneArraylistIBeacon = (ArrayList<Beacon>) arrayL.clone();
ArrayList<Beacon>nonRangedBeacons = new ArrayList<>();
int index = 0;
for (Beacon presentBeacons : cloneArraylistIBeacon) {
beaconPresent = false;
for (Beacon eachRangedBeacon : allRangedBeacons) {
if (presentBeacons.equals(eachRangedBeacon)) {
arrayL.remove(index);
arrayL.add(index, eachRangedBeacon);
beaconPresent = true;
}
if(beaconPresent = false) {
nonRangedBeacons.add(presentBeacons);
}
}
index++;
}
for (Beacon eachRangedBeacon : allRangedBeacons) {
beaconPresent = false;
for (Beacon presentBeacons : cloneArraylistIBeacon) {
if (eachRangedBeacon.equals(presentBeacons)) {
beaconPresent = true;
}
}
if (!beaconPresent) {
newRangedBeacons.add(eachRangedBeacon);
}
}
arrayL.remove(nonRangedBeacons);
arrayL.addAll(newRangedBeacons);
adapter.notifyDataSetChanged();
}
});
}
});
}
protected void onPause() {
super.onPause();
mBeaconManager.unbind(this);
}
private class BeaconAdapter extends BaseAdapter {
#Override
public int getCount() {
if (arrayL != null && arrayL.size() > 0) {
return arrayL.size();
} else {
return 0;
}
}
#Override
public Beacon getItem(int position) {
return arrayL.get(position);
}
#Override
public long getItemId(int arg0) {
return arg0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
holder = new ViewHolder(convertView = inflater.inflate(R.layout.tupple_monitoring, null));
try {
holder.uuid.setText("UUID: " + arrayL.get(position).getId2());
holder.rssi.setText("RSSI: " + arrayL.get(position).getRssi());
holder.txpow.setText("TXPOW: " + arrayL.get(position).getTxPower());
return convertView;
}catch(Exception e) {
e.printStackTrace();
}
return convertView;
}
}
private class ViewHolder {
private TextView uuid;
private TextView rssi;
private TextView txpow;
public ViewHolder(View view) {
uuid = (TextView)view.findViewById(R.id.BEACON_uuid);
rssi = (TextView)view.findViewById(R.id.BEACON_rssi);
txpow = (TextView)view.findViewById(R.id.BEACON_txpower);
view.setTag(this);
}
}
}
If you only want to display beacons in range, every time you receive a list of beacons simply change the adapter source list.
arrayL.clear();
arrayL.addAll(beacons);
adapter.notifyDataSetChanged();
To avoid jumping around if list items, maybe sort the beacons by their RSSI before displaying them.
Because the Android Beacon Library already tracks the list of visible beacons and updates it in the ranging callback, you can simply refresh the whole list in your BeaconAdapter each time. Like this:
#Override
public void didRangeBeaconsInRegion(final Collection<Beacon> beacons, Region region) {
runOnUiThread(new Runnable() {
#Override
public void run() {
arrayL = new ArrayList<Beacon>(beacons);
adapter.notifyDataSetChanged();
}
});
}