繁体   English   中英

如何从Android Activity中提取API和数据库调用?

[英]How to extract API and DB calls from Android Activity?

我是Android世界的新手。 在开发了漂亮的Rest API之后,我认为Android开发将很容易,但是我仍然坚持基础知识。

在我的Android应用程序上,我创建了Login(登录),该API调用了API,并在提供有效凭据时返回令牌。 此令牌存储在共享首选项中,并且用户被重定向到主要活动:HomeActivity。

该活动有很多工作要做:

  • 它具有BottomNavigationBar,因此当用户单击它的按钮时,将加载新的片段。

  • 调用API端点以获取资源并根据片段进行显示。

  • 将API响应存储在数据库中,以避免服务器过载。

当然,对于Android开发人员而言,这将非常容易,但是对我来说是这样的:

import android.arch.persistence.room.Room;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.ibosca.thub.database.AppDatabase;
import com.ibosca.thub.helpers.BottomNavigationViewHelper;
import com.ibosca.thub.models.Channel;
import com.ibosca.thub.models.Content;
import com.ibosca.thub.models.ContentList;
import com.ibosca.thub.models.Town;
import com.ibosca.thub.models.User;
import com.ibosca.thub.parser.ContentParser;
import com.ibosca.thub.volley.MySingleton;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HomeActivity extends AppCompatActivity {

private String userToken;
public TextView contentList;
private ContentParser contentParser = new ContentParser();
public static AppDatabase db;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "townhub").build();

    contentList = (TextView) findViewById(R.id.contentList);
    loadContents();

    SharedPreferences sharedPref = getSharedPreferences(MainActivity.PACKAGE_NAME, Context.MODE_PRIVATE);
    userToken = sharedPref.getString("token", null);

    BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
    BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

    View contentsButton = bottomNavigationView.findViewById(R.id.action_contents);
    contentsButton.performClick();

    bottomNavigationView.setOnNavigationItemSelectedListener(
            new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem item) {

                    Toast toast = Toast.makeText(getApplicationContext(), "UNDF", Toast.LENGTH_LONG);

                    switch (item.getItemId()) {
                        case R.id.action_towns:
                            toast = Toast.makeText(getApplicationContext(), "Towns", Toast.LENGTH_LONG);
                            break;

                        case R.id.action_channels:
                            toast = Toast.makeText(getApplicationContext(), "Channels", Toast.LENGTH_LONG);
                            break;

                        case R.id.action_contents:
                            loadContents();
                            break;

                        case R.id.action_question:
                            toast = Toast.makeText(getApplicationContext(), "Questions", Toast.LENGTH_LONG);
                            break;

                        case R.id.action_user:
                            toast = Toast.makeText(getApplicationContext(), "Settings", Toast.LENGTH_LONG);
                            break;

                    }

                    toast.show();
                    return true;
                }


            });

}

public void ExecuteInsert(ContentList...lists){
    new InsertContents().execute(lists);
}

protected void loadContents() {

    String url = MySingleton.BASE_URL + "/contents";


    JsonObjectRequest jsObjRequest = new JsonObjectRequest
            (Request.Method.GET, url, null, new Response.Listener<JSONObject>() {

                @Override
                public void onResponse(JSONObject response) {
                    try {
                        ContentList list = contentParser.fromContents(response);
                        ContentList[] lists = new ContentList[1];
                        lists[0] = list;
                        ExecuteInsert(lists);

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
            }, new Response.ErrorListener() {

                @Override
                public void onErrorResponse(VolleyError error) {
                    Toast.makeText(getApplicationContext(), "Failed to connect", Toast.LENGTH_LONG).show();
                }
            }) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> headers = new HashMap<>();

            headers.put("Authorization", "Bearer " + userToken);
            return headers;
        }
    };

    MySingleton.getInstance(this).addToRequestQueue(jsObjRequest);

}


public static class InsertContents extends AsyncTask<ContentList, Void, Void> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        //Perform pre-adding operation here.
    }

    @Override
    protected Void doInBackground(ContentList...lists) {
        ContentList list = lists[0];

        //Insert towns, channels
        db.townDao().insertArrayList(list.getTowns());
        db.channelDao().insertArrayList(list.getChannels());
        db.userDao().insertArrayList(list.getUsers());
        db.contentDao().insertArrayList(list.getContents());

        //Select data from DB
        List<Town> towns = db.townDao().getAll();
        List<Channel> channels = db.channelDao().getAll();
        List<User> users = db.userDao().getAll();
        List<Content> contents = db.contentDao().getAll();

        for (int i = 0; i < contents.size(); i++) {
            Content content = contents.get(i);
            Town contentTown = db.townDao().findById(content.getTownId());
            Log.i("Poble: ", contentTown.getName());
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);

        //To after addition operation here.
    }
}
}

为了简要介绍一下,在方法loadContents()我正在进行API调用; 和类InsertContents这是我在本地数据库中玩的地方。

最后,问题是:

1)如您所见,我正在使用Volley进行API调用。 是否有最佳实践将任何“ api端点”放在单独的类上,并在Activity中使用该类? 如何在Android开发中分离此代码?

2)与数据库管理相同。 如何将代码放在单独的类上,然后从Activity调用它? 目前已经完成,但是...我无法从AsyncTask更新TextView(更新TextView只是一个简单的尝试,我的最终目标是使用ListView或ReciclerView。

欢迎提出任何改进建议。

您可以尝试使用存储库模式。

这个想法或多或少如下,假设您有一个Car域类,并且您的数据库或api交互执行典型的CRUD操作,例如插入一辆汽车,通过其车牌号检索一张或全部卡的列表。

您可以创建一个类似的界面

public interface CarRepository {
     void insertCar(@NonNull Car car);

     List<Car> getAllCars();

     Car getCarByPlate(@NonNull String plateNumber);
}

然后,您可以根据使用哪个源存储数据来创建所述接口的具体实现。

例如,如果使用排球,则可以创建一个RestCarRepository来扩展CarRepository并使用Volley从rest api获取/存储数据。 或使用SQLite的DBCarRepository (或任何其他数据库引擎)。

最后,您可以在活动中声明存储库,从而抽象出提取数据的逻辑。

免责声明:关于存储库模式的文章很多(如答案开头的文章所述),当添加更多模式作为DI或MVP时,此答案可能会变得更加复杂,因此您可以掌握这个想法。

两种情况的简短答案:最好将视图(活动/片段)与模型或数据分开。 您将活动中的所有内容混合在一起,在这种小情况下可以,但是如果您的应用程序扩展,则很难阅读和理解活动并导致活动/片段生命周期出现问题。

为了进行更简洁的代码,有很多不同的方法可以将android中的关注点分开。

我建议您在这个回购中谈论android应用中的干净架构https://github.com/android10/Android-CleanArchitecture

Google还拥有一个相对较新的库来实现多种模式

https://developer.android.com/topic/libraries/architecture/adding-components.html

在这里,您可以获得有关数据库,页面调度,视图模型等的帮助。

编辑:详细回答:1)您可以遵循Model View Presenter(MVP)模式,将活动/片段视为仅一个View(仅负责一项职责的组件,呈现组件),并创建一个类(Presenter)了解模型/数据(您的api调用),并充当View和Model之间的桥梁。 视图将在Presenter中委派对模型的调用(例如,如果按下某些按钮),并且Presenter将数据返回给View,并且View仅具有绘制屏幕的方式。

2)您可以遵循调用Presenter的相同方法来检索信息并在RecyclerView中绘制数据。 您可以使用ThreadPoolExecutor来将数据与活动分离。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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