简体   繁体   中英

At what part of the lifecycle should you initialize objects in a fragment used by a service?

I'm working on an Android app so I can learn mobile dev and I'm stuck with this problem.

Basically in my SampleFragment class I have an adapter called mAdapter and when my TestService gets my data objects and updates my dataObjects arrayList and notifies the adapter that the data has changed the adapter isn't initialized and is null at the time. Is it a thread issue or is it associated with the fragment lifecycle?

SampleFragment.java

import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class SampleFragment extends Fragment {

    private static final int SEND_DELAY = 1500;
    private String userName, sEventId;
    private EditText etMessage;
    private ImageButton btSend;
    private Context applicationContext;
    private View view;
    private Handler handler = new Handler();
    private ArrayList<Message> dataObjects = new ArrayList<>();
    private MessageListAdapter mAdapter;
    private Runnable initMessageAdapter = new Runnable() {
        @Override
        public void run() {
            initMessageAdapter();
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String eventName = CurrentActiveEvent.getInstance().getEventName();
        Activity activity = getActivity();
        activity.setTitle(eventName);
        mAdapter = new MessageListAdapter(context, userName, dataObjects);
        CurrentActiveUser currentUser = CurrentActiveUser.getInstance();
        userName = currentUser.getUsername();
        Intent intent = new Intent(activity, TestService.class);
        activity.startService(intent);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_messaging, container, false);
        applicationContext = getActivity();
        sEventId = CurrentActiveEvent.getInstance().getEventID();
        btSend = (ImageButton) view.findViewById(R.id.btSend);
        handler.post(initMessageAdapter);
        btSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        saveMessage(body);
                    }
                });
            }
        });
        return view;
    }

    // Setup message field and posting
    private void initMessageAdapter() {
        etMessage = (EditText) view.findViewById(R.id.etMessage);
        ListView lvChat = (ListView) view.findViewById(R.id.lvChat);
        lvChat.setAdapter(mAdapter);
    }

    public void updatedataObjects(List<objs> newdataObjects){
        this.dataObjects.clear();
        this.dataObjects.addAll(newdataObjects);
        mAdapter.notifyDataSetChanged();
    }
}

TestService.java

import android.app.IntentService;
import android.content.Intent;

import java.util.Collections;
import java.util.List;

public class TestService extends IntentService {
    private static final int MAX_RESULTS = 50;
    private static final String CLASS_NAME = TestService.class.getSimpleName();
    private final String sEventId = CurrentActiveEvent.getInstance().getEventID();

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     */
    public TestService() {
        super(CLASS_NAME);
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void onHandleIntent(Intent intent) {
        if (NetworkState.isConnected(getApplicationContext())) {
            Query query = new Query(Data.class);
            query.whereEqualTo(Events.ID, sEventId);
            query.orderByDESC(Data.CREATED_AT);
            query.setLimit(MAX_RESULTS);
            List objs = queryDB(query, Data.class.getSimpleName());
            if (objs != null) {
                Collections.reverse(objs);
                new SampleFragment().updateMessages(objs);
            }
        }
    }
}

Your problem comes from this line:

new SampleFragment().updateMessages(objs);

You are creating a new instance of your fragment inside your service. Since you are not attaching the fragment anywhere, it's lifecycle is not started and the onCreate() method is never called, which results in the NullPointerException .

IntentService s are great for executing tasks on a background thread, but they are components, that are meant to be separated from the UI - related components, like Activities and Fragments. You should never have direct communication between an IntentService and a Fragment or Activity . If you need to return a result from your IntentService , you should consider using the LocalBroadcastManager . It will fire an intent, containing the result, and you can register receivers to intercept it.

There are also other options, like Bound Services - they are created to provide an interface for their clients, and you can use this to return your result. But bear in mind, that, unlike IntentService they don't work in a background thread by default.

Since you are trying to work with a database, I recommend you take a look and the ContentProvider and ContentResolver classes. They are the recommended way of working with DBs in Android and come with loads of neat stuff.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM