Rewriting deprecated code and improving offline mode. (#800)

Moving UI-related code to message queue of main thread.

Removing NetworkObserver in favor of NetworkStatusObserver

Some fixes.

Removing deprecated PreferenceManager.

Fixing crash.

Merge branch 'master' of https://codeberg.org/gitnex/GitNex into fix-performance-regression

 Conflicts:
	app/src/main/java/org/mian/gitnex/clients/RetrofitClient.java

Rewriting deprecated code.

Improving degraded performance due to unnecessary object allocation.

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/800
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-Authored-By: opyale <opyale@noreply.codeberg.org>
Co-Committed-By: opyale <opyale@noreply.codeberg.org>
This commit is contained in:
opyale 2021-01-14 17:33:50 +01:00 committed by M M Arif
parent 5d2bb02b2d
commit b75bf84d43
7 changed files with 138 additions and 123 deletions

View File

@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<application
android:allowBackup="true"

View File

@ -2,6 +2,7 @@ package org.mian.gitnex.activities;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
@ -17,7 +18,7 @@ import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.database.api.UserAccountsApi;
import org.mian.gitnex.database.models.UserAccount;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.NetworkObserver;
import org.mian.gitnex.helpers.NetworkStatusObserver;
import org.mian.gitnex.helpers.PathsHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
@ -63,7 +64,7 @@ public class LoginActivity extends BaseActivity {
super.onCreate(savedInstanceState);
NetworkObserver networkMonitor = new NetworkObserver(ctx);
NetworkStatusObserver networkStatusObserver = NetworkStatusObserver.get(ctx);
loginButton = findViewById(R.id.login_button);
instanceUrlET = findViewById(R.id.instance_url);
@ -79,7 +80,7 @@ public class LoginActivity extends BaseActivity {
ArrayAdapter<Protocol> adapterProtocols = new ArrayAdapter<>(LoginActivity.this, R.layout.list_spinner_items, Protocol.values());
protocolSpinner.setAdapter(adapterProtocols);
protocolSpinner.setSelection(0);
protocolSpinner.setOnItemClickListener((parent, view, position, id) -> {
selectedProtocol = String.valueOf(parent.getItemAtPosition(position));
@ -115,18 +116,24 @@ public class LoginActivity extends BaseActivity {
}
});
networkMonitor.onInternetStateListener(isAvailable -> {
Handler handler = new Handler(getMainLooper());
if(isAvailable) {
networkStatusObserver.registerNetworkStatusListener(hasNetworkConnection -> {
enableProcessButton();
}
else {
handler.post(() -> {
disableProcessButton();
loginButton.setText(getResources().getString(R.string.btnLogin));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
}
if(hasNetworkConnection) {
enableProcessButton();
}
else {
disableProcessButton();
loginButton.setText(getResources().getString(R.string.btnLogin));
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
}
});
});
loadDefaults();
@ -267,8 +274,10 @@ public class LoginActivity extends BaseActivity {
if(gitea_version.less(getString(R.string.versionLow))) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ctx).setTitle(getString(R.string.versionAlertDialogHeader))
.setMessage(getResources().getString(R.string.versionUnsupportedOld, version.getVersion())).setIcon(R.drawable.ic_warning)
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ctx)
.setTitle(getString(R.string.versionAlertDialogHeader))
.setMessage(getResources().getString(R.string.versionUnsupportedOld, version.getVersion()))
.setIcon(R.drawable.ic_warning)
.setCancelable(true);
alertDialogBuilder.setNegativeButton(getString(R.string.cancelButton), (dialog, which) -> {

View File

@ -36,8 +36,6 @@ public class RetrofitClient {
TinyDB tinyDB = TinyDB.getInstance(context);
final boolean connToInternet = AppUtil.hasNetworkConnection(context);
int cacheSize = FilesData.returnOnlyNumber(tinyDB.getString("cacheSizeStr")) * 1024 * 1024;
Cache cache = new Cache(new File(context.getCacheDir(), "responses"), cacheSize);
@ -59,7 +57,7 @@ public class RetrofitClient {
Request request = chain.request();
request = connToInternet ?
request = AppUtil.hasNetworkConnection(context) ?
request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build() :
request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 30).build();

View File

@ -5,13 +5,12 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.ColorInt;
import androidx.core.content.pm.PackageInfoCompat;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
@ -34,32 +33,14 @@ public class AppUtil {
public static boolean hasNetworkConnection(Context context) {
boolean haveConnectedWifi = false;
boolean haveConnectedMobile = false;
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
assert cm != null;
NetworkInfo[] netInfo = cm.getAllNetworkInfo();
for(NetworkInfo ni : netInfo) {
if(ni.getTypeName().equalsIgnoreCase("WIFI")) {
if(ni.isConnected()) {
haveConnectedWifi = true;
}
}
if(ni.getTypeName().equalsIgnoreCase("MOBILE")) {
if(ni.isConnected()) {
haveConnectedMobile = true;
}
}
}
return haveConnectedWifi || haveConnectedMobile;
return NetworkStatusObserver.get(context).hasNetworkConnection();
}
public static int getAppBuildNo(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
return (int) PackageInfoCompat.getLongVersionCode(packageInfo);
}
catch(PackageManager.NameNotFoundException e) {
throw new RuntimeException("Could not get package name: " + e);

View File

@ -1,82 +0,0 @@
package org.mian.gitnex.helpers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
/**
* Author M M Arif
*/
public class NetworkObserver implements LifecycleObserver {
private ConnectivityManager mConnectivityMgr;
private Context mContext;
private NetworkStateReceiver mNetworkStateReceiver;
public interface ConnectionStateListener {
void onAvailable(boolean isAvailable);
}
public NetworkObserver(Context context) {
mContext = context;
mConnectivityMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
((AppCompatActivity) mContext).getLifecycle().addObserver(this);
}
public void onInternetStateListener(ConnectionStateListener listener) {
mNetworkStateReceiver = new NetworkStateReceiver(listener);
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(mNetworkStateReceiver, intentFilter);
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
((AppCompatActivity) mContext).getLifecycle().removeObserver(this);
if (mNetworkStateReceiver != null) {
mContext.unregisterReceiver(mNetworkStateReceiver);
}
}
public class NetworkStateReceiver extends BroadcastReceiver {
ConnectionStateListener mListener;
public NetworkStateReceiver(ConnectionStateListener listener) {
mListener = listener;
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getExtras() != null) {
NetworkInfo activeNetworkInfo = mConnectivityMgr.getActiveNetworkInfo();
if (activeNetworkInfo != null && activeNetworkInfo.getState() == NetworkInfo.State.CONNECTED) {
mListener.onAvailable(true); // connected
} else if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE)) {
mListener.onAvailable(false); // disconnected
}
}
}
}
}

View File

@ -0,0 +1,109 @@
package org.mian.gitnex.helpers;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author opyale
*/
public class NetworkStatusObserver {
private static NetworkStatusObserver networkStatusObserver;
private final AtomicBoolean hasNetworkConnection = new AtomicBoolean(false);
private final List<NetworkStatusListener> networkStatusListeners = new ArrayList<>();
private final Object mutex = new Object();
private boolean hasInitialized = false;
private NetworkStatusObserver(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.build();
cm.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(@NonNull Network network) {
hasNetworkConnection.set(true);
networkStatusChanged();
checkInitialized();
}
@Override
public void onLost(@NonNull Network network) {
hasNetworkConnection.set(false);
networkStatusChanged();
checkInitialized();
}
private void checkInitialized() {
if(!hasInitialized) {
hasInitialized = true;
synchronized(mutex) {
mutex.notify();
}
}
}
});
synchronized(mutex) {
try {
// This is actually not the recommended way to do this, but there
// is no other option besides upgrading to API level 26
// in order to use the built-in timeout functionality of {@code requestNetwork()}
// which in turn gives us access to {@code onUnavailable()} .
mutex.wait(5);
} catch(InterruptedException ignored) {}
}
if(!hasInitialized) {
hasInitialized = true;
}
}
private void networkStatusChanged() {
boolean hasNetworkConnection = hasNetworkConnection();
for(NetworkStatusListener networkStatusListener : networkStatusListeners) {
networkStatusListener.onNetworkStatusChanged(hasNetworkConnection);
}
}
public boolean hasNetworkConnection() {
return hasNetworkConnection.get();
}
public void registerNetworkStatusListener(NetworkStatusListener networkStatusListener) {
networkStatusListeners.add(networkStatusListener);
networkStatusListener.onNetworkStatusChanged(hasNetworkConnection());
}
public void unregisterNetworkStatusListener(NetworkStatusListener networkStatusListener) {
networkStatusListeners.remove(networkStatusListener);
}
public interface NetworkStatusListener { void onNetworkStatusChanged(boolean hasNetworkConnection); }
public static NetworkStatusObserver get(Context context) {
if(networkStatusObserver == null) {
networkStatusObserver = new NetworkStatusObserver(context);
}
return networkStatusObserver;
}
}

View File

@ -6,7 +6,6 @@ import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
@ -25,7 +24,7 @@ public class TinyDB {
private String lastImagePath = "";
private TinyDB(Context appContext) {
preferences = PreferenceManager.getDefaultSharedPreferences(appContext);
preferences = appContext.getSharedPreferences(appContext.getPackageName() + "_preferences", Context.MODE_PRIVATE);
}
public static synchronized TinyDB getInstance(Context context) {