I try to use Loaders instead AsyncTask.I can not figure out how to correctly organize the conservation status when the screen is rotated. I receive information from Json and trying create list.
public class FragmentWeatherTestApplication extends Fragment
implements LoaderManager.LoaderCallbacks<List<WeatherItem>> {
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(0,null,this).forceLoad();
}
...
#Override
public Loader<List<WeatherItem>> onCreateLoader(int id, Bundle args) {
Log.i(TAG, "onCreateLoader");
return new FetchWeatherLoader(getActivity());
}
#Override
public void onLoadFinished(Loader<List<WeatherItem>> loader, List<WeatherItem> data) {
Log.i(TAG, "onLoadFinished");
mItems = data;
setupAdapter();
}
#Override
public void onLoaderReset(Loader<List<WeatherItem>> loader) {
Log.i(TAG, "onLoaderReset");
}
....
private static class FetchWeatherLoader extends AsyncTaskLoader<List<WeatherItem>>{
public FetchWeatherLoader(Context context) {
super(context);
}
#Override
public List<WeatherItem> loadInBackground() {
return new OpenWeatherFetch().fetchItems();
}
}
Related
I am migrating from SQL to ORM Room. I followed a tutorial, it usually worked to insert data, but when I delete an item it does not disappear. I have to open and close the App to show it is gone.
The tutorial I followed is this: https://medium.com/#anujguptawork/note-making-application-using-sqlite-vs-room-part-2-using-room-becf92672e29
public class MainActivity extends AppCompatActivity implements Contrato.MainViewInterface {
#BindView(R.id.recyclerHome)
RecyclerView recyclerView;
private HomeAdapter adapter;
private List<Clientes> clientesList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initViews();
loadNotes();
}
private void initViews() {
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
}
private void loadNotes(){
ClienteRepository.getInstance(this).getNotes(this);
}
#OnClick(R.id.fabAdicionar)
public void addNote(){
Intent i = new Intent(MainActivity.this, AdicionarActivity.class);
startActivity(i);
}
#OnClick(R.id.buttonDeletar)
public void buttonDeletar(){
ClienteRepository.getInstance(this).deletarNotes();
}
#Override
public void onNotesLoaded(List<Clientes> clientesList) {
clientesList = clientesList;
if(clientesList.size() == 0){
onDataNotAvailable();
}else {
adapter = new HomeAdapter(this, clientesList);
recyclerView.setAdapter(adapter);
}
}
#Override
public void onDataNotAvailable() {
Toast.makeText(this,"Adicione uma nota",Toast.LENGTH_SHORT).show();
}
}
public class ClienteRepository {
private Context context;
private static ClienteRepository _instance;
private ClienteRoomDatabase db;
public static ClienteRepository getInstance(Context context) {
if (_instance == null) {
_instance = new ClienteRepository(context);
}
return _instance;
}
public ClienteRepository(Context context) {
this.context = context;
db = ClienteRoomDatabase.getClienteDatabase(context);
}
public void getNotes(final Contrato.MainViewInterface mainViewInterface) {
db.clienteDAO().getAllClientes().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<List<Clientes>>() {
#Override
public void accept(List<Clientes> notes) throws Exception {
mainViewInterface.onNotesLoaded(notes);
}
});
}
public void addNotes(final Contrato.AddNoteViewInterface addNoteViewInterface, final String nome) {
Completable.fromAction(new Action() {
#Override
public void run() throws Exception {
Clientes clientes = new Clientes(nome);
db.clienteDAO().insert(clientes);
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io()).subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onComplete() {
addNoteViewInterface.onNoteAdded();
}
#Override
public void onError(Throwable e) {
addNoteViewInterface.onDataNotAvailable();
}
});
}
public void deletarNotes() {
Completable.fromAction(new Action() {
#Override
public void run() throws Exception {
db.clienteDAO().deleteAll();
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io()).subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onComplete() {
}
#Override
public void onError(Throwable e) {
}
});
}
}
#Dao
public interface ClienteDAO {
#Insert
void insert(Clientes clientes);
#Query("DELETE FROM table_clientes")
void deleteAll();
#Query("SELECT * FROM table_clientes ORDER BY name ASC")
Maybe<List<Clientes>> getAllClientes();
}
Remove item from your dataset of your adapter then call adapter.notifyItemRemoved(position)
There will be a lot of code. I had to leave it for you to understand logic of an application.
Here is the MainActivity. Called on starting.
public class MainActivity extends AppCompatActivity {
private GameView gameView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//some unnecessary code
setContentView(R.layout.activity_main);
}
public void startSurvival(View view) {
gameView = new GameView(this, this, "survival");
setContentView(gameView);
}
public void chooseData(View view){
setContentView(new DView(this, this));
}
public void backToMenu(){
setContentView(R.layout.activity_main);
gameView = null;
}
#Override
protected void onResume() {
super.onResume();
try {
gameView.update();
} catch (NullPointerException e) {}
}
}
This Activity is a List of options. You choose one and then GameView sets as content View with appropriate parameters.
Here is no questions so I cut almost all the code.
public class DView extends ListView {
DView(final Context context, final MainActivity mainActivity){
super(context);
this.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String[] columns = {"data"};
String having = "id = " + ids[position];
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query("levels", columns, null, null, ID, having, null);
if (cursor.moveToFirst()){
int dataInd = cursor.getColumnIndex(DATA);
mainActivity.setContentView(new GameView(context, mainActivity, cursor.getString(dataInd)));
}//everything here works fine. This just shows that setContentView can be done multiple times
//without bugs
cursor.close();
dbHelper.close();
}
});
}
}
And here comes the problem. When win() method is called display turns black. Application does not crash.
public class GameView extends SurfaceView{
public MainActivity mainActivity;
GameThread gameThread;
public Player player = null;
public Canvas canvas;
public ExtraData data;
public GameView (Context context, MainActivity mainActivity, String data){
super(context);
this.mainActivity = mainActivity;
if (data.equals("survival")) {
this.data = new ExtraData("RandomSpawn47",null, this);
} else {
this.data = new ExtraData("UsingData", data, this);
}
update();
}
void update(){
gameThread = new GameThread(this);
getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
gameThread.running(true);
if (gameThread.getState() == Thread.State.NEW)
gameThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
gameThread.running(false);
}
});
if (player == null)
player = new Player(this);
}
public class GameThread extends Thread{
private GameView gameView;
public GameThread(GameView gameView) {
this.gameView = gameView;
}
public void running(boolean run){
running = run;
}
#Override
public void run() {
while (running){
canvas = null;
try{
canvas = gameView.getHolder().lockCanvas(null);
synchronized (gameView.getHolder()){
draw(canvas);
this.wait(45);
}
} catch(Exception e) {}
finally {
if((canvas != null)&&(running)){
gameView.getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawColor(Color.BLUE);
data.onDraw();
}
public void win(){
mainActivity.backToMenu();//not switching the menu
}
}
Other classes like ExtraData and Player are not important.
GameThread and SurfaceView destroyes (I checked them with Logs in onDestroy() and in the end of run() method).
You are calling method of Activity from another class. Instead of mainActivity.backToMenu(), create one interface, implement it in MainActivity and pass the reference in GameView to initialize the interface. And where you are calling win method, call interface method instead of calling the public method of MainActivity.
Create one interface like:
public interface UpdateActivity{
void updateActivity();
}
In MainActivity
public class MainActivity extends AppCompatActivity implements UpdateActivity
then override the method of interface
void updateActivity(){
setContentView(R.layout.activity_main);
gameView = null;
}
Pass the reference in GameView instead of passing the MainActivity reference.
public GameView (Context context, UpdateActivity updateActivity , String data) {
super(context);
this.updateActivity = updateActivity ;
if (data.equals("survival")) {
this.data = new ExtraData("RandomSpawn47",null, this);
} else {
this.data = new ExtraData("UsingData", data, this);
}
update();
}
Now call the method where you want to call:
updateActivity.updateActivity();
I cannot call method from another activity in OnNotificationPosted. I also tried to make instance of activity but failed. I searched alot but no success. please help
NotificationListener
public class NotificationListener extends NotificationListenerService {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
otherActivity oth = new otherActivity();
oth.loc();
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn) {
Log.i("Msg", "Notification Removed");
}
}
otherActivity
public class OtherActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
}
public void loc() {
//code body
}
}
public class OtherActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
}
public static void loc(){
//code body
}
}
how to using : otherActivity.loc();
public class NotificationListener extends NotificationListenerService {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
otherActivity.loc();
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn) {
Log.i("Msg","Notification Removed");
}
I use loader to do task in back ground in method loadInBackground i added for loop to print log in logcat 50 time , so when i click the button start print log in logcat
but when i click the button i don't have any action and i don't have ant error , what is problem ?
mainActicity
public class MainActivity extends AppCompatActivity implements android.app.LoaderManager.LoaderCallbacks<String> {
TextView textView;
android.app.LoaderManager loaderManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loaderManager=getLoaderManager();
textView=findViewById(R.id.tv_result);
if (loaderManager.getLoader(0) ==null){
loaderManager.initLoader(0,null,this);
}
}
public void StartMysynstack (View view){
loaderManager.initLoader(0,null,this);
}
#Override
public android.content.Loader<String> onCreateLoader(int i, Bundle bundle) {
return new Myloader(this);
}
#Override
public void onLoadFinished(android.content.Loader<String> loader, String s) {
textView.setText(s);
}
#Override
public void onLoaderReset(android.content.Loader<String> loader) {
}
}
my loader
public class Myloader extends AsyncTaskLoader<String> {
int i;
public Myloader(Context context) {
super(context);
}
#Override
public String loadInBackground() {
for( i=0;i<=100;i++){
try {
Thread.sleep(50);
Log.d("waad","loadInBackground"+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Task result";
}
}
you can try calling it manually.
getLoaderManager().initLoader(0, null, this).forceLoad();
so according to your code you can make following changes.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loaderManager=getLoaderManager();
textView=findViewById(R.id.tv_result);
if (loaderManager.getLoader(0) ==null){
loaderManager.initLoader(0,null,this).forceLoad();;
}
}
I have an Android activity with a viewpager fragment. In the onCreate method of the activity, I bind a service to it which constantly runs in the background.
In the fragment, on a certain condition I need to call a function in the service which deals with the condition. What is the correct way to access the service, and call it's functions?
MainActivity.java
public class MainActivity extends AppCompatActivity {
private String TAG = "MainActivity";
DbHelper dbHelper;
SessionManager sessionManager;
SessionCache sessionCache;
Map<String, ?> userDetails;
protected SocketListener socketService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sessionManager = new SessionManager(getApplicationContext());
// Connect to background socketlistener service
Intent serviceIntent = new Intent(MainActivity.this, SocketListener.class);
startService(serviceIntent);
.
.
.
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setText("").setIcon(getResources().getDrawable(R.drawable.profileicon)));
tabLayout.addTab(tabLayout.newTab().setText("").setIcon(getResources().getDrawable(R.drawable.homeicon)));
tabLayout.addTab(tabLayout.newTab().setText("").setIcon(getResources().getDrawable(R.drawable.chaticon)));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
final NonSwipeableViewPager viewPager = (NonSwipeableViewPager) findViewById(R.id.view_pager);
final CustomPagerAdapter pagerAdapter = new CustomPagerAdapter
(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(pagerAdapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
viewPager.setCurrentItem(1);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
socketService = ((SocketListener.LocalBinder) iBinder).getService();
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
socketService = null;
}
};
}
This is my service. I connect to a server, and constantly listen for updates.
SocketListener.java
package com.example.gopa2000.mobapps;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import java.net.URISyntaxException;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
public class SocketListener extends Service {
private static String TAG = "SocketListener";
private Socket socket;
public SocketListener() { }
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return localBinder;
}
private final IBinder localBinder = new LocalBinder();
public class LocalBinder extends Binder {
public SocketListener getService(){
Log.i(TAG, "getService: Sitting in local binder.");
return SocketListener.this;
}
public void sendMessage(String message){
socket.emit("match", message);
}
}
#Override
public void onCreate() {
super.onCreate();
}
public void isBoundable(){
Log.i(TAG, "Bind like a baller.");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Runnable connect = new ConnectSocket();
new Thread(connect).start();
return START_STICKY;
}
class ConnectSocket implements Runnable {
#Override
public void run() {
try {
socket = IO.socket(RESTClient.getURL());
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i(TAG, "call: Connected to backend!");
}
});
socket.connect();
} catch (URISyntaxException e){
Log.e(TAG, "run: ", e);
}
}
}
public Socket getSocket(){
return this.socket;
}
}
And this is the fragment where I would need to call the sendMessage(string).
public class MainViewFragment extends Fragment {
private final String TAG = "MVFragment";
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
private SessionManager sessionManager;
private ArrayList<CustomCard> cards;
private CardAdapter cardAdapter;
private Button btn;
private SwipeFlingAdapterView flingContainer;
private Map<String, ?> userDetails;
// hax
private static String userEmail;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.from(getContext()).inflate(R.layout.fragment_main_view, container, false);
.
.
flingContainer.setAdapter(adapter);
flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener(){
.
.
#Override
public void onRightCardExit(Object o) {
.
.
if(match){
// need to call sendMessage from the service here. <------------------------
sessionCache.addToMatchTable(Liker, Likee);
}
}
#Override
public void onAdapterAboutToEmpty(int i) {
}
#Override
public void onScroll(float v) {
}
});
flingContainer.setOnItemClickListener(new SwipeFlingAdapterView.OnItemClickListener(){
#Override
public void onItemClicked(int itemPosition, Object dataObject){
Toast.makeText(getActivity(), "Clicked!", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(getActivity().getApplicationContext(), FullScreenCardLayout.class);
startActivity(intent);
}
});
return view;
}
First the method sendMessage(message) should be inside the service not the LocalBinder class
public class SocketListener extends Service {
public void sendMessage(String message){
socket.emit("match", message);
}
}
Second to access activity method from fragment you should create interface inside your fragment
interface MessageSender {
void sendMessage(String message);
}
then implement it in your activity
public class MainActivity extends AppCompatActivity implements MessageSender {
#Override
public void sendMessage(String message) {
// call the service here
socketService.sendMessage(message);
}
}
inside your fragment, implement onAttach() and initialize the interface instance
public class MainViewFragment extends Fragment {
private MessageSender mMessageSenderCallback;
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mMessageSenderCallback = (MessageSender) context;
} catch (ClassCastException e) {
// Error, class doesn't implement the interface
}
}
#Override
public void onDetach() {
super.onDetach();
// Remove activity reference
mMessageSenderCallback = null;
}
}
To send a message, call mMessageSenderCallback.sendMessage(message) with your message inside the fragment.